2015-09-14 14 views
5

Próbowałem znaleźć odpowiedź tutaj, ale nie mogłem.Python decorator @func(). Błąd składni atrybutu

@obj.funC# works 
@obj.func(**kwargs) #works 
@obj.func1(**kwargs).func2 #-> syntax error 

Nie rozumiem dlaczego trzecia forma jest SyntaxError, wydaje się dla mnie nie naruszają jakiekolwiek składni Pythona i to jest dla mnie jasne, co użytkownik chce zrobić (patrz przykład poniżej).

Spojrzałem na pep 0318 realizacji dekoratora, ale nie znalazłem żadnych odpowiedzi.

Tutaj ryczeć, byłoby przykładem użycia:

class ItemFunc(object): 
    def __init__(self, fcall=None, **kwargs): 
     self.defaults = kwargs 
     self.fcall = None 

    def __call__(self, *args, **kwargs): 
     kwargs = dict(self.defaults, **kwargs) 
     # do something more complex with kwargs 
     output = self.fcall(*args, **kwargs) 
     # do something more with output 
     return output 

    def caller(self, fcall): 
     """ set call and return self """ 
     self.call = fcall # after some check obviously 
     return self 

    def copy(self,**kwargs): 
     kwargs = dict(self.defaults, **kwargs) 
     return self.__class__(self.fcall, **kwargs) 

    def copy_and_decorate(self, **kwargs): 
     return self.copy(**kwargs).caller 

niż można użyć ItemFunc jako dekorator:

@ItemFunc 
def plot(**kwargs): 
    pass 

redcross = plot.copy(color="red", marker="+") 
@redcross.caller 
def plot_data1(**kwargs): 
    pass 

bluecross = redcross.copy(color="blue") 
@bluecross.caller 
def plot_data2(**kwargs): 
    pass 

ale dlaczego to po 'krótki składnia cut' jest zabronione:

@redcross.copy(color="blue").caller 
def plot_data2(**kwargs): 
    pass 

Ale mogę zrobić:

@redcross.copy_and_decorate(color="blue") 
def plot_data2(**kwargs): 
    pass   

Pierwsza forma wygląda ładniej, przynajmniej lepiej rozumiem intencje z tyłu.

Odpowiedz

6
Urządzenie Function definitions grammar nie zezwala na połączenia z kolejnymi nazwami z kropkami; składnia jest ograniczone do przerywanych nazw i opcjonalnego połączenia na koniec:

decorated  ::= decorators (classdef | funcdef) 
decorators  ::= decorator+ 
decorator  ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE 
funcdef  ::= "def" funcname "(" [parameter_list] ")" ":" suite 
dotted_name ::= identifier ("." identifier)* 

Zauważ, że to nie pełne ekspresji, ale bardzo ograniczony podzbiór.

To echa PEP, który stanowi:

Oświadczenie dekorator jest ograniczona, co może przyjąć - dowolne wyrażenia nie będzie działać. Guido preferował to ze względu na uczucie jelit [17].

i

Uzasadnieniem posiadające funkcję, która zwraca dekorator jest to, że część po znaku @ może być uznana za wyraz (choć składniowo ograniczony do zaledwie funkcja), i cokolwiek to wyrażenie zwraca. Zobacz argumenty deklaracji [16].

Podkreślam moją.

Uzasadnieniem jest to, że Guido feels there isn't a real use case for allowing more:

Tak więc byłoby dość łatwo zmienić składnię @test w przyszłości , chciałbym pozostać przy bardziej ograniczonej formie, chyba że prawdziwym przedstawiono przypadek użycia, w którym pozwolenie @test zwiększyłoby czytelność. (@foo(). Bar() nie liczy się, ponieważ nie oczekuję, że kiedykolwiek będziesz potrzebował ).

Będziesz musiał przekonać Guido i innych deweloperów, że Twój przypadek jest właściwym miejscem, godnym zniesienia tych ograniczeń!

+0

Tak, to bardziej problem filozoficzny. Dla mnie wykończenie dekoratora czymś takim jak .getter lub .caller (jak w moim przykładzie) wyjaśnia, co chcemy zrobić, podczas wywoływania funkcji, która na końcu wysyła metodę .caller (mój przykład ponownie) jest dozwolone, ale mniej czytelny. nie sądzisz? – user3240484

+0

@ user3240484: Widzę, dokąd zmierzasz; ale być może zamiast używać atrybutu, ''_call__' zwróci rzeczywisty dekorator, co również obsługuje' __call__'? –

+0

Masz rację, ale jeśli spojrzysz na mój przykład, metoda __call__ już działa jak dekorator funkcji fcall, aby zachować funkcję podobną do funkcji dla użytkowników. Mógłbym zastąpić __call__ przez funkcję połączenia i użyć __call__, aby zwrócić dekoratora, ale to, co tam zyskuję, tracę tam. dzięki – user3240484

Powiązane problemy