为什么`instance_of_object.foo是instance_of_object.foo`评估为False?

ste*_*fen 5 python introspection

如果我有

class A:
  def foo(self):
    pass
Run Code Online (Sandbox Code Playgroud)

这评估为True:

getattr(A, 'foo') is A.foo
Run Code Online (Sandbox Code Playgroud)

但这评估为False:

a = A()
getattr(a, 'foo') is a.foo
Run Code Online (Sandbox Code Playgroud)

同样如此

a.foo is a.foo
Run Code Online (Sandbox Code Playgroud)

为什么?

我找到了getattr(a, 'foo'),a.foo两者都代表了

<bound method A.foo of <__main__.A object at 0x7a2c4de10d50>>)
Run Code Online (Sandbox Code Playgroud)

所以没有暗示....

GMa*_*ckG 3

至少在 CPython 中,绑定方法是作为类的实例实现的method。每次您询问绑定函数的值时,您都会获得此类的一个实例。

x = a.foo
y = a.foo

assert x is not y
id(x)  # E.g. 139664144271304
id(y)  # E.g. 139664144033992
type(x)  # <class 'method'>
type(y)  # <class 'method'>
Run Code Online (Sandbox Code Playgroud)

这个类所做的只是存储对实例和未绑定函数的引用,当您调用该类时,它会使用存储的实例(以及其他参数)调用未绑定函数。

未绑定函数,例如A.foo,只是常规的旧函数 - 没有构建代理类的新实例,因此身份按您的预期工作。

造成这种差异的原因是 的语义a.foo取决于件事, 的值a和 的值A.foo。为了能够在以后的任何时间点获得这个含义,这两个值都需要存储。这就是method班级所做的。

相反, 的含义A.foo仅取决于单个值:A.foo。因此不需要额外的工作来存储任何内容,并且使用值本身。

您可能会考虑预分配绑定方法实例的想法,以便a.foo始终返回相同的不可变对象 - 但考虑到 Python 的动态性质,每次构造一个新对象会更简单、更便宜,即使它们可能是相同的。

  • 是的,“A.foo”是一个函数,就像任何非类函数一样(例如,比较类型)。行为上的差异在于,“a.foo”抽象地表示“用“a”调用的函数“A.foo”,就像它们在调用时一样”。为了稍后实际进行此调用,您还必须存储它们两个的值以供稍后使用,而“method”就是此存储。简单地引用 `A.foo` 不需要额外的存储,因为您已经有了对相关唯一值的引用,所以常规的 Python 引用语义就足够了。 (2认同)