Python - tvetydighet med dekoratører som fikk en enkelt arg

stemmer
1

Jeg prøver å skrive en dekoratør som får en enkel arg, dvs.

@Printer(1)
def f():
    print 3

Så naivt, jeg prøvde:

class Printer:
    def __init__(self,num):
         self.__num=num
    def __call__(self,func):
         def wrapped(*args,**kargs):
              print self.__num
              return func(*args,**kargs**)
         return wrapped

Dette er ok, men det fungerer også som en dekoratør mottar ingen args, dvs.

@Printer
def a():
   print 3

Hvordan kan jeg unngå det?

Publisert på 21/08/2009 klokken 15:48
kilden bruker
På andre språk...                            


4 svar

stemmer
1

Er du sikker på at det fungerer uten argumenter? Hvis jeg la dem ut får jeg denne feilmeldingen:

Tilbakesporings (siste samtale sist):
  Fil "/tmp/blah.py", linje 28, i?
    en()
Feiltype: __call __ () tar nøyaktig 2 argumenter (1 angitt)

Du kan prøve dette alternativ definisjon, men hvis det klassebasert en ikke fungerer for deg.

def Printer(num):
    def wrapper(func):
        def wrapped(*args, **kwargs):
            print num
            return func(*args, **kwargs)
        return wrapped

    return wrapper
Svarte 21/08/2009 kl. 16:06
kilden bruker

stemmer
4

Vel, det er allerede effektivt forhindret, i den forstand at kallet a()ikke fungerer.

Men for å stoppe det som funksjonen er definert, jeg antar at du måtte endre __init__for å sjekke type num:

def __init__(self,num):
    if callable(num):
        raise TypeError('Printer decorator takes an argument')
    self.__num=num

Jeg vet ikke om dette er virkelig verdt bryet, skjønt. Det allerede virker ikke som det er; du virkelig be om å håndheve hvilke typer argumenter i en ande skrevet språk.

Svarte 21/08/2009 kl. 16:07
kilden bruker

stemmer
1

Dekoratør er uansett uttrykk etter @evalueres til. I det første tilfellet, det er en forekomst av Printer, så hva som skjer er (ganske mye) tilsvarer

decorator = Printer(1) # an instance of Printer, the "1" is given to __init__

def f():
    print 3
f = decorator(f) # == dec.__call__(f) , so in the end f is "wrapped"

I det andre tilfellet, er at klassen skriver, slik at du har

decorator = Printer # the class

def a():
   print 3
a = decorator(a) # == Printer(a), so a is an instance of Printer

Så selv om det fungerer (fordi konstruktøren av Printertar en ekstra argument, akkurat som __call__), det er en helt annen ting.

Python måte å forebygge dette vanligvis er: Ikke gjør det. Gjør det klart (for eksempel i docstring) hvordan fungerer dekoratør, og deretter stole på at folk gjør det rette.

Hvis du virkelig ønsker sjekken, Eevee svar gir en måte å fange denne feilen (under kjøring, selvfølgelig --- er det Python).

Svarte 21/08/2009 kl. 16:08
kilden bruker

stemmer
1

Jeg kan ikke tenke på en ideell svar, men hvis du tvinger Skriver klassen å brukes med et nøkkelord argument, kan det aldri prøve på å bruke via dekoratør selv, siden det bare avtaler med ikke-søkeord argumenter:

def __init__(self,**kwargs):
     self.__num=kwargs["num"]

...

@Printer(num=1)
def a():
    print 3
Svarte 21/08/2009 kl. 16:30
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more