簡體   English   中英

用另一個類裝飾一個python類方法

[英]decorate a python class method with another class

我目前正在研究一個 Python 類,用作類方法的裝飾器。 在這種情況下,我遇到了一個我難以理解的問題。 讓我們以下面的例子為例:

from functools import partial

class Decorator:
    def __init__(self, func = None, *args):
        self.uses_init = func is None
        self.func = func
        self.instance = None
        self.args = args
    
    def __call__(self, *args, **kwargs):
        self.func = args[0]
        
        def wrapper(cls, *args, **kwargs):
            print('before')
            parsed_func = self.func(cls, *args, **kwargs)
            print('after')
            return parsed_func
        
        return wrapper
    
    def call(self, cls, *args, **kwargs):
        print('before')
        parsed_func = self.func(cls, *args, **kwargs)
        print('after')
        return parsed_func       

    def __get__(self, instance, owner):
        # This is only used when uses_init == False
        return partial(self.call, instance)

可以不帶參數@Decorator或帶參數@Decorator(*args)

使用此代碼按預期工作:

class HelloWorld:
    @Decorator()
    def print(self, name):
        print(name)
hello_world = HelloWorld()
hello_world.print("Max Musterman")
print('----------------------')
class HelloWorld:
    @Decorator
    def print(self, name):
        print(name)
hello_world = HelloWorld()
hello_world.print("Max Musterman")

我想使用self.call方法self.call wrapper來避免重復代碼。 當我嘗試這個時:

class Decorator:
    def __init__(self, func = None, *args):
        self.uses_init = func is None
        self.func = func
        self.instance = None
        self.args = args
    
    def __call__(self, *args, **kwargs):
        self.func = args[0]        
        return self.call
    
    def call(self, cls, *args, **kwargs):
        print('before')
        parsed_func = self.func(cls, *args, **kwargs)
        print('after')
        return parsed_func       

    def __get__(self, instance, owner):
        # This is only used when uses_init == False
        return partial(self.call, instance)

我遇到了TypeError: print() missing 1 required positional argument: 'name'盡管檢查了方法的簽名inspect.signature(Decorator().call)inspect.signature(Decorator()(lambda: None))給出了相同的結果。

裝飾器無法獲取參數。

>>> class MyClass:
...     def __init__(self, func, *args):
...         print(args)
...
>>> @MyClass
... def my_func():
...     pass
... 
()
>>> @MyClass('args1', 'args2', 'args3')
... def my_func():
...     pass
... 
('args2', 'args3')
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: MyClass object is not callable
>>>

您可以使用函數或方法來制作裝飾器。
在它之前“如何解決TypeError: MyClass object is not callable ?”:

>>> def my_decorator(*args **kwargs):
...     def func_getter(func):
...         return func(*args, **kwargs)
...     return func_getter  # mine decorator
... 
>>> @my_decorator('arg1', 'arg2', 'arg3', kwarg1=1, kwarg2=2) # -> func_getter
... def print_row(*args, **kwargs):
...     print(args, kwargs)
... 
('arg1', 'arg2', 'arg3') {'kwarg1': 1, 'kwarg2': 2}

解決方案 1:使用函數制作裝飾器:

>>> class MyClass:
...     def __init__(self, func = None, *args): # copied form your code
...         ... # your code here
... 
>>> def decorator(*args):
...     def func_getter(func):
...         return MyClass(func, *args)
...     return func_getter
... 
>>> @decorator
... def test(): ...
... 
>>> test
<MyClass object at 0x0000000000000000>

解決方案一:使用方法制作裝飾器:

>>> class MyClass:
...     def __init__(self, func = None, *args): # copied form your code
...         ... # your code here
...     @classmethod # romove this line in python3.10
...     def create(cls, *args):
...         def func_getter(func):
...             return cls(func, *args) # "cls" is "MyClass" instance
... 
>>> @MyClass.create('args1', 'arg2', ...)
... def test(): ...
... 
>>> test
<MyClass object at 0x0000000000000000>

感謝@Delta 的回答,我能夠編寫一個裝飾器(-maker)來滿足我的需求

class Decorator:
    def __init__(self, func = None, text_before = "start", text_after = "end"):
        self.func = func
        self.text_before = text_before
        self.text_after = text_after
    
    def __call__(self, func):
        return self.create(func, text_before=self.text_before, text_after=self.text_after)
    
    @classmethod
    def create(cls, func, *args, **kwargs):
        return cls(func, *args, **kwargs)
    
    def call(self, cls, *args, **kwargs):
        print(f'--- {self.text_before} ---')
        parsed_func = self.func(cls, *args, **kwargs)
        print(f'--- {self.text_after} ---')
        return parsed_func       

    def __get__(self, instance, owner):
        return partial(self.call, instance)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM