Python – Writing Functions – Complete Guide

Writing Python code is fun and easy. You can use Procedural programming, Functional programming , Object oriented programming or any combination.  Functions are basic unit in any method you choose.

Functions are objects, defined with the ‘def’ statement followed by argument list. The function body is defined using indentation like other python statements

def fn(a,b):
    return a+b

x = fn(10,20)

Arguments are named, defaults may be assigned , return statement is optional and you can return anything. Variables inside functions are local unless the keyword ‘global’ is used

Default Values

You can assign default values to the parameters:

def fn(a = 100,b = 200):
    return a+b

print(fn()) # 100 + 200
print(fn(10)) # 10 + 200
print(fn(10,20)) # 10 + 20

if one parameter is defaulted then all that follow must also be defaulted too so def fn(a=100, b) gives a syntax error

Passing parameters by name

You can ignore the parameter position and pass it by name. This is useful when functions have many parameters with default values:

def fn(a = 100,b = 200):
    return a+b*10

print(fn(a=10,b=20)) # 210
print(fn(b=30,a= 10)) # 310

Enforcing Named Parameters (Python 3)

You can use * to force a user to supply named arguments:

def fn(*, a = 100,b = 200):
    return a+b*10

print(fn()) # 2100
print(fn(b=30,a= 10)) # 310
print(fn(10,20)) # TypeError fn() takes 0 positional arguments but 2 were given


Variadic Functions

Variadic functions have a variable number of parameters. They can be collected into a tuple with a * prefix

def fn(a ,*all ):
    for item in all:
    return a+sum

print(fn(10)) # 10
print(fn(10,20)) # 30
print(fn(10,20,30,40,50)) # 150


Keyword Parameters

Keyword parameters (kwargs) enable the parameters to be passed as a disctionary. The parameters are placed into a dictionary means that the user does not need to get the order correct.  This is useful with a long parameter list for example while connecting to a database (user, password, dbname, …) . A kwargs parameter may only be used at the end of a parameter list.

You can send named parameters or a dictionary. Use ** if caller’s parameters are in a dictionary

def fn(**kwargs ):
    return kwargs['a'] + kwargs['b']

print(fn(a=200,b=500)) # 700

d1 = {'a':100 , 'b':200}
print(fn(**d1)) # 300


Global Variables

The rules of scope in Python are that an undefined variable used in a function must be a global, but if a value is assigned in the function before it is used then it is a local.

For example:

num = 9

def f1():
    num = 20

def f2():

f2() # 9
f2() # 9

The function f1 declares a local copy of num so it won’t change the global value. To access the global num:

num = 9

def f1():
    global num
    num = 20

def f2():

f2() # 9
f2() # 20


Nested Functions

You can place a function inside another function for simple scope or for closure

In the following example only f1 can use the function f2.

def f1(a):
    def f2(s):
        print(b) # 100
        return s+10
    return c

f2(66) # NameError: name 'f2' is not defined

variables in nested functions:

If we define a variables with the same name in a different scopes it may confuses the interpreter for example:

b = 3
def f1():
    b = 10

    def f2():
        if b < 100: # error here
            b += 1

    print(b, "from f1")

print(b, "from main")

This code will fail with the error: UnboundLocalError: local variable ‘b’ referenced before assignment

To fix this you need to declare b as global or nonlocal


b = 3
def f1():
    b = 10

    def f2():
        nonlocal b
        if b < 100:
            b += 1

    print(b, "from f2") # 11 from f2

print(b, "from main") # 3 from main


b = 3
def f1():
    b = 10

    def f2():
        global b
        if b < 100:
            b += 1

    print(b, "from f2") # 10 from f2

print(b, "from main") # 4 from main



Functions are objects so you can pass a function as a parameter to another function or return a function from another function. This is useful when you write a function that create and return another function dynamically for example, gets a list of points (x,y) and returns an interpolation function.


def getmulby(m):
    def op(n):
        return m*n
    return op


print( f1(2) ) # 20
print( f2(2) ) # 10

Each call to getmulby returns a new function



Decorator is a good example of closure. Decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it

def add_stars(some_function):
    def wrapper():
    return wrapper

def my_function():


# ********************
# Hello!!!
# ********************

Before calling my_function we are actually calling add_stars sending my_function as a parameter. The function add_stars returns the inner function (closure)  and this is what we really invoke.

This is very helpful while writing infrastructures


Lambda Expressions

lambda functions are anonymous functions for simple operations. It is very common where we pass a function to another function. For example the builtin map function to map a list to a new list:

ls = [2,4,6]

newlist = map(lambda item:item * 2, ls)

for n in newlist:
# 4
# 8
# 12

lambda functions cannot contain branches or loops but can contain conditional expression. Usually a simple expression:

import random

f1 = lambda x:x+10
f2 = lambda :random.randint(100,200)
f3 = lambda x,y:x+y
compare=lambda a,b: -1 if a < b else (+1 if a > b else 0)

print( f1(10) ) # 20
print( f2() ) # prints random number 
print( f3(2,3)) # 5
print( compare(10,20) ) # -1


Function Documentation

You can add docstring comments to a function. It is used for help function and automated testing.

def add(a,b):
    """ Simple function - add 2 numbers"""
    return a+b

>>> help(add)
Help on function add in module __main__:

add(a, b)
    Simple function - add 2 numbers

It is stored in an attribute __doc__. You can set it explicitly


Function Annotations (Python 3)

You can add documentation to the parameters and the return value:

def add(a:"first number" = 0,
        b:"second number" = 0) -> "sum of a and b":
    return a+b

for item in add.__annotations__.items():

# ('a', 'first number')
# ('b', 'second number')
# ('return', 'sum of a and b')


Subscribe to our list









6 thoughts on “Python – Writing Functions – Complete Guide

  1. Please use pep8

  2. […] Python – Writing Functions – Complete Guide […]

  3. VPN tunnel by VPNKI with python

Comments are closed.