Na dość prostym przykładzie poznamy short-circuiting, czyli pewien sposób warunkowego wywoływania funkcji.
Wyjaśnimy sobie, czym jest tzw. short circuiting na prostych przykładach. A jest to sposób na wywoływanie – warunkowe – wielu różnych funkcji na raz w oparciu o operatory logiczne „or” i „and”.
Rzućmy okiem na ten przykład:
person1 = {"name" : "John", "age": 30, "drunk": False}
person2 = {"name" : "John", "age": 13, "drunk": False}
def check_age(person):
return person["age"] >= 18
def get_drunk(person):
person["drunk"] = True
return True
print(person1)
# {'name': 'John', 'age': 30, 'drunk': False}
get_drunk(person1)
print(person1)
# {'name': 'John', 'age': 30, 'drunk': True}
Mamy tutaj słowniki person1 i person2 oraz funkcje check_age (sprawdza, czy wiek jest >= 18) oraz get_drunk („upija” nasz słownik, zwraca prawdę).
Teraz zadanie – wydać rozkaz „upicia” person1, ale tylko wtedy, gdy jest ona pełnoletnia.
Można osiągnąć to poprzez bloki if-else, ale nie tego chcemy się nauczyć.
Robimy to tak, używając short-circuiting:
check_age(person1) and get_drunk(person1)
print(person1)
# {'name': 'John', 'age': 30, 'drunk': True}
Czyli tak – funkcja check_age zostanie wywołana i jeżeli zwróci ona prawdę, wywoła się funkcja get_drunk (która też dobrze by było, aby prawdę zwracała, jeżeli chcielibyśmy podłączać tam jakieś kolejne funkcje).
To samo zróbmy z person2:
check_age(person2) and get_drunk(person2)
print(person2)
# {'name': 'John', 'age': 13, 'drunk': False}
Jak widać funkcja po prawej się nie wykonała, ponieważ ta po lewej zwróciła fałsz. Tak działa short-circuiting. Możemy to sobie sprawdzić dodając jeszcze jedną funkcję po prawej:
check_age(person1) and get_drunk(person1) and print("got drunk")
# got drunk
Jak widać funkcja check_age zwraca prawdę i odpala get_drunk. Funkcja get_drunk zwraca prawdę więc nasz print po prawej może się wykonać
A co zrobić z person2? Możemy użyć operatora „or”:
check_age(person2) and get_drunk(person2) or print("too young")
#too young
Tutaj check_age nie zwraca prawdy, więc get_drunk się nie wykonuje. Mamy jednak or, który sprawdza, czy „na lewo” od niego jest jakiś fałsz i jeżeli jest – odpala się jako alternatywa.
Innym przykładem użycia or byłoby coś takiego:
f.closed or f.close()
Mamy zmienną f, która jest plikiem. Posiada taki atrybut jak closed, który może wynosić False, jeżeli plik jest nadal otwarty.
I jeżeli f.closed zwraca fałsz, to wykonaj metodę close, która plik zamknie.
Po ludzku – jak nie jest zamknięty to go zamknij. Tak ta linijka wygląda.
I tym sposobem poznaliśmy sposób zwany szumnie „short-circuiting evaluation” albo „minimal evaluation”.
Nazwa pochodzi od tego, że program wykonuje minimum: jeżeli mamy and i coś po prawej nie zwraca prawdy, to nawet nie wywołuję funkcji po lewej, bo fałsz i prawda dają fałsz.
W przypadku alternatywy jest odwrotnie – funkcja wywołana po or wywoła się tylko wtedy, gdy to, co przed nią będzie fałszywe. Jeżeli będzie prawdziwe to nawet alternatywy wywoływać nie trzeba.
Albo po ludzku, jeszcze raz to powtórzę – [f.closed or f.close()] jak nie jest zamknięty to go zamknij