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.
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>)
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:
# 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)
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.
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.
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.
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.
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.
# 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 # combine with spread operator 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.
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.
# 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.
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.
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
0 -> 0 1 -> 1 2 -> 2 3 -> 3 4 -> 4 5 -> 5 6 -> 6 7 -> 7 8 -> 8 9 -> 9
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
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=",".
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
Read next: Classes