此
<class 'assign.A'>
<class 'BoundFunctionWrapper'>
由以下代码打印:
from wrapt import FunctionWrapper
class A(FunctionWrapper):
A = None
def __init__(self, f):
super(A, self).__init__(f, self.wrapper)
def wrapper(self, wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
@A
def f():
pass
print(type(f))
A.A = f
print(type(A.A))
如果将f
分配给类的静态变量,则类型会仅更改 。我原以为该类型会保持A
。
怎么会发生这种情况?
答案 0 :(得分:1)
I checked that and this would be the default behavior in Python 2 and not in Python 3:
>>> class X(object): # Python 2
def g():pass
>>> X.g
<unbound method X.g>
Reasons for the behavior of wrapt:
wrapt.wrappers
that creates different behavior form 2 to 3 for this special case.The __get__
behavior changed.
Python 2:
>>> class X(object):
def g():pass
>>> X.g
<unbound method X.g>
>>> class B: # error: Must inherit form object (see comments)
def __get__(self, *args):
print(args)
>>> X.b = B()
>>> X.b
<__main__.B instance at 0x029C0440>
Python 3:
>>> class X(object):
def g():pass
>>> X.g
<function g at 0x030430C0>
>>> class B:
def __get__(self, *args):
print(args)
>>> X.b = B()
>>> X.b
(None, <class 'X'>)
Recommendation
I would say that this may be a bug. According to pypi
, wrapt
longs for correctness. So, this should be discussed, I guess. Please open an issue on github and link this question (Tell me if I should do it).
Use the attribute __bound_function_wrapper__
to create an own wrapper for bound methods. Code that shows context in wrapt.wrappers
:
class FunctionWrapper(_FunctionWrapperBase):
__bound_function_wrapper__ = BoundFunctionWrapper
So, if you really want to create an own wrapper class you can do that:
class OwnBoundWrapper(wrapt.BoundFunctionWrapper):
# additional code here
A.__bound_function_wrapper__ = OwnBoundWrapper
答案 1 :(得分:1)
我猜这是(大多数)预期的行为。
您可以阅读this了解更多详情,但基本上,正如您所提到FunctionWrapper
是descriptor(有__get__
方法)的原因是什么原因造成的你观察到的行为。
当您执行类似
之类的操作时,描述符协议用于返回方法而不是仅返回裸函数some_var = instance.method
当从类中检索实例方法时,python 2和3确实有不同的行为:
python3:
In [1]: class Test:
...: def a(self):
...: pass
...:
In [2]: Test.a
Out[2]: <function __main__.Test.a>
python2:
In [1]: class Test:
...: def a(self):
...: pass
...:
In [2]: Test.a
Out[2]: <function __main__.Test.a>
python2返回一个unbound方法,python3只返回该函数。然而,可能有某种原因,人们可能希望在课堂上访问它们时仍然装饰东西。做这样的事情的一个例子是创建一个混合属性,该属性具有一个名称,但对于该类的实例而言,该类具有不同的行为。