A function is a block of code which only runs when it is called, you can pass data, known as parameters, into a function, a function can return data as a result. A function will perform a specific task and is generally named to hightlight this task. Python uses the def keyword to start a function and uses the normal Python indentation for the block (no braces)
Arguments are passed to functions in by object reference. The parameter becomes a new reference to the object. For immutable objects (such as tuples, strings, and numbers), what is done with a parameter has no effect outside the function. But if you pass in a mutable object (such as a list, dictionary, or class instance), any change made to the object changes what the argument is referencing outside the function
Basic function | def function1(): # notice the semi-colon at the end print("Hello World") function1() |
Passing Parameters | def function2(str1, str2): print(str1 + " " + str2) function2("Hello", "World") # you can pass parameters by position function2(str2="World", str1="Hello") # you can pass parameters by name |
Default values | def function3(str1, str2="world"): # using a default value return str1 + " " + str2 print(function3("Hello", "Paul")) # the function will use both passed values print(function3("Hello")) # the function will use the default value |
Variable number of parameters | def function4(*strings): # variable number of arguments (mixed data types) print(strings[0] + " " + strings[1] + " " + str(strings[2])) # you could use a for loop here function4("Hello", "World", 100) # you can send mixed data types Note: If the final parameter in the parameter list is prefixed with **, it collects all excess keyword-passed arguments into a dictionary. The key for each entry in the dictionary is the keyword (parameter name) for the excess argument. The value of that entry is the argument itself. An argument passed by keyword is excess in this context if the keyword by which it was passed doesn’t match one of the parameter names in the function definition. |
Using Local variables | def function5(): i = 101 # you can create local variables y = "Hello World" print(str(i) + " " + y) function5() |
Using Global variables | g_var = 10 nl_var = 5 def function5(): def inner_function(): global g_var # use the global variable, 10 nonlocal nl_var # bind to closest scoped nl_var variable, 25 print(str(g_var) + " " + str(nl_var)) g_var = 20 nl_var = 25 print(str(g_var) + " " + str(nl_var)) # we are using the local variables, 20 and 25 inner_function() function5() Note: You can explicitly make a variable global by declaring it so before the variable is used, using the global statement. Global variables can be accessed and changed by the function. They exist outside the function and can also be accessed and changed by other functions that declare them global or by code that’s not within a function. |
Assigning functions to variables | def function2(str1, str2): print(str1 + " " + str2) funcVariable = function2 # you can assign a function to a variable funcVariable("Hello", "World") # then use the variable like a normal function |
Short functions can alos defined by using lambda expressions
t2 = {'FtoK': lambda deg_f: 273.15 + (deg_f - 32) * 5 / 9, 'CtoK': lambda deg_c: 273.15 + deg_c} print(t2['FtoK'](32)) |
Generator function is a special kind of function that you can use to define your own iterator. When you define a generator function, you return each iteration’s value using the yield keyword. The generator will stop returning values when there are no more iterations, or it encounters either an empty return statement or the end of the function. Local variables in a generator function are saved from one call to the next, unlike in normal functions.
Generator Function | def four(): x = 0 while x < 4: print("in generator, x =", x) yield x # notice the yield keyword x += 1 for i in four(): print(i) |
Functions can also be passed as arguments to other functions and passed back as return values from other functions. It’s possible, for example, to write a Python function that takes another function as its parameter, wraps it in another function that does something related, and then returns the new function. This new combination can be used instead of the original function.
A decorator is syntactic sugar for this process and lets you wrap one function inside another with a one-line addition. It still gives you exactly the same effect as the previous code, but the resulting code is much cleaner and easier to read. Very simply, using a decorator involves two parts: defining the function that will be wrapping or “decorating” other functions and then using an @ followed by the decorator immediately before the wrapped function is defined. The decorator function should take a function as a parameter and return a function
Decorator | def decorate(func): print("in decorate function, decorating", func.__name__) def wrapper_func(*args): print("Executing", func.__name__) return func(*args) return wrapper_func # return the wrapped function def myfunction(parameter): print(parameter) myfunction = decorate(myfunction) # The wrapped function is called after the decorator function has completed, # results in 'in decorate function, decorating myfunction' myfunction("hello") # results in 'Executing myfunction' # 'hello' |