# Functies

# Aanroepen


 
 

# ./python/syntax/functions/call.py
print()
print('hello, world\n')
1
2
3
$ python3 ./python/syntax/functions/call.py

hello, world

$ _

# Eigen Functies

# Definiëren


 


# ./python/syntax/functions/definition.py
def my_function():
    pass
1
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()
1
2
3
4
5
6
7
$ python3 ./src/python/syntax/functions/definition_and_call.py
hello, world

$ _

# Parameters en argumenten

Parameter

Een parameter is de variabele in de functiedefinitie.

Argument

Een argument is de waarde of verwijzing die je meegeeft bij het aanroepen van de functie. Dit kan in de vorm van een literal of een variabele zijn.


 




 

# ./python/syntax/functions/parameter_and_argument.py
def hello(name):
    print(f'hello, {name}\n')


# Testing
hello('Olivier')
1
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')
1
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')
1
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.

Hogere-orderfunctie

Een hogere-ordefunctie (Eng. higher-order function) is een functie die een andere functie als argument neemt.

Opmerking

Ook in JavaScript zijn functies eersteklasobjecten

# 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')
1
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

Naamruimte

Een naamruimte (Eng. namespace) is een reeks van namen die aan een object toegewezen (Eng. mapped) zijn. Er kunnen meerdere namen aan eenzelfde object toegewezen zijn.

De naamruimtehiërarchie (Eng. namespace hierarchy) in Python is LEGB:

  1. Lokale naamruimte (Eng. Local namespace) – binnenste naamruimte van een functie.
  2. Insluitende naamruimten (Eng. Enclosing namespaces) van insluitende functies.
  3. Globale naamruimte (Eng. Global namespace) van de module.
  4. Ingebouwde naamruimte (Eng. Built-in namespace) – buitenste naamruimte.

Bereik

Een bereik (Eng. scope) is het codegebied waarbinnen Python een (niet-gekwalificeerde) naam opzoekt in de naamruimten om zo het juiste object te vinden.

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.

Gekwalificeerd en Ongekwalificeerd.

Een naam met de vermelding van de naamruimte noemt men gekwalificeerde naam (Eng. qualified name), terwijl een naam zonder vermelding een niet-gekwalificeerde naam (Eng. unqualified name) is.

# 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)
1
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)
1
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)
1
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

Anonieme Functie

Een anonieme functie (Eng. anonymous function) is een functie die gedefinieerd wordt zonder identifier.

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

Lambdafunctie

Een lambdafunctie (Eng. lambda function) is een anonieme functie die als argument voor een hogere-ordefunctie gebruikt wordt.

In onderstaand voorbeeld berekenen we met een lambdafunctie van .



 




# ./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]}')
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

Closure

Een closure is een functie die een waarde die niet in de lokale scope zit vastlegt in de lexicale scope – de scope bij het definiëren van de functie.

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ë: , of .



 











# ./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))
1
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()
1
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()
1
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

Mappen & Bestanden

  • print/
    • data_pretty_print.py
    • data.py
    • print.py
# ./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}),
]
1
2
3
4
5
6



 

# ./python/syntax/functions/print.py
from data import DATA as d

print(d)
1
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)
1
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

Opgelet

Computers zijn gemaakt om bij dezelfde input hetzelfde resultaat te geven. Algoritmes maken doe echte random (Ned. willekeurige) getallen maken is daarom heel erg moeilijk. Veel algoritmes vertonen een voorspelbaar patroon. De betere algortimes maken gebruik van datums en/of andere veranderlijke gegevens om een pseudorandom getal te genereren.

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)}')
1
2
3
4
5
6
$ python3 ./python/syntax/functions/random/randomint__1.py
1: 5710
2: 2540
3:  667
4: 7149
5: 1661
$ _

Opgelet

Als je zelf een bestand maakt met de naam random.py kan dat een conflict opleveren met de gelijknamige module.

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)}')
1
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)}')
1
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
$ _

# Bronnen

© 2024 Arteveldehogeschool Laatst bijgewerkt: 14/2/2020, 11:07:52