使用wrapt包更改了类型

时间:2015-07-31 19:09:14

标签: python-3.x variable-assignment static-members

<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。 怎么会发生这种情况?

2 个答案:

答案 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:

  1. The same module is also existent in Python 2.
  2. I see no check in the code of wrapt.wrappers that creates different behavior form 2 to 3 for this special case.

Explanation

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

  1. 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).

  2. 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了解更多详情,但基本上,正如您所提到FunctionWrapperdescriptor(有__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只返回该函数。然而,可能有某种原因,人们可能希望在课堂上访问它们时仍然装饰东西。做这样的事情的一个例子是创建一个混合属性,该属性具有一个名称,但对于该类的实例而言,该类具有不同的行为。