This tutorial walks you through the concept of Python functions. It helps you learn how to create user-defined functions and use them to write modular programs in Python.
Simple Steps to Create Functions in Python
In programming, a function is a label or name assigned to a piece of code. You can call that code any number of times by using the name. It is quite easy to define a function in Python using the “def” keyword. Before we get into the details of creating functions, first understand a little more about them.
What is a Function in Programming?
A function in Python is an independent and reusable block of code that you can call any number of times from any place in a program. It is an essential tool for programmers to split a big project into smaller modules. Here are some key points to consider.
1. They are the core building blocks of any programming language that a programmer must learn to use. Python provides several built-in methods for direct use and also allows you to define your custom functions.
2. A function in Python is a logical unit of code containing a sequence of statements indented under a name given using the “def” keyword.
3. Functions allow you to create a logical division of a big project into smaller modules. They make your code more manageable and extensible.
4. While programming, a function prevents you from adding duplicate code and promotes reusability.
Let’s now quickly see what else are we going to learn from this tutorial.
How to Create a Function – Syntax
The syntax of a Python function is as follows.
Single line function:
def single_line(): statement
Python function with docstring:
def fn(arg1, arg2,...): """docstring""" statement1 statement2
Nested Python function:
def fn(arg1, arg2,...): """docstring""" statement1 statement2 def fn_new(arg1, arg2,...): statement1 statement2 ... ...
Why is the Def Statement Used in Python?
Please read the below notes to understand the purpose of the “def” keyword in Python.
- The “def” keyword is a statement for defining a function in Python.
- You start a function with the def keyword and specify a name followed by a colon (:) sign.
- The “def” call creates the function object and assigns it to the name given.
- You can further re-assign the same function object to other names.
- Give a unique name to your function and follow the same rules as naming the identifiers.
- Add a meaningful docstring to explain what the function does. However, it is an optional step.
- Now, start the function body by adding valid Python statements each indented with four spaces.
- You can also add a statement to return a value at the end of a function. However, this step is optional.
- Just press enter and remove the indentation to end a function.
- Since def is a statement, you can use it anywhere a statement can appear – such as nested in an if clause or within another function.
Example :
if test: def test(): # First definition ... else: def test(): # Alternate definition ... ...
How to Call a Function in Python?
By using the def keyword, you learned to create the blueprint of a function that has a name, parameters to pass, and a body with valid Python statements.
The next step is to execute it. You can do so by calling it from the Python script, inside a function, or directly from the Python shell.
To call a function, you need to specify the function name with relevant parameters, and that’s it.
Follow the below example to learn how to call a function in Python.
Example of a Function Call
It’s a simple example where a function “typeOfNum()” has nested functions to decide if a number is either odd or even.
def typeOfNum(num): # Function header # Function body if num % 2 == 0: def message(): print("You entered an even number.") else: def message(): print("You entered an odd number.") message() # End of function typeOfNum(2) # call the function typeOfNum(3) # call the function again
Polymorphism in Python
In Python, function polymorphism is possible as we don’t specify the argument types while creating functions.
- The behavior of a function may vary depending on the arguments passed to it.
- The same function can accept arguments of different object types.
- If the objects find a matching interface, the function can process them.
Example :
def product(x, y) : return x * y print(product(4, 9)) # function returns 36 print(product('Python!', 2)) # function returns # Python!Python! print(product('Python 2 or 3?', '3')) # TypeError occurs
The above example clarifies that we can pass any two objects to the product() function which supports the ‘*’ operator.
The concept above we’ve explained is known as polymorphism. Some points which you should remember are as follows.
- Python is a dynamically typed language which means the types correlate with values, not with variables. Hence, the polymorphism runs unrestricted.
- That’s one of the primary differences between Python and other statically typed languages such as C++ or Java.
- In Python, you don’t have to mention the specific data types while coding.
- However, if you do, then the code limits to the types anticipated at the time of coding.
- Such code won’t allow other compatible types that may be required in the future.
- Python doesn’t support any form of function overloading.
Parameters in a Function
We often use the terms parameters and arguments interchangeably. However, there is a slight difference between them.
Parameters are the variables used in the function definition whereas arguments are the values we pass to the function parameters.
Python supports different variations of passing parameters to a function. Before we discuss each of them, you should read the following notes.
- The argument gets assigned to the local variable name once passed to the function.
- Changing the value of an argument inside a function doesn’t affect the caller.
- If the argument holds a mutable object, then changing it in a function impacts the caller.
- We call the passing of immutable arguments as Pass by Value because Python doesn’t allow them to change in place.
- The passing of mutable arguments happens to be Passed by Pointer in Python because they are likely to be affected by the changes inside a function.
Example: Immutable vs. Mutable
def test1(a, b) : a = 'Garbage' # 'a' receives an immutable object b[0] = 'Python' # 'b' receives a list object # list is mutable # it can undergo an in place change def test2(a, b) : a = 'Garbage 2' b = 'Python 3' # 'b' now is made to refer to new # object and therefore argument 'y' # is not changed arg1 = 10 arg2 = [1, 2, 3, 4] test1(arg1, arg2) print("After executing test 1 =>", arg1, arg2) test2(arg1, arg2) print("After executing test 2 =>", arg1, arg2)
After execution, the above code prints the following.
After executing test 1 => 10 ['Python', 2, 3, 4] After executing test 2 => 10 ['Python', 2, 3, 4]
Example: Avoid change in mutable argument
def test1(a, b) : a = 'Garbage' b[0] = 'Python' arg1 = 10 arg2 = [1, 2, 3, 4] print("Before test 1 =>", arg1, arg2) test1(arg1, arg2[:]) # Create an explicit copy of mutable object # 'y' in the function. # Now 'b' in test1() refers to a # different object which was initially a # copy of 'arg2' print("After test 1 =>", arg1, arg2)
After execution, the above code prints the following.
Before test 1 => 10 [1, 2, 3, 4] After test 1 => 10 [1, 2, 3, 4]
Standard arguments
The standard arguments are those that you pass as specified in a Python function definition. It means without changing their order and without skipping any of them.
def fn(value): print(value) return fn()
Executing the above code throws the below error as we’ve not passed the single argument required.
TypeError: fn() missing 1 required positional argument: 'value'
Keyword-based arguments
When you assign a value to the parameter (such as param=value) and pass it to the function (like fn(param=value)), then it turns into a keyword argument.
If you pass the keyword arguments to a function, then Python determines it through the parameter name used in the assignment.
See the below example.
def fn(value): print(value) return fn(value=123) # output => 123 fn(value="Python!") # output => Python!
While using keyword arguments, you should make sure that the name in the assignment should match the one in the function definition. Otherwise, Python throws the TypeError as shown below.
fn(value1="Python!") # wrong name used in the keyword argument
The above function call causes the following error.
TypeError: fn() got an unexpected keyword argument 'value1'
Arguments with Default Values
Python functions allow setting the default values for parameters in the function definition. We refer to them as the default arguments.
The callee uses these default values when the caller doesn’t pass them in the function call.
The below example will help you clearly understand the concept of default arguments.
def daysInYear(is_leap_year=False): if not is_leap_year: print("365 days") else: print("366 days") return daysInYear() daysInYear(True)
Here, the parameter “is_leap_year” is working as a default argument. If you don’t pass any value, it assumes the False default.
The output of the above code is:
365 days 366 days
Variable Arguments
You may encounter situations when you have to pass additional arguments to a Python function. We refer to them as variable-length arguments.
Python’s print() is itself an example of such a function that supports variable arguments.
To define a function with variable arguments, you need to prefix the parameter with an asterisk (*) sign. Follow the below syntax.
def fn([std_args,] *var_args_tuple ): """docstring""" function_body return_statement
Check out the below example for better clarity.
def inventory(category, *items): print("%s [items=%d]:" % (category, len(items)), items) for item in items: print("-", item) return inventory('Electronics', 'tv', 'lcd', 'ac', 'refrigerator', 'heater') inventory('Books', 'python', 'java', 'c', 'c++')
The output of the above code goes like this.
Electronics [items=5]: ('tv', 'lcd', 'ac', 'refrigerator', 'heater') - tv - lcd - ac - refrigerator - heater Books [items=4]: ('python', 'java', 'c', 'c++') - python - java - c - c++
Please note that you can choose to have a formal argument or not in the function definition along with the variable arguments.
You may choose to skip the variable arguments while calling the function. In such a case, the tuple would remain empty.
Use Variables in Functions
Two types of variables can exist in a Python function. Let’s check out.
Local Variables inside a Function
A local variable has visibility only inside a code block such as the function def. They are available only while the function is executing. Check out the below example of using local variables.
def fn(a, b) : temp = 1 for iter in range(b) : temp = temp*a return temp print(fn(2, 4)) print(temp) # error : can not access 'temp' out of scope of function 'fn' print(iter) # error : can not access 'iter' out of scope of function 'fn'
In this example, we try to access local variables outside the function body which results in the NameError.
The function’s local variables don’t retain values between calls. The names used inside a def do not conflict with variables outside the def, even if you’ve used the same names elsewhere.
In Python, the variables assignment can occur at three different places.
- Inside a def – it is local to that function
- In an enclosing def – it is nonlocal to the nested functions
- Outside all def(s) – it is global to the entire file
Global Variables in a Function
The global keyword is a statement in Python. It enables variables (names) to retain changes that live outside a def, at the top level of a module file.
In a single global statement, you can specify one or more names separated by commas.
All the listed names are attached to the enclosing module’s scope when assigned or referenced within the function body.
Check the below example.
x = 5 y = 55 def fn() : global x x = [3, 7] y = [1, 33, 55] # a local 'y' is assigned and created here # whereas, 'x' refers to the global name fn() print(x, y)
In the above code, ‘x’ is a global variable that will retain any change in its value made in the function. Another variable ‘y’ has local scope and won’t carry forward the change.
Let’s now see how a globally declared name behaves in two different Python functions.
foo = 99 def fn1() : foo = 'new' # new local foo created def fn2() : global foo foo = 'update' # value of global foo changes
In the next example, let’s see how global behaves with the import statement.
Here, we have the following three scripts:
- mod_global.py: It contains the global definition and a function changing and displaying values.
- test1.py: It imports the first file and accesses the global variable.
- test2.py: It uses the “from” clause to import the first file and access the global variable.
# mod_global.py def fn1() : global x x = [1,2] ; y = [20, 200] # a local 'y' is created – availableonly within 'f1' # 'x' can be accessed anywhere after a call to 'f1' fn1() try : print(x, y) # name 'y' is not defined – error except Exception as ex: print('y ->', ex) print('x ->', x)
# test1.py import mod_global print('test1 ->', mod_global.x)
# test2.py from mod_global import * print('test2 ->', x)
General Function Rules
While creating and calling the functions, you should know about the following rules.
Name Resolution in a Python Function
It is essential to understand how name resolution works in case of a def statement.
Here are a few points you should keep in mind.
- The name assignments create or change local names.
- The LEGB rule comes in the picture for searching the name reference.
- local – L
- then enclosing functions (if any) – E
- next comes the global – G
- and the last one is the built-in – B
To gain more understanding, run through the below example.
#var = 5 def fn1() : #var = [3, 5, 7, 9] def fn2() : #var = (21, 31, 41) print(var) fn2() fn1() # uncomment var assignments one-by-one and check the output print(var)
After uncommenting the first “var” assignment, the output is:
5 5
Next, after uncommenting the second “var” assignment as well, the output is:
[3, 5, 7, 9] 5
Finally, if we uncomment the last “var” assignment, then the result is as follows.
(21, 31, 41) 5
Variable Scope in Functions
Python functions can access names in all available enclosing def statements.
Check the below example.
X = 101 # global scope name - unused def fn1(): X = 102 # Enclosing def local def fn2(): print(X) # Reference made in nested def fn2() # Prints 102: enclosing def local fn1()
The scope lookup remains in action even if the enclosing function has already returned.
def fn1(): print('In fn1') X = 100 def fn2(): print('In fn2') print(X) # Remembers X in enclosing def scope return fn2 # Return fn2 but don't call it action = fn1() # Make, return function action() # Call fn2() now: prints 100
The output is as follows.
In fn1 In fn2 100
Return Values from a Python Function
In Python functions, you can add the “return” statement to return a value.
Usually, the functions return a single value. But if required, Python allows returning multiple values by using the collection types such as using a tuple or list.
This feature works like the call-by-reference by returning tuples and assigning the results back to the original argument names in the caller.
def returnDemo(val1, val2) : val1 = 'Windows' val2 = 'OS X' return val1, val2 # return multiple values in a tuple var1 = 4 var2 = [2, 4, 6, 8] print("before return =>", var1, var2) var1, var2 = returnDemo(var1, var2) print("after return =>", var1, var2)
The above code gives the following output.
before return => 4 [2, 4, 6, 8] after return => Windows OS X
Python Function Examples
We have compiled a few distinct Python function examples. Check these and try to practice with them.
Check out a general function call example.
def getMin(*varArgs) : min = varArgs[0] for i in varArgs[1:] : if i < min : min = i return min min = getMin(21, -11, 17, -23, 6, 5, -89, 4, 9) print(min)
The output is as follows.
-89
Next is an example of the recursive function.
def calcFact(num) : if(num != 1) : return num * calcFact(num-1) else : return 1 print(calcFact(4))
The output is as follows.
24
Also Read: Higher Order Functions in Python
Python Functions as Objects
Yes, Python treats everything as an object and functions are no different.
You can assign a function object to any other name.
def testFunc(a, b) : print('testFunc called') fn = testFunc fn(22, 'bb')
The output is:
testFunc called
You can even pass the function object to other functions.
def fn1(a, b) : print('fn1 called') def fn2(fun, x, y) : fun(x, y) fn2(fn1, 22, 'bb')
The output is:
fn1 called
You can also embed a function object in data structures.
def fn1(a) : print('fn1', a) def fn2(a) : print('fn2', a) listOfFuncs = [(fn1, "First function"), (fn2, "Second function")] for (f, arg) in listOfFuncs : f(arg)
The output is:
fn1 First function fn2 Second function
You can return a function object from another function.
def FuncLair(produce) : def fn1() : print('fn1 called') def fn2() : print('fn2 called') def fn3() : print('fn3 called') if produce == 1 : return fn1 elif produce == 2 : return fn2 else : return fn3 f = FuncLair(2) ; f()
The output is:
fn2 called
Function Attributes
Python functions also have attributes.
- You can list them via the dir() built-in function.
- The attributes can be system-defined.
- Some of them can be user-defined as well.
- The dir() function also lists the user-defined attributes.
def testFunc(): print("I'm just a test function.") testFunc.attr1 = "Hello" testFunc.attr2 = 5 testFunc() print(dir(testFunc))
The output is:
I'm just a test function. ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'attr1', 'attr2']
You can utilize the function attributes to archive state information instead of using any of the globals or nonlocal names. Unlike the nonlocals, attributes are accessible anywhere the function itself is, even from outside its code.
We’ve covered the essential concept of a Python function in this tutorial. You should now try to use these concepts in your routine programming tasks.
Before you leave. share this post on social media (Linkedin/Twitter). It would help us run this site free for our users.
Enjoy coding,
TechBeamers.