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.
Đú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
@ 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__'? –
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