1. Home
  2. Docs
  3. Python 101 – Python Programming for Beginners
  4. Functions

Functions

Functions

 

What is a function ?

 
A function a sequence of statements which perform computation.

Functions makes it possible to reuse the code.

In Python we have two kinds of functions,

built-in functions and user defined function.

The creators of Python, wrote a set of functions to address most common problems.

And included them as a part of standard Python installation.

Examples.

len(), abs(), int(), str(), print(), input(), open() etc..
 

What are user defined funcitons ?

 
Functions which are written by user, other than built-in functions,

to solve a problem.

A function is a reusable code,

which takes arguments as inputs, does some computation, and returns a result.

Some function takes arguments, some don’t,

Like wise some function return result, and some don’t.

Functions that do not return implicitly return the value None.

Syntax:

def function_name([arguments]):
    statements
	[return result]

 

In Python functions are created by using a def keyword,

providing a funciton name, followed by arguments inside parentheses.

def is shorthand for define.  def keyword binds the function name to its body.

Parentheses are mandatory, even if function takes no arguments.

A (:) colon at the end of the def line, starts a function block.

Statements inside function block are indented.

Indentation is must, otherwise Python interpreter throws indentation error.

Funciton name is just a reference(lable) to a function object.

The only operation on function object is to call it.

To call a function, its name used fallowed by arguments inside parentheses.

Lets look at some examples of functions.

Example:

1. Function does nothing, takes not arguments and returns nothing

# do_nothing is  function name
def do_nothing():
	pass

#Calling do_nothing

do_nothing()

2. Function to say Hello, World.

def say_hello():
	print("Hello, World")

say_hello()

 

Functions with arguments
 

What is an argument ?

An argument is a value passed to a function as an input during a function call.

In Python its possible to have different options to pass arguments.

Four types of Arguments

#1. Required arguments
#2. Optional arguments
#3. Variable positional arguments
#4. Variable keyword arguments

 

Lets look at some example for each of these possibilities.
 

#1. Required arguments

 
Function to add two numbers

# Takes two arguments, and returns the result

def add(num1, num2):
	return num1 + num2

sum = add(10,20)

Here both num1, num2, argument values are required at function call.

 

#2. Optional arguments

 
Example of Optional arguments
 
When funciton is defined with default values for arguments,

passing values during function call is optional.

Its possible to have default values for arguments.
 

def add(a = 10, b = 20):
    return a + b

def add(a = 10, b = 20):
    print("a and b are :",a,b)
    return a + b

#add called with no arguments

sum1 = add() 

print("sum1 is :", sum1)

#add called with one arguments 

sum2 = add(30) 

print("sum2 is :", sum2)

#add called with two arguments

sum3 = add(60, 50) 

print("sum3 is :", sum3)


output:

a and b are : 10 20
sum1 is : 30
a and b are : 30 20
sum2 is : 50
a and b are : 60 50
sum3 is : 110


 

#3. Variable positional arguments

 
Passing variable number of arguments.

Most functions designed to work on fixed set of arguments.

But some can handle any number of arguments.

In Python its possible to pass varialbe arguments.

Lets see an example of this,


def sum_numbers(*args):
    sum = 0
    for i in args:
        sum += i
    return sum

sum_numbers(1,2,3,4,5,6)

sum_numbers(1,2)

sum_numbers()


In the above example sum_numbers takes variable number of arguments.
 

#4. Variable keyword arguments

 
Variable number of keyword arguments, with key value pair passed to funciton.
 

def user_details(**kwargs):
    for k ,v  in kwargs.items():
        print("Keyword args : %s = %s" %(k,v)) 



output:

user_details(name='Alex')

Keyword args : name = Alex

user_details(name ="John", age=23, pwd ='capital')

Keyword args : name = John
Keyword args : age = 23
Keyword args : pwd = capital

 

Example showing all arguments together.

 

def func_arg_options(req, opt ='abc', *args,**kwargs):
    print("req arg  :", req) 

    print("opt arg  :", opt) 

    for arg in args:
        print("Positional args :", arg) 

    for k ,v  in kwargs.items():
        print("Keyword args : %s = %s" %(k,v)) 


func_arg_options(15, 'xyz', 'another', name='Alex')

output:

req arg  : 15
opt arg  : xyz
Positional args : another
Keyword args : name = Alex


func_arg_options('change', age=23, pwd ='capital')

req arg  : change
opt arg  : abc
Keyword args : age = 23
Keyword args : pwd = capital

 

While using varargs position and keyword matters.

The order is required, optional, positional args, and keyword arguments.

Lets pass keyword argument before positional argument and see.
 

func_arg_options(15, 'xyz', name='Alex', 'another')

output:
File "", line 10
func_arg_options(15, 'xyz',name='Alex', 'another')
^
SyntaxError: positional argument follows keyword argument

 

Return more than one value.

 
Often a function takes arguments, does some computation, and

returns a result. The return keyword is used for this.

To get the result it has to be assigned to a variable, at the function call.

Example :

sum3 = add(60, 50)

add is function, takes two values for arguments 60, 50,

and result is assigned to a sum3 varible.

Unlike in other languages, In Python its possible to return more than one value.
 

def max_min(numbers):
	return max(numbers), min(numbers)

max_num, min_num = max_min([10,23,9,27,8,90,11])

print("max , and min are ", max_num, min_num)

output:
	max , and min are  90 8

 

How Python treats the return values?

 
Number of returned values How python treats internally

1. return 0 objects None # if nothing is returned python returns None

2. return 1 object object #python returns 1 object

3. more than 1 objects tuple #tuple as a collection of objects

 

Call by reference and call by value ?

 
Call by reference or call by value

Python doesn’t follow that model directly.

Its depends on passed arguments mutability

If the object is mutable, object can be changed in the function (reference)

If the object is not mutable then its call by value

Now we have understood bit about function,

its time to look at scopes of variables.

 

We have three types of scopes.

 
1. Global scope

Global variables can be accessed from anywhere

2. Local scope

Local variables can be accessed only in block where defined

3. Nonlocal scope

Accessible only in enclosing blocks(Inner functions, clousers)

Example:
 
Ex 1:

x = 2

def var_scope():
	y = 30
	print("I'm x and I'm global ", x)

	print("I'm y and I'm local ", y)
	
var_scope()

	
output:	
	I'm x and I'm global  2
	I'm y and I'm local  30

 
Ex 2:
 

x = 2

def var_scope():
    y = 30
    x = 20
    print("I'm x and I'm local ", x)

    print("I'm y and I'm local ", y)

print("I'm x and I'm global ", x)

var_scope()

output:
	I'm x and I'm global  2
	I'm x and I'm local  20
	I'm y and I'm local  30

 

What is namespace and scope ?

 
Namespace is bindings of names to an object.

There may be more than one variable with same name.

The scope of the variable is derived from namespace.

There are many namespaces,

each one for function, class, instance, modules, etc.

The global namespace represents, full contents of the file.

While inside function its a local namespace.

By using global() locals() built-in functions, we can access global and local namespaces.

Objects(variables, functions, classes, etc) defined in the file manipulate the global space.

Where is anything defined inside a function manipulates local namespace.
 

x = 20
#get the globals
print("Global scope before add():", globals())

output:
    
Global scope before add(): {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 20}
    
#define a function add
def add(a, b):
    #get the locals
    print("Local scope :", locals())
    return a + b

#calling add function
sum = add(10,30)

output:
    
Local scope : {'b': 30, 'a': 10}
    
#now get the globals again
print("Global scope after add():", globals())

output:

Global scope after add(): {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 20, 'add': <function add at 0x02A5D660>, 'sum': 40}

 
Take a closer look at the locals() and globals() output.
 

Scope evaluation order.

 
The variable evalution is done from inner most to the outer block.

Local -> nonlocal -> global , built-ins