Python-decorateurs
Python-decorateurs
Een decorateur neemt een functie over, voegt wat functionaliteit toe en geeft deze terug. In deze tutorial leer je hoe je een decorateur kunt maken en waarom je deze zou moeten gebruiken.
Video:@Decorators in Python
Decorateurs in Python
Python heeft een interessante functie genaamd decorators om functionaliteit toe te voegen aan een bestaande code.
Dit wordt ook wel metaprogrammering genoemd omdat een deel van het programma een ander deel van het programma probeert te wijzigen tijdens het compileren.
Vereisten voor het leren van decorateurs
Om te begrijpen wat decorateurs zijn, moeten we eerst een paar basisdingen in Python weten.
We moeten ons comfortabel voelen met het feit dat alles in Python (Ja! Zelfs klassen), objecten zijn. Namen die we definiëren zijn eenvoudig identifiers die aan deze objecten zijn gebonden. Functies zijn geen uitzonderingen, het zijn ook objecten (met attributen). Er kunnen verschillende namen aan hetzelfde functieobject worden gebonden.
Hier is een voorbeeld.
def first(msg):
print(msg)
first("Hello")
second = first
second("Hello")
Uitvoer
Hello Hello
Wanneer u de code uitvoert, werken beide functies first
en second
dezelfde output geven. Hier de namen first
en second
verwijzen naar hetzelfde functie-object.
Nu worden de dingen vreemder.
Functies kunnen als argumenten aan een andere functie worden doorgegeven.
Als je functies zoals map
. hebt gebruikt , filter
en reduce
in Python, dan weet je dit al.
Dergelijke functies die andere functies als argumenten aannemen, worden ook wel functies van hogere orde . genoemd . Hier is een voorbeeld van zo'n functie.
def inc(x):
return x + 1
def dec(x):
return x - 1
def operate(func, x):
result = func(x)
return result
We roepen de functie als volgt aan.
>>> operate(inc,3)
4
>>> operate(dec,3)
2
Bovendien kan een functie een andere functie teruggeven.
def is_called():
def is_returned():
print("Hello")
return is_returned
new = is_called()
# Outputs "Hello"
new()
Uitvoer
Hello
Hier, is_returned()
is een geneste functie die wordt gedefinieerd en geretourneerd elke keer dat we is_called()
. aanroepen .
Ten slotte moeten we meer weten over Closures in Python.
Terug naar Decorateurs
Functies en methoden worden aanroepbaar genoemd zoals ze genoemd kunnen worden.
In feite kan elk object dat de speciale __call__()
. implementeert methode wordt callable genoemd. Dus in de meest basale zin is een decorateur een callable die een callable retourneert.
Kortom, een decorateur neemt een functie in zich, voegt wat functionaliteit toe en geeft deze terug.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
Wanneer u de volgende codes in shell uitvoert,
>>> ordinary()
I am ordinary
>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary
In het bovenstaande voorbeeld, make_pretty()
is een binnenhuisarchitect. In de toewijzingsstap:
pretty = make_pretty(ordinary)
De functie ordinary()
werd versierd en de geretourneerde functie kreeg de naam pretty
.
We kunnen zien dat de decorateurfunctie een aantal nieuwe functionaliteit aan de oorspronkelijke functie heeft toegevoegd. Dit is vergelijkbaar met het inpakken van een cadeau. De decorateur fungeert als een wikkel. De aard van het object dat is versierd (eigenlijk geschenk binnenin) verandert niet. Maar nu ziet het er mooi uit (sinds het versierd is).
Over het algemeen decoreren we een functie en wijzen we deze opnieuw toe als,
ordinary = make_pretty(ordinary).
Dit is een veel voorkomende constructie en om deze reden heeft Python een syntaxis om dit te vereenvoudigen.
We kunnen de @
. gebruiken symbool samen met de naam van de decorateurfunctie en plaats deze boven de definitie van de te decoreren functie. Bijvoorbeeld,
@make_pretty
def ordinary():
print("I am ordinary")
is gelijk aan
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
Dit is slechts een syntactische suiker om decorateurs te implementeren.
Functies decoreren met parameters
De bovenstaande decorateur was eenvoudig en werkte alleen met functies die geen parameters hadden. Wat als we functies hadden die parameters innamen zoals:
def divide(a, b):
return a/b
Deze functie heeft twee parameters, a en b . We weten dat het een foutmelding geeft als we b . doorgeven als 0.
>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Laten we nu een decorateur maken om te controleren op dit geval dat de fout veroorzaakt.
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
Deze nieuwe implementatie retourneert None
als de fout zich voordoet.
>>> divide(2,5)
I am going to divide 2 and 5
0.4
>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide
Op deze manier kunnen we functies decoreren die parameters nodig hebben.
Een scherp waarnemer zal opmerken dat parameters van de geneste inner()
functie binnen de decorateur is hetzelfde als de parameters van functies die hij decoreert. Hiermee rekening houdend, kunnen we nu algemene decorateurs maken die met een willekeurig aantal parameters werken.
In Python wordt deze magie gedaan als function(*args, **kwargs)
. Op deze manier, args
zal de tupel van positionele argumenten zijn en kwargs
zal het woordenboek van trefwoordargumenten zijn. Een voorbeeld van zo'n decorateur is:
def works_for_all(func):
def inner(*args, **kwargs):
print("I can decorate any function")
return func(*args, **kwargs)
return inner
Decorateurs aaneenketenen in Python
Meerdere decorateurs kunnen in Python worden geketend.
Dit wil zeggen dat een functie meerdere keren kan worden ingericht met verschillende (of dezelfde) decorateurs. We plaatsen de decorateurs gewoon boven de gewenste functie.
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%" * 30)
func(*args, **kwargs)
print("%" * 30)
return inner
@star
@percent
def printer(msg):
print(msg)
printer("Hello")
Uitvoer
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
De bovenstaande syntaxis van,
@star
@percent
def printer(msg):
print(msg)
is gelijk aan
def printer(msg):
print(msg)
printer = star(percent(printer))
De volgorde waarin we decorateurs ketenen, is van belang. Als we de volgorde hadden omgedraaid als,
@percent
@star
def printer(msg):
print(msg)
De uitvoer zou zijn:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Python
- Python-gegevenstypen
- Python-operators
- Python pass-instructie
- Python-functieargumenten
- Python Anonieme/Lambda-functie
- Python Lambda-functies met VOORBEELDEN
- Python abs() Functie:Voorbeelden van absolute waarden
- Python round() functie met VOORBEELDEN
- Python range() Functie:Float, List, For loop Voorbeelden
- Python map() functie met VOORBEELDEN
- Opbrengst in Python-zelfstudie:voorbeeld van generator en rendement versus rendement