Functions

Functions are blocks of code identified by a name, which can receive ""predetermined"" parameters or not ;).

In Python, functions:

  • return objects or not.
  • can provide documentation using Doc Strings.
  • Can have their properties changed (usually by decorators).
  • Have their own namespace (local scope), and therefore may obscure definitions of global scope.
  • Allows parameters to be passed by name. In this case, the parameters can be passed in any order.
  • Allows optional parameters (with pre-defined defaults ), thus if no parameter are provided then, pre-defined default will be used.

Syntax:

def func_name(parameter_one, parameter_two=default_value):
    """
    Doc String
    """
    <code block>
    return value

NOTE: The parameters with default value must be declared after the ones without default value.


In [3]:
def caps(val):
    """
    caps returns double the value of the provided value
    """
    return val*2

a = caps("TEST ")
print(a)
print(caps.__doc__)


TEST TEST 

    caps returns double the value of the provided value
    

In the above example, we have caps as function, which takes val as argument and returns val * 2.


In [6]:
a = caps(1234)
print(a)


2468

Functions can return any data type, next example returns a boolean value.


In [5]:
def is_valid(data):
    if 10 in data:
        return True
    return False

a = is_valid([10, 200, 33, "asf"])
print(a)


True

In [22]:
a = is_valid((10,))
print(a)


True

In [25]:
is_valid((10,))


Out[25]:
True

In [7]:
a = is_valid((110,))
print(a)


False

In [11]:
def is_valid_new(data):
    return 10 in data

print(is_valid_new([10, 200, 33, "asf"]))


True

In [12]:
a = is_valid_new((110,))
print(a)


False

Example (factorial without recursion):


In [13]:
def fatorial(n):#{
    n = n if n > 1 else 1
    j = 1
    for i in range(1, n + 1):
        j = j * i
    return j
    #}

# Testing...
for i in range(1, 6):
    print (i, '->', fatorial(i))


1 -> 1
2 -> 2
3 -> 6
4 -> 24
5 -> 120

Example (factorial with recursion):


In [12]:
def factorial(num):
    """Fatorial implemented with recursion."""
    if num <= 1:
        return 1
    else:
        return(num * factorial(num - 1))

# Testing factorial()
print (factorial(5))

# 5 * (4 * (3 * (2) * (1))


120

Example (Fibonacci series with recursion):


In [13]:
def fib(n):
    """Fibonacci:
    fib(n) = fib(n - 1) + fib(n - 2) se n > 1
    fib(n) = 1 se n <= 1
    """
    if n > 1:
        return fib(n - 1) + fib(n - 2)
    else:
        return 1

# Show Fibonacci from 1 to 5
for i in [1, 2, 3, 4, 5]:
    print (i, '=>', fib(i))


1 => 1
2 => 2
3 => 3
4 => 5
5 => 8

Example (Fibonacci series without recursion):


In [14]:
def fib(n):    
    # the first two values
    l = [1, 1]
    
    # Calculating the others
    for i in range(2, n + 1):
        l.append(l[i -1] + l[i - 2])
        
    return l[n]

# Show Fibonacci from 1 to 5
for i in [1, 2, 3, 4, 5]:
    print (i, '=>', fib(i))


1 => 1
2 => 2
3 => 3
4 => 5
5 => 8

In [2]:
def test(a, b):
    print(a, b)
    return a + b
    
print(test(1, 2))
test(b=1, a=2)


1 2
3
2 1
Out[2]:
3

In [3]:
def test_abc(a, b, c):
    print(a, b, c)
    return a + b + c
test_abc(b=1, a=2, 3)

Output:

File "<ipython-input-10-e66702cbcb27>", line 2
    test_abc(b=1, a=2, 3)
                      ^
SyntaxError: positional argument follows keyword argument

NOTE: We cannot have non-keyword arguments after keyword arguments


In [4]:
test_abc(2, c=3, b=2)


2 2 3
Out[4]:
7

In [5]:
test_abc(2, b=2, c=3)


2 2 3
Out[5]:
7

In [7]:
try:
    test_abc(2, a=12, c=3)
except Exception as e:
    print(e)


test_abc() got multiple values for argument 'a'

Functions can also not return anything like in the below example


In [24]:
def test_new(a, b, c):
    pass

Functions can also return multiple values, usually in form of tuple.


In [25]:
def test(a, b):
    print(a, b)
    return a*a, b*b

x, a = test(2, 5)

print(x)
print(type(x))
print(a)
print(type(a))


2 5
4
<class 'int'>
25
<class 'int'>

In [27]:
print(type(test(2, 5)))


2 5
<class 'tuple'>

In [32]:
def test(a, b):
    print(a, b)
    return a*a, b*b, a*b

In [33]:
x = test(2 , 5)
print(x)
print(type(x))


2 5
(4, 25, 10)
<class 'tuple'>

In [47]:
def test(a, b):
    print(a, b)
    return a*a, b*b, "asdf"

x = test(2, 5)
print(x)
print(type(x))


2 5
(4, 25, 'asdf')
<class 'tuple'>

In [48]:
def test(a=100, b=1000):
    print(a, b)
    return a, b

x = test(2, 5)
print(x)
print(test(10))


2 5
(2, 5)
10 1000
(10, 1000)

In [49]:
def test(a=100, b=1000):
    print(a, b)
    return a, b

print(test(b=10))
print(test(101))


100 10
(100, 10)
101 1000
(101, 1000)

In [9]:
def test(d, c, a=100, b=1000):
    print(d, c, a, b)
    return d, c, a, b

x = test(c=2, d=10, b=5)
print(x)
x = test(1, 2, 3, 4)
print(x)
print(test(10, 2))


10 2 100 5
(10, 2, 100, 5)
1 2 3 4
(1, 2, 3, 4)
10 2 100 1000
(10, 2, 100, 1000)

Example (RGB conversion):


In [3]:
def rgb_html(r=0, g=0, b=0):
    """Converts R, G, B to #RRGGBB"""

    return '#%02x%02x%02x' % (r, g, b)

def html_rgb(color='#000000'):
    """Converts #RRGGBB em R, G, B"""

    if color.startswith('#'): color = color[1:]

    r = int(color[:2], 16)
    g = int(color[2:4], 16)
    b = int(color[4:], 16)

    return r, g, b


print (rgb_html(200, 200, 255))
print (rgb_html(b=200, g=200, r=255))
print (html_rgb('#c8c8ff'))


#c8c8ff
#ffc8c8
(200, 200, 255)

Note: non-default argument's should always follow default argument

Example:

def test(d, a=100, c, b=1000):
        print(d, c, a, b)
        return d, c, a, b

x = test(c=2, d=10, b=5)
print(x)
x = test(1, 2, 3, 4)
print(x)
print(test(10, 2))

Output:

File "<ipython-input-6-3d33b3561563>", line 1
    def test(d, a=100, c, b=1000):
            ^
SyntaxError: non-default argument follows default argument

In [4]:
def test(c, d, a=100, b=1000):
    print(d, c, a, b)
    return d, c, a, b

x = test(c=2, d=10, b=5)
print(x)
x = test(1, 2, 3, 4)
print(x)
print(test(10, 2))


10 2 100 5
(10, 2, 100, 5)
2 1 3 4
(2, 1, 3, 4)
2 10 100 1000
(2, 10, 100, 1000)

Observations:

  • The  arguments with default value must come last, after the non-default arguments.
  • The default value for a parameter is calculated when the function is defined.
  • The arguments passed without an identifier are received by the function in the form of a list.
  • The arguments passed to the function with an identifier are received in the form of a dictionary.
  • The parameters passed to the function with an identifier should come at the end of the parameter list.

Example of how to get all parameters:


In [18]:
# *args - arguments without name (list)
# **kargs - arguments with name (ditcionary)

def func(*args, **kargs):
    print (args)
    print (kargs)

func('weigh', 10, unit='k')


('weigh', 10)
{'unit': 'k'}

In the example, kargs will receive the named arguments and args will receive the others.

The interpreter has some builtin functions defined, including sorted(), which orders sequences, and cmp(), which makes comparisons between two arguments and returns -1 if the first element is greater, 0 (zero) if they are equal, or 1 if the latter is higher. This function is used by the routine of ordering, a behavior that can be modified.

Example:


In [21]:
def func(* , **kargs):
    print (args)
    print (kargs)
a = {
    "name": "Mohan kumar Shah",
    "age": 24 + 1
}
func('weigh', 10, unit='k', val=a)


('weigh', 10)
{'val': {'age': 25, 'name': 'Mohan kumar Shah'}, 'unit': 'k'}

In [24]:
def func(*args):
    print(args)

func('weigh', 10, "test")


('weigh', 10, 'test')

In [25]:
data = [(4, 3), (5, 1), (7, 2), (9, 0)]

# Comparing by the last element
def _cmp(x, y):
    return cmp(x[-1], y[-1])

print ('List:', data)


('List:', [(4, 3), (5, 1), (7, 2), (9, 0)])

Python also has a builtin function eval(), which evaluates code (source or object) and returns the value.

Example:


In [1]:
print (eval('12. / 2 + 3.3'))


9.3

In [7]:
def listing(lst):
    for l in lst:
        print(l)
       
d = {"Mayank Johri":40, "Janki Mohan Johri":68}
listing(d)


Mayank Johri
Janki Mohan Johri

In [1]:
d = {
    "name": "Mohan",
    "age": 24
}

a = {
    "name": "Mohan kumar Shah",
    "age": 24 + 1
}

def process_dict(d=a):
    print(d)

process_dict(d)
process_dict()


{'name': 'Mohan', 'age': 24}
{'name': 'Mohan kumar Shah', 'age': 25}

In [11]:
def test(a=[]):
    a.append(1)
    print(a)

test()
test()
test()


[1]
[1, 1]
[1, 1, 1]

In [13]:
def test(a=None):
    if a == None:
        a = []
    a.append(1)
    print(a)

test()
test()
test()


[1]
[1]
[1]

In [ ]: