A training to acquire strong basis in Python to use it efficiently
Pierre Augier (LEGI), Cyrille Bonamy (LEGI), Eric Maldonado (Irstea), Franck Thollard (ISTerre), Christophe Picard (LJK), Loïc Huder (ISTerre)
A function is a block of organized, reusable code that is used to perform a single, related action. Functions provide better modularity for your application and a high degree of code reusing.
None
and tuple
¶type(print())
NoneType
def return_a_tuple():
return 1, 'hello', 3 # a tuple, same as (1, 'hello', 3)
my_tuple = return_a_tuple()
print(my_tuple)
(1, 'hello', 3)
a, b, c = return_a_tuple()
print(b)
hello
For each function call:
Exercice: use 2 schemes "namespaces-objects" to understand these 2 pieces of code.
number = 2
mylist = []
def my_strange_append_square(l, n):
# new function namespace with names "l" and "n"
n = n**2
l.append(n)
my_strange_append_square(mylist, number)
print(mylist, number)
[4] 2
number = 2
mylist = []
def my_strange_append_square(mylist, number):
# new function namespace with names "mylist" and "number"
number = number**2
mylist.append( number)
my_strange_append_square(mylist, number)
print(mylist, number)
[4] 2
Variables that are defined inside a function body have a local scope (i.e. are defined in the function namespace), and those defined outside have a global scope.
This means that local variables can be accessed only inside the function in which they are declared, whereas global variables can be accessed throughout the module by all functions.
# global variables
result = 0
multiplicator = 2
def multiply(arg0):
# here we create a new name `result` in the function namespace
# `result` is a local variable
# we can use the global variable `multiplicator`
result = multiplicator * arg0
print('Inside the function local result:\t', result)
return result
multiply(10)
print('Outside the function global result:\t', result)
Inside the function local result: 20 Outside the function global result: 0
global
keyword. Discourage!).global
keyword¶There is a keyword global
to define inside a function a global variable and to modify a global variable in the function. It is often a bad idea to use it :-)
def func():
global me
# Defined locally but declared as global
me = 'global variable locally defined'
print(me)
func()
# Ask for a global variable
print(me)
global variable locally defined global variable locally defined
delta = 0
def add_1_to_delta():
global delta
# global variable modified in a function
delta += 1
for i in range(4):
add_1_to_delta()
print(delta, end=', ')
1, 2, 3, 4,
You can call a function by using the following types of formal arguments:
Required arguments are the arguments passed to a function in correct positional order. Here, the number of arguments in the function call should match exactly with the function definition.
def myfunc(arg0, arg1):
"Return the sum of the first argument with twice the second one."
result = arg0 + 2*arg1
print(f'arg0 + 2*arg1 = {arg0} + 2*{arg1} = {result}')
return result
myfunc(4, 6)
arg0 + 2*arg1 = 4 + 2*6 = 16
16
To call the function myfunc
, you definitely need to pass two arguments, otherwise it gives a syntax error.
Keyword arguments are related to the function calls. When you use keyword arguments in a function call, Python identifies the arguments by the parameter name.
myfunc(arg1=3, arg0=2)
arg0 + 2*arg1 = 2 + 2*3 = 8
8
A default argument is an argument that assumes a default value if a value is not provided in the function call for that argument.
def my_count(arg0, elem=None):
"""return the number of elem in arg0 if elem is None, else
the number of times elem appears"""
if elem is None:
return len(arg0)
nb_elem = 0
for e in arg0:
if e == elem:
nb_elem += 1
return nb_elem
assert my_count("abb") == 3
assert my_count("abb", "a") == 1
assert my_count("abb", "b") == 2
assert my_count("") == 0
assert my_count("abb", "c") == 0
Warning: the default arguments are created only once, at the function definition! They are stored in a tuple associated with the function object.
def do_not_use_mutable_object_for_default_arg(l=[]):
l.append(1)
print(l)
Exercice: what will be the result of 3 calls of this function? Use a namespaces-objects diagram!
Warning: the default arguments are created only once, at the function definition! They are stored in a tuple associated with the function object.
def do_not_use_mutable_object_for_default_arg(l=[]):
l.append(1)
print(l)
do_not_use_mutable_object_for_default_arg()
do_not_use_mutable_object_for_default_arg()
do_not_use_mutable_object_for_default_arg()
[1] [1, 1] [1, 1, 1]
def how_to_use_list_as_default_arg(l=None):
if l is None:
l = []
l.append(1)
print(l)
return l
l1 = [1, 2, 3]
how_to_use_list_as_default_arg(l1)
assert l1 == [1, 2, 3, 1]
assert how_to_use_list_as_default_arg() == [1]
assert how_to_use_list_as_default_arg() == [1]
[1, 2, 3, 1] [1] [1]
You may need to process a function for more arguments than you specified while defining the function. These arguments are called variable-length arguments and are not named in the function definition, unlike required and default arguments.
An asterisk (*) is placed before the variable name that holds the values of all nonkeyword variable arguments.
def sum_args(*args):
"""Return the sum of numbers."""
totalsum = 0
print('args =', args)
for var in args:
totalsum += var
print('totalsum =', totalsum)
return totalsum
sum_args()
sum_args(4)
sum_args(4, 3, 4, 7)
args = () totalsum = 0 args = (4,) totalsum = 4 args = (4, 3, 4, 7) totalsum = 18
18
There is also a (very useful) syntax with two asterisks **
, which works like this:
def func(a, b, *args, **kwargs):
print(f'call:\n\ta = {a}\n\targs = {args}\n\tkwargs = {kwargs}')
func(1, 2, 3, toto=3, titi=3)
func('a', 'b', bob=3)
call: a = 1 args = (3,) kwargs = {'toto': 3, 'titi': 3} call: a = a args = () kwargs = {'bob': 3}
Write a function that takes as input a list l
and a number a
and that multiplies
all the elements of the list by the number. If not set, number is defaulted to 2.
def multiply(l, factor=2):
""" nput a list l and a number a and that multiplies all the elements
of the list by the number. If not set, number is defaulted to 2."""
pass
import traceback
def test_func(func):
try:
l1 = [1, 2]
func(l1)
assert l1 == [2, 4]
func(l1, 4)
assert l1 == [8, 16]
l1 = []
func(l1)
assert l1 == []
l1 = ['a', 'b']
func(l1)
assert l1 == ["aa", "bb"]
except AssertionError:
traceback.print_exc()
else:
print("All tests pass!")
test_func(multiply)
Traceback (most recent call last): File "<ipython-input-20-411d52618068>", line 12, in test_func assert l1 == [2, 4] AssertionError
def multiply(l, a=2):
for i, val in enumerate(l):
l[i] = a * val
test_func(multiply)
All tests pass!
lambda
keyword and anonymous functions¶The lambda
functions are called anonymous because they have no name as they are not declared by using the def
keyword.
f = lambda x, y: x + y
print(f(1, 2))
print(f.__name__)
3 <lambda>
print
¶In [1]: print?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type: builtin_function_or_method