Python-sisustajat: Kuinka sitä käytetään ja miksi?

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 firstja secondantavat saman tuloksen. Tässä nimet firstja secondviittaavat samaan funktio-objektiin.

Nyt asiat alkavat muuttua outoiksi.

Funktiot voidaan välittää argumentteina toiselle funktiolle.

Jos olet käyttänyt toimintoja, kuten map, filterja reducePythonissa, 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, Nonejos 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 ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Mielenkiintoisia artikkeleita...