# Functies
# Aanroepen
# ./python/syntax/functions/call.py
print()
print('hello, world\n')
2
3
$ python3 ./python/syntax/functions/call.py
hello, world
$ _
# Eigen Functies
# Definiëren
# ./python/syntax/functions/definition.py
def my_function():
pass
2
3
Omdat een definitie altijd een body moet hebben zetten we in het bovenstaande voorbeeld pass
, wat eigenlijk niks doet.
# Definiëren en aanroepen
# ./python/syntax/functions/definition_and_call.py
def hello():
print('hello, world\n')
# Testing
hello()
2
3
4
5
6
7
$ python3 ./src/python/syntax/functions/definition_and_call.py
hello, world
$ _
# Parameters en argumenten
# ./python/syntax/functions/parameter_and_argument.py
def hello(name):
print(f'hello, {name}\n')
# Testing
hello('Olivier')
2
3
4
5
6
7
$ python3 ./python/syntax/functions/parameter_and_argument.py
hello, Olivier
$ _
# Standaardwaarde voor een argument
# ./python/syntax/functions/default_argument_value.py
def hello(name='anonymous'):
print(f'hello, {name}\n')
# Testing
hello()
hello('Olivier')
2
3
4
5
6
7
8
$ python3 ./python/syntax/functions/default_argument_value.py
hello, anonymous
hello, Olivier
$ _
# Argumenten met naam
# ./python/syntax/functions/named_arguments.py
def hello(first_name, last_name):
print(f'hello, {first_name} {last_name}\n')
# Testing
hello('Olivier', 'Parent')
hello(first_name='Olivier', last_name='Parent')
hello(last_name='Parent', first_name='Olivier')
2
3
4
5
6
7
8
9
$ python3 ./python/syntax/functions/named_arguments.py
hello, Olivier Parent
hello, Olivier Parent
hello, Olivier Parent
$ _
# Functie als argument
In Python is een functies een eersteklasobject (Eng. first-class object) waardoor ze als argument aan een functie meegegeven kunnen worden.
# Type Hinting
Python laat toe dat je bij elke parameter een type hint toevoegt, maar Python zal dit zelf niet controleren.
# ./python/syntax/functions/type_hinting.py
def sum(a: int = 0, b: int = 0) -> str:
sum = a + b
return str(sum)
# Testing
sum(12, 89)
sum('23', '78')
2
3
4
5
6
7
8
9
Om de types te controleren moet je een aparte module installeren zoals mypy
.
$ python3 -m pip install --upgrade pip
$ python3 -m pip install mypy
Om het de code te testen met mypy
.
$ python3 -m mypy type_hinting.py
type_hinting.py:6: error: Argument 1 to "sum" has incompatible type "str"; expected "int"
type_hinting.py:6: error: Argument 2 to "sum" has incompatible type "str"; expected "int"
$ _
# Naamruimte en Bereik
De naamruimtehiërarchie (Eng. namespace hierarchy) in Python is LEGB:
- Lokale naamruimte (Eng. Local namespace) – binnenste naamruimte van een functie.
- Insluitende naamruimten (Eng. Enclosing namespaces) van insluitende functies.
- Globale naamruimte (Eng. Global namespace) van de module.
- Ingebouwde naamruimte (Eng. Built-in namespace) – buitenste naamruimte.
Een statisch bereik (static scope) – ook wel **lexicaal brereik ** genoemd) als het tijdens de functiedefinitie bepaald is, en dynamisch als het tijdens het uitvoeren bepaald wordt.
# Locaal bereik
Het lokaal bereik (Eng. local scope) is het normaal bereik binnen een functie.
# ./python/syntax/functions/scope__1.py
i = 1
def do_outer_enclosing_scope():
i = 20
def do_inner_enclosing_scope():
i = 300
def do_local_scope():
i = 4000
print('4. In local scope:\t\t', i)
# Testing
print('3. In inner enclosing scope:\t', i)
do_local_scope()
print('5. In inner enclosing scope:\t', i)
# Testing
print('2. In outer enclosing scope:\t', i)
do_inner_enclosing_scope()
print('6. In outer enclosing scope:\t', i)
# Testing
print('1. In global scope:\t\t', i)
do_outer_enclosing_scope()
print('7. In global scope:\t\t', i)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ python3 ./python/syntax/functions/scope__1.py
1. In global scope: 1
2. In outer enclosing scope: 20
3. In inner enclosing scope: 300
4. In local scope: 4000
5. In inner enclosing scope: 300
6. In outer enclosing scope: 20
7. In global scope: 1
$ _
# Niet-lokaal bereik
Het niet-lokaal bereik (Eng. nonlocal scope) geef je aan met nonlocal
en verwijst naar de dichtste omsluitende naamruimte.
# ./python/syntax/functions/scope__2.py
i = 1
def do_outer_enclosing_scope():
i = 20
def do_inner_enclosing_scope():
i = 300
def do_local_scope():
nonlocal i
i = 4000
print('4. In local scope:\t\t', i)
# Testing
print('3. In inner enclosing scope:\t', i)
do_local_scope()
print('5. In inner enclosing scope:\t', i)
# Testing
print('2. In outer enclosing scope:\t', i)
do_inner_enclosing_scope()
print('6. In outer enclosing scope:\t', i)
# Testing
print('1. In global scope:\t\t', i)
do_outer_enclosing_scope()
print('7. In global scope:\t\t', i)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ python3 ./python/syntax/functions/scope__2.py
1. In global scope: 1
2. In outer enclosing scope: 20
3. In inner enclosing scope: 300
4. In local scope: 4000
5. In inner enclosing scope: 4000
6. In outer enclosing scope: 20
7. In global scope: 1
$ _
# Globaal bereik
Het globaal bereik (Eng. global scope) geef je aan met gobal
en verwijst naar de naamruimte van de module.
# ./python/syntax/functions/scope__3.py
i = 1
def do_outer_enclosing_scope():
i = 20
def do_inner_enclosing_scope():
i = 300
def do_local_scope():
global i
i = 4000
print('4. In local scope:\t\t', i)
# Testing
print('3. In inner enclosing scope:\t', i)
do_local_scope()
print('5. In inner enclosing scope:\t', i)
# Testing
print('2. In outer enclosing scope:\t', i)
do_inner_enclosing_scope()
print('6. In outer enclosing scope:\t', i)
# Testing
print('1. In global scope:\t\t', i)
do_outer_enclosing_scope()
print('7. In global scope:\t\t', i)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ python3 ./python/syntax/functions/scope__3.py
1. In global scope: 1
2. In outer enclosing scope: 20
3. In inner enclosing scope: 300
4. In local scope: 4000
5. In inner enclosing scope: 300
6. In outer enclosing scope: 20
7. In global scope: 4000
$ _
# Lambda-expressies
In Python kan een anonieme functie gemaakt worden met een lambda-expressie (Eng. lambda expression). Hiervoor gebruik je het keyword lambda
.
Een lambda-expressie bestaat uit 1 regel code. De functiebody van een lambda-expressie bestaat uit een expressie die als returnwaarde teruggegeven wordt. Er is dus geen expliciet return
-statement.
# Lambdafunctie
In onderstaand voorbeeld berekenen we
# ./python/syntax/functions/lambda.py
numbers = range(10)
nth_roots = map(lambda n: n ** n, numbers)
for item in (tuple(zip(numbers, nth_roots))):
print(f'{item[0]}^{item[0]} is {item[1]}')
2
3
4
5
6
$ python3 ./python/syntax/functions/lambda.py
0^0 is 1
1^1 is 1
2^2 is 4
3^3 is 27
4^4 is 256
5^5 is 3125
6^6 is 46656
7^7 is 823543
8^8 is 16777216
9^9 is 387420489
$ _
# Closure
Een closure wordt meestal met een anonieme functie gemaakt, maar dit hoeft eigenlijk niet.
In onderstaand voorbeeld gebruiken we een lambda-expressie om closures te maken voor elk BTW-tarief (Eng. VAT rate) in België:
# ./python/syntax/functions/lambda_closure.py
def make_vat_calculator(percentage):
return lambda amount: amount + amount * percentage
vat_06 = make_vat_calculator(.06)
vat_12 = make_vat_calculator(.12)
vat_21 = make_vat_calculator(.21)
# Testing
print(vat_06(100))
print(vat_12(100))
print(vat_21(100))
2
3
4
5
6
7
8
9
10
11
12
13
$ python3 ./python/syntax/functions/closure_as_lambda.py
106.0
112.0
121.0
$_
# Decorator
Een decorator wrapt een functie in een closure (in het voorbeeld is dat de functie wrapper()
).
# ./python/syntax/functions/decorator__1.py
def my_decorator_function(the_function):
def wrapper():
print('Before!')
the_function()
print('After!')
return wrapper
def my_function():
print('Now!')
a_decorated_function = my_decorator_function(my_function)
# Testing
a_decorated_function()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ python3 ./python/syntax/functions/decorator__1.py
Before!
Now!
After!
$ _
Dit kan met syntaxissuiker (Eng. syntactic sugar) korter geschreven worden.
# ./python/syntax/functions/decorator__2.py
def my_decorator(the_function):
def wrapper():
print('Before!')
the_function()
print('After!')
return wrapper
@my_decorator
def a_decorated_function():
print('Now!')
# Testing
a_decorated_function()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ python3 ./python/syntax/functions/decorator__1.py
Before!
Now!
After!
$ _
# Toepassing
Een concrete toepassing is bijvoorbeeld een timer maken om de uitvoeringstijd te bepalen.
# Ingebouwde Functies
# Print en Data Pretty Printer
# ./python/syntax/functions/print/data.py
DATA = [
('EN', {'one': 1, 'two': 2, 'three': 3}),
('FR', {'un': 1, 'deux': 2, 'trois': 3}),
('NL', {'een': 1, 'twee': 2, 'drie': 3}),
]
2
3
4
5
6
# ./python/syntax/functions/print.py
from data import DATA as d
print(d)
2
3
4
$ python3 ./python/syntax/functions/print/print.py
[('EN', {'one': 1, 'two': 2, 'three': 3}), ('FR', {'un': 1, 'deux': 2, 'trois': 3}), ('NL', {'een': 1, 'twee': 2, 'drie': 3})]
$ _
# ./python/syntax/functions/print/data_pretty_printer.py
from data import DATA as d
from pprint import pprint
pprint(d)
2
3
4
5
$ python3 ./python/syntax/functions/print/data_pretty_printer.py
[('EN', {'one': 1, 'three': 3, 'two': 2}),
('FR', {'deux': 2, 'trois': 3, 'un': 1}),
('NL', {'drie': 3, 'een': 1, 'twee': 2})]
$ _
# Random Functies
De standaardmodule random
importeren
# ./python/syntax/functions/random/randomint__1.py
import random
for i in range(1, 6):
ri = random.randint(0, 9999)
print(f'{i}: {str(ri).rjust(4)}')
2
3
4
5
6
$ python3 ./python/syntax/functions/random/randomint__1.py
1: 5710
2: 2540
3: 667
4: 7149
5: 1661
$ _
Enkel de methode randint
van de standaardmodule random
importeren zodat je die als functie kan gebruiken.
# ./python/syntax/functions/random/randomint__2.py
from random import randint
for i in range(1, 6):
ri = randint(0, 9999)
print(f'{i}: {str(ri).rjust(4)}')
2
3
4
5
6
$ ./python/syntax/functions/random/randomint__2.py
1: 7953
2: 7145
3: 100
4: 6030
5: 4106
$ _
# Wiskundige Functies
abs()
pow(«radix», «exponent»)
sum()
max()
min()
round()
all() -> bool
any() -> bool
chr()
bin()
oct()
hex()
# Logaritmen
# ./python/syntax/functions/math/logarithm.py
from math import log2, log10
for i in range(1, 7):
exp_2 = 2 ** i
exp_10 = 10 ** i
log_2 = log2(exp_2)
log_10 = log10(exp_10)
print(f'log2({exp_2}) = {log_2}\tlog10({int(exp_10)}) = {int(log_10)}')
2
3
4
5
6
7
8
9
$ python3 ./python/syntax/functions/math/logarithm.py
log2(2) = 1 log10(10) = 1
log2(4) = 2 log10(100) = 2
log2(8) = 3 log10(1000) = 3
log2(16) = 4 log10(10000) = 4
log2(32) = 5 log10(100000) = 5
log2(64) = 6 log10(1000000) = 6
$ _