python - 用另一个类装饰一个python类方法
问题描述
我目前正在研究一个 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
方法代替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}
解决方案一:使用函数制作装饰器:
>>> 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>
推荐阅读
- algorithm - 为什么二进制搜索算法中的赋值不会增加时间复杂度?
- javascript - 为 django_admin 的移动视图使用不同的 css 和删除项目
- jquery - 如何从 Jquery 中的 ajax 调用中触发函数?
- php - 从 github 下载 Laravel 项目
- javascript - 如何在 Laravel 中导入 Progressbar.js?
- oracle - 我在 Oracle 的 DBA 面板中看不到表、视图或索引
- authentication - kubernetes 用户在 kubeconfig 和 basic-auth-file 中的区别?
- mysql - 如何将 mysql 结果行存储为包含表格格式字符串的变量?
- c - 目录条目和链表
- python - 这个程序有什么错误?