【发布时间】:2019-03-17 13:24:21
【问题描述】:
(我需要一位 Python 3 内部专家)
我有一个类装饰器,它可以修改某些函数,但不能修改其他函数。 简化示例:
import functools
import inspect
import types
def mydecorator(myobj):
@functools.wraps(myobj)
def decorated_method(*args, **kwargs):
print("I'm decorated!")
return myobj(*args, **kwargs)
if inspect.isclass(myobj): # act as class decorator
for name, obj in myobj.__dict__.items():
if name == "add":
setattr(myobj, name, types.MethodType(mydecorator(obj), myobj))
return myobj # return decorated class
elif inspect.isfunction(myobj): # act as function decorator
return decorated_method
else:
assert False, "can decorate only classes and functions"
因此,这将修改任何 add 方法以在运行之前打印“我已装饰”。
我们将把它应用到这个类中:
class MyClass:
def add(self, x, y): return x + y
def mul(self, x, y): return x * y
它工作正常。我们这样做
#--- try out undecorated MyClass:
print("MyClass.add:", MyClass.add, "MyClass.mul:", MyClass.mul)
print("3+4 =", MyClass().add(3, 4), "3*4 =", MyClass().mul(3, 4), )
#--- decorate MyClass:
print("MyClass = mydecorator(MyClass)")
MyClass = mydecorator(MyClass)
#--- try out decorated MyClass in the same manner:
print("MyClass.add:", MyClass.add, "MyClass.mul:", MyClass.mul)
print("3+4 =", MyClass().add(3, 4), "3*4 =", MyClass().mul(3, 4), )
并获取此输出(来自 Linux 上的 CPython 3.6.7)
MyClass.add: <function MyClass.add at 0x7faededda0d0> MyClass.mul: <function MyClass.mul at 0x7faededda158>
3+4 = 7 3*4 = 12
MyClass = mydecorator(MyClass)
MyClass.add: <bound method MyClass.add of <class '__main__.MyClass'>> MyClass.mul: <function MyClass.mul at 0x7faededda158>
I'm decorated!
3+4 = 7 3*4 = 12
所以mul 保持一个普通函数,而装饰的add 变成一个绑定方法。装饰工作正常。
但是当我现在更改方法时,add 调用mul(忽略这没有多大意义的事实)如下:
class MyClass:
def add(self, x, y): z = self.mul(x, y); return x + y
def mul(self, x, y): return x * y
输出变成这样:
MyClass.add: <function MyClass.add at 0x7fbc760870d0> MyClass.mul: <function MyClass.mul at 0x7fbc76087158>
3+4 = 7 3*4 = 12
MyClass = mydecorator(MyClass)
MyClass.add: <bound method MyClass.add of <class '__main__.MyClass'>> MyClass.mul: <function MyClass.mul at 0x7fbc76087158>
I'm decorated!
Traceback (most recent call last):
File "tryout.py", line 34, in <module>
print("3+4 =", MyClass().add(3, 4), "3*4 =", MyClass().mul(3, 4), )
File "tryout.py", line 16, in decorated_method
return myobj(*args, **kwargs)
File "tryout.py", line 7, in add
def add(self, x, y): z = self.mul(x, y); return x + y # round 2
TypeError: mul() missing 1 required positional argument: 'y'
原来mul(虽然它和以前一样!)现在被调用就好像它是@staticmethod:self 没有通过。
我有很多问题:
- 这种惊人的效果从何而来?
-
add绑定到什么对象? - Python 如何在内部区分普通方法和
@classmethod或@staticmethod? -
types.MethodType的真正含义是什么? - 我会写什么来分别获得普通方法、类方法或静态方法?
- 我在哪里可以找到所有这些的文档?
- 哪些答案与 Python 属性有关,而不是 CPython 实现细节?
【问题讨论】:
标签: python python-3.x decorator