index<--

## Python Functions

A function is a block of code that make a computation and return a result. If a block of code do not have a name or do not return a result it is not a function.This kind of block can be considered method, subroutine or maybe procedure. That is: the role of each block is establish by it's context.

Function Concepts

## Keyword: def

In Python we use keyword "def" to define a named block of code. This block can be reused to calculate one or more values called results. The result value is defined using keyword "return".If a block of code look like a function but do not return any value, then is not a function but something else.

#### Example:

In this example we define a block of code named "fib" that have a side-effect but does not return a result:This block of code is very similar to a function but is in fact a subprogram.That is: python do not use specific keywords like: "function", "procedure" or "method" but only "def".

``````
# create a function fib with parameter n
def fib(n):
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
pass # end fib

fib(2000) #call function fib
``````

`0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597`

Homework: Test this example live: Fibonacci

Note: Remember in Python the indentation is mandatory. A named block end when the indentation is back align with "def" keyword.In the example above, I have used keyword "pass" to make a "null statement" to mark the end of block.This style of programming is optional. Statement "pass" can be used to mark the end of any block of code.

The description of a function can be created using triple quotes and string as the first statement after the function declaration. This can be used to find information about function using: help(<function_name>)

## The Result

Functions usually produce a result that can be captured into a variable using assign operator "=". It can also be used in expressions. In the example below we calculate a mathematical function: "f(n) = !n" (factorial) using a recursive function call. That is a function that call itself with different parameters until a condition becomes True:

#### Example:

``````
# calculate factorial of n
def factorial(n):
if n==0:
return 1
else:
return n*factorial(n-1)

# call factorial function and capture result
result=factorial(5)
print(result)
``````

## Parameters

Function parameters, sometimes called "formal parameters" are actually local variables that can receive values from a function call. Parameters can be mandatory or optional. Mandatory parameters are usually declared first. Optional parameters, have a "default value" specified in parameter declaration using notation: `"param = value" or "param:type = value.`

Mandatory arguments

To execute a function we use function name follow by a list of arguments enclosed in round brackets and separated by comma like: `function_name(args).` The parenthesis are mandatory after the function name, otherwise the function is not executed.If a function has mandatory parameters, for each parameter we must provide and argument. The argument can be a value, a variable or an expression.

Optional arguments

Arguments are paired-up with parameters by position or by name using equal sign. Mandatory and optional arguments can coexist in a call. For mandatory parameters we can assign arguments by position while optional parameters can receive arguments by name. We can also use names for all arguments, but this is unusual practice.

#### Example:

Next example is using what you have learned so far to create a median function. This function is good only for 2 up to 5 numbers. It also has a logical defect to establish the divisor in case of zero value arguments.

``````
# define function with variable argument
def avg(a,b,c=0,d=0,e=0):
divisor = 2
if c != 0: divisor += 1;
if d != 0: divisor += 1;
if e != 0: divisor += 1;
result = (a+b+c+d+e)/divisor;
return result

# test function avg
print (avg(2,4)); # 3.0
print (avg(0,5,10)); # 5.0
print (avg(0,0,e=9)); # 3.0
print (avg(1,0,d=10,e=20)); #7.75
``````

Homework: Copy the example from here: optional and then make a better version using variable argument "varargs", that you will learn later in this article. Post your snippet on Discord or make a Gist on GitHub and brag about it on reddit.I will give you one reputation point for this job.

## Variable arguments

A procedure can receive a list of arguments into one special parameter. This feature is sometimes called: "varargs" or "rest". For declaring this parameter we use prefix "*". This parameter becomes a collection of values visible in local scope.

#### Example:

``````
# define function with variable argument
def sum_all(first:int, *rest: [int]) -> int:
result: int = first
for e in rest:
result += e
return result

# test function sum_all
print (sum_all(0)); # 0
print (sum_all(1,2)); # 3
print (sum_all(1,2,3)); # 6

args = [1,1,1]
print (sum_all(*args)); # 3
``````

Homework: Test this snippet on-line: Varargs

Note: In the example above I have used a new syntax available since Python 3.6, that enables you to specify parameters types, variable types and function result type. This may surprise you since you know, Python is a dynamic language. It is a good practice to use this style of programming.

Type hinting may improve program readability but does not affect performance. It was introduced to improve programming experience for developers. Python can use type hinting to avoid logical mistakes for large projects.

## Namespace

A namespace is a composite word from "name" and "space". It represents a block of code that hold several identifiers. A namespace is defined by a "scope". This is a region of a program used to define: variables, constants and functions.

#### Example:

``````
# define large namespace
def scope_test():
# local scope
def do_local():
spam = "local spam"
pass # end do_local

def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
pass # end do_nonlocal

def do_global():
global spam
spam = "global spam"
pass # end do_global

# back to namespace
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
pass # end scope_test

# back to global scope
scope_test() # test function with no result
print("In global scope:", spam)
``````

Test this example live: Namespaces

Output of the program:

``````
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
``````

Note: The namespaces are nested. The outermost scope is called "global" scope and it create a "global" namespace. Functions can be nested. Inside every function there is a local namespace.

Using "=" will create a new variable in the local scope. If a variable exists already defined in the global scope or in the parent scope it is shadowed. We create a new variable in the local scope that hide the outer scope variable. To avoid shadowing we have to declare variables using "global" or "nonlocal" keywords.This is necessary for every single nested function that uses other variables than the local variables.

## Function attributes

In Python a function is an object. Any object can have attributes that can be created using a dot operator. Function attributes are attached to the function as static variables. This is another alternative to global variables and it can be used to create encapsulated functions that behave like objects.

#### Example:

In the next example the function test_attr() is creating an attribute called counter the first time is called. Then the attribute is used to memorize the current counter value. Next time is able to return the value and increment it for next call.

``````
# demonstrate attributes attached to a function
def test_attr():
if not hasattr(test_attr, "counter"):
test_attr.counter = 0
else:
test_attr.counter += 1
return test_attr.counter
pass # end test_attr

# call function  attributes
def main():
for i in range(0,10):
j=test_attr()
print(i,'->',j)
pass # end main

# compiler entry point
if __name__ == "__main__":
main()
pass # end if
``````

Homework: Open test this example live: Attributes

Test output:

``````
0 -> 0
1 -> 1
2 -> 2
3 -> 3
4 -> 4
5 -> 5
6 -> 6
7 -> 7
8 -> 8
9 -> 9
``````

## Switch function:

Switch statement does not exist in Python.However you can simulate a switch statement using different techniques. In the next example we create a fake statement switch using two functions:

``````
#define a value holder function
# => True
def switch(value):
switch.value=value
return True

#define matching case function
# => True or False
def case(*args):
return any((arg == switch.value for arg in args))

# Switch example:
print("Describe a number from range:")
for n in range(0,10):
print(n, end=",")
print(flush=True)

# Ask for a number and analyze
x=input("n:")
n=int(x)
while switch(n):
if case(0):
print ("n is zero;")
break
if case(1, 4, 9):
print ("n is a perfect square;")
break
if case(2):
print ("n is an even number;")
if case(2, 3, 5, 7):
print ("n is a prime number;")
break
if case(6, 8):
print ("n is an even number;")
break
print ("Only single-digit numbers are allowed.")
pass # end of switch
``````

## Example description

switch: In the example above I use one function "switch" with attribute "value" and one function "case" that return True or False if "switch.value" is one of arguments.

case: Is a function that receive a variable number of arguments. This function uses any(...), a Python function that returns True if any item in an iterable object is True, otherwise it returns False. If the iterable object is empty, the any() function will return False.

while: Using while loop will iterate one single time ant we can use break statement like a "switch" statement will do. This example demonstrate how using meaningful names for functions python language can be extended in interesting ways.

print: This example also demonstrate how to use print function to print numbers and avoid new line using optional parameter end=",".

## Testing the program

Open this example live and run it: switch function

``````
Describe a number from range:
0,1,2,3,4,5,6,7,8,9,
n:3
n is a prime number;

Process finished with exit code 0
``````