Sisustaja ottaa toiminnon, lisää toiminnallisuutta ja palauttaa sen. Tässä opetusohjelmassa opit, kuinka voit luoda sisustajan ja miksi sinun pitäisi käyttää sitä.
Sisustajat Pythonissa
Pythonilla on mielenkiintoinen ominaisuus, jota kutsutaan sisustajiksi toiminnallisuuden lisäämiseksi olemassa olevaan koodiin.
Tätä kutsutaan myös metaprogrammiksi, koska osa ohjelmaa yrittää muokata toista ohjelman osaa kääntöhetkellä.
Edellytykset sisustajien oppimiselle
Jotta ymmärtäisimme sisustajia, meidän on ensin tiedettävä muutama perusasia Pythonissa.
Meidän on oltava tyytyväisiä siihen, että kaikki Pythonissa (Kyllä! Jopa luokat) ovat esineitä. Määrittelemämme nimet ovat yksinkertaisesti näihin objekteihin sidottuja tunnisteita. Funktiot eivät ole poikkeuksia, ne ovat myös objekteja (määritteillä). Useita eri nimiä voidaan sitoa samaan funktio-objektiin.
Tässä on esimerkki.
def first(msg): print(msg) first("Hello") second = first second("Hello")
Tuotos
terve terve
Kun suoritat koodin, molemmat toiminnot first
ja second
antavat saman tuloksen. Tässä nimet first
ja second
viittaavat samaan funktio-objektiin.
Nyt asiat alkavat muuttua outoiksi.
Funktiot voidaan välittää argumentteina toiselle funktiolle.
Jos olet käyttänyt toimintoja, kuten map
, filter
ja reduce
Pythonissa, tiedät jo siitä.
Sellaisia funktioita, jotka ottavat muita toimintoja argumentteina, kutsutaan myös korkeamman asteen funktioiksi . Tässä on esimerkki tällaisesta toiminnosta.
def inc(x): return x + 1 def dec(x): return x - 1 def operate(func, x): result = func(x) return result
Käynnistämme funktion seuraavasti.
>>> operate(inc,3) 4 >>> operate(dec,3) 2
Lisäksi toiminto voi palauttaa toisen toiminnon.
def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() # Outputs "Hello" new()
Tuotos
Hei
Tässä is_returned()
on sisäkkäinen toiminto, joka määritetään ja palautetaan joka kerta, kun soitamme is_called()
.
Lopuksi meidän on tiedettävä Pythonin sulkemisista.
Palaa sisustajille
Toiminnot ja menetelmät voivat olla vaadittaessa maksettavaa , sillä ne voidaan kutsua.
Itse asiassa mitä tahansa erikoismenetelmän toteuttavaa esinettä __call__()
kutsutaan kutsuvaksi. Joten alkeellisessa mielessä sisustaja on soitettava, joka palauttaa soitettavan.
Pohjimmiltaan sisustaja ottaa toiminnon, lisää toimintoja ja palauttaa sen.
def make_pretty(func): def inner(): print("I got decorated") func() return inner def ordinary(): print("I am ordinary")
Kun suoritat seuraavat koodit kuoressa,
>>> ordinary() I am ordinary >>> # let's decorate this ordinary function >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated I am ordinary
Yllä olevassa esimerkissä make_pretty()
on sisustaja. Tehtävävaiheessa:
pretty = make_pretty(ordinary)
Funktio ordinary()
koristeltiin ja palautetulle funktiolle annettiin nimi pretty
.
Voimme nähdä, että sisustustoiminto lisäsi uusia toimintoja alkuperäiseen toimintoon. Tämä muistuttaa lahjan pakkaamista. Sisustaja toimii kääreenä. Koristeltu esine (todellinen lahja sisällä) ei muutu. Mutta nyt se näyttää hyvältä (koska se koristeltiin).
Yleensä koristamme funktion ja määritämme sen uudelleen
ordinary = make_pretty(ordinary).
Tämä on yleinen rakenne, ja tästä syystä Pythonilla on syntaksin yksinkertaistamiseksi.
Voimme käyttää @
symbolia yhdessä sisustustoiminnon nimen kanssa ja sijoittaa sen koristettavan toiminnon määritelmän yläpuolelle. Esimerkiksi,
@make_pretty def ordinary(): print("I am ordinary")
vastaa
def ordinary(): print("I am ordinary") ordinary = make_pretty(ordinary)
Tämä on vain syntaktinen sokeri sisustajien toteuttamiseksi.
Toimintojen koristelu parametreilla
Yllä oleva sisustaja oli yksinkertainen ja se toimi vain sellaisten toimintojen kanssa, joilla ei ollut mitään parametreja. Entä jos meillä olisi toimintoja, jotka ottavat parametrit, kuten:
def divide(a, b): return a/b
Tällä toiminnolla on kaksi parametria, a ja b. Tiedämme, että se antaa virheen, jos välitämme b: n arvoksi 0.
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last):… ZeroDivisionError: division by zero
Tehdään nyt sisustaja tarkistaaksesi tämän tapauksen, joka aiheuttaa virheen.
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)
Tämä uusi toteutus palaa, None
jos virhetila ilmenee.
>>> 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
Tällä tavoin voimme koristaa toimintoja, jotka ottavat parametrit.
Tarkka tarkkailija huomaa, inner()
että sisustusyksikön sisäkkäisen toiminnon parametrit ovat samat kuin sen koristamien toimintojen parametrit. Kun tämä otetaan huomioon, voimme nyt tehdä yleisiä sisustajia, jotka toimivat minkä tahansa määrän parametreilla.
In Python, this magic is done as function(*args, **kwargs)
. In this way, args
will be the tuple of positional arguments and kwargs
will be the dictionary of keyword arguments. An example of such a decorator will be:
def works_for_all(func): def inner(*args, **kwargs): print("I can decorate any function") return func(*args, **kwargs) return inner
Chaining Decorators in Python
Multiple decorators can be chained in Python.
This is to say, a function can be decorated multiple times with different (or same) decorators. We simply place the decorators above the desired function.
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")
Output
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
The above syntax of,
@star @percent def printer(msg): print(msg)
is equivalent to
def printer(msg): print(msg) printer = star(percent(printer))
The order in which we chain decorators matter. If we had reversed the order as,
@percent @star def printer(msg): print(msg)
The output would be:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%