2015-09-14 19 views
5

Tôi đã cố gắng tìm câu trả lời ở đây, nhưng không thể.Python decorator @func(). Lỗi cú pháp thuộc tính

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

Tôi không hiểu tại sao các hình thức thứ ba là một Lỗi Cú pháp, có vẻ như đối với tôi đó là không vi phạm bất kỳ cú pháp python và nó là rõ ràng cho tôi những gì người dùng muốn làm (xem ví dụ dưới đây).

Tôi đã xem pep 0318 việc triển khai trang trí nhưng không tìm thấy bất kỳ câu trả lời nào.

đây rống lên, sẽ là một ví dụ về sử dụng:

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 

hơn bạn có thể sử dụng ItemFunc như một trang trí:

@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 

Nhưng tại sao điều này sau 'cú pháp cắt ngắn' bị cấm:

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

Nhưng tôi có thể làm:

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

Biểu mẫu đầu tiên trông đẹp hơn, ít nhất tôi hiểu rõ hơn ý định đằng sau.

Trả lời

6

Function definitions grammar không cho phép thực hiện cuộc gọi có tên rải rác; cú pháp được giới hạn tên rải rác và cuộc gọi không bắt buộc vào cuối:

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

Lưu ý rằng đó là không một biểu hiện đầy đủ, nhưng một tập hợp con rất hạn chế.

Đây là sự lặp PEP, trong đó nêu:

Tuyên bố trang trí được giới hạn ở những gì nó có thể chấp nhận - biểu thức tùy ý sẽ không làm việc. Guido ưa thích điều này vì cảm giác ruột [17].

Lý do vì có một hàm trả về một trang trí là các phần sau dấu @ có thể được coi là một biểu (mặc dù cú pháp hạn chế để chỉ là một chức năng), và bất kỳ biểu thức nào trả về được gọi. Xem các đối số khai báo [16].

Mỏ nhấn mạnh.

Lý do là Guido feels there isn't a real use case for allowing more:

Vì vậy, trong khi nó sẽ là khá dễ dàng để thay đổi cú pháp để @test trong tương lai , tôi muốn gắn bó với các hình thức hạn chế hơn, trừ khi một thực trường hợp sử dụng được trình bày khi cho phép @test tăng khả năng đọc. (@foo(). Bar() không tính vì tôi không mong đợi bạn sẽ cần điều đó).

Bạn sẽ phải thuyết phục Guido và các nhà phát triển cốt lõi khác rằng trường hợp của bạn là một ứng dụng phù hợp đáng để nâng những hạn chế này!

+0

Đúng, đó là một vấn đề triết học. Đối với tôi hoàn thành trang trí với một cái gì đó như .getter hoặc .caller (như trong ví dụ của tôi) làm cho nó rõ ràng những gì chúng ta muốn làm, trong khi gọi một hàm mà ở cuối gửi một method .caller (ví dụ của tôi một lần nữa) được cho phép nhưng ít có thể đọc được. bạn không nghĩ sao? – user3240484

+0

@ user3240484: Tôi có thể biết bạn đang đi đâu với thiết lập của mình; nhưng có lẽ thay vì sử dụng một thuộc tính, có '__call__' trả về trang trí thực sự, cái gì đó cũng hỗ trợ' __call__'? –

+0

Bạn nói đúng, nhưng nếu bạn nhìn vào ví dụ của tôi, phương thức __call__ đã hoạt động như trang trí của chức năng 'fcall', để giữ cho đối tượng giống như chức năng cho người dùng. Tôi có thể thay thế __call__ bằng một chức năng gọi và sử dụng __call__ để trả lại trang trí, nhưng những gì tôi đạt được ở đó tôi mất nó ở đó. cảm ơn – user3240484

Các vấn đề liên quan