5

给定一个类,我可以简单地通过A添加一个实例方法a

def a(self):
    pass

A.a = a

但是,如果我尝试添加另一个 classB的 instancemethod b,即A.b = B.b尝试调用会A().b()产生

TypeErrorb()必须以B实例作为第一个参数调用未绑定的方法(什么都没有)

(虽然B().b()很好)。确实有区别

A.a -> <unbound method A.a>
A.b -> <unbound method B.b>  # should be A.b, not B.b

所以,

  • 如何解决这个问题?
  • 为什么会这样?这似乎并不直观,但通常 Guido 有一些很好的理由......

奇怪的是,这在 Python3 中不再失败......

4

2 回答 2

6

让我们:

class A(object): pass

class B(object):
    def b(self): 
        print 'self class: ' + self.__class__.__name__

当你在做:

A.b = B.b

您不是将一个函数附加到 A,而是一个未绑定的方法。因此,python 仅将其添加为标准属性,而不会将其转换为 A-unbounded 方法。解决方法很简单,附上底层函数:

A.b = B.b.__func__

print A.b
    # print: <unbound method A.b>
a = A()
a.b()
    # print: self class: A

我不知道未绑定方法和函数之间的所有区别(仅第一个包含第二个),也不知道所有这些在内部如何工作。所以我无法解释它的原因。我的理解是,一个方法对象(绑定与否)比函数需要更多的信息和功能,但它需要一个来执行。

我同意自动执行此操作(更改未绑定方法的类)可能是一个不错的选择,但我可以找到不这样做的理由。因此,python 3 与 python 2 的不同令人惊讶。我想找出这种选择的原因。

于 2013-09-10T08:30:18.230 回答
2

当您引用类实例上的方法时,该方法将绑定到该类实例。

B().b相当于:lambda *args, **kwargs: b(<B instance>, *args, **kwargs)

我怀疑您在评估 Bb 时得到了类似(但不完全相同)的包装参考但是,这不是我所期望的行为。

有趣的是:

A.a = lambda s: B.b(s)
A().a()

产量:

类型错误:必须以 B 实例作为第一个参数调用未绑定的方法 b()(改为获取 A 实例)

这表明B.b正在评估实际方法的包装器,并且包装器正在检查“自我”是否具有预期的类型。我不知道,但这可能与翻译效率有关。

这是一个有趣的问题。希望有人能给出更明确的答案。

于 2013-09-10T07:55:18.167 回答