如果我有
class A:
def foo(self):
pass
这评估为True
:
getattr(A, 'foo') is A.foo
但评估结果为False
:
a = A()
getattr(a, 'foo') is a.foo
和
一样a.foo is a.foo
为什么?
我发现getattr(a, 'foo')
和a.foo
都由
<bound method A.foo of <__main__.A object at 0x7a2c4de10d50>>)
所以没有提示......
答案 0 :(得分:3)
至少在CPython中,绑定方法是作为类method
的实例实现的。每次询问绑定函数的值时,都会得到此类的 new 实例。
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'>
所有这个类都存储对实例和未绑定函数的引用,当您调用该类时,它会使用存储的实例(以及其他参数)调用未绑定函数。 / p>
未绑定的函数(如A.foo
)只是常规的旧函数 - 没有构造新的代理类实例,因此身份可以按预期工作。
这种差异的原因是a.foo
的语义含义取决于两个事物,a
的值和A.foo
的值。为了能够在以后的任何时间点获得此含义,需要存储这两个值。这就是method
类的作用。
相反,A.foo
的含义仅取决于单个值:A.foo
。因此,不需要额外的工作来存储任何东西,并且使用值本身。
您可能会考虑预先分配绑定方法实例的想法,以便a.foo
始终返回相同的不可变对象 - 但考虑到Python的动态特性,每个构造一个新的更简单,更便宜时间,即使它们可能是相同的。
答案 1 :(得分:3)
答案 2 :(得分:2)
存储在类中的某些对象是descriptors,它们不遵循对象查找的常规规则。您在示例中处理的CaseUtils.toCamelCase("camel_case", false, new char[]{'_'}); // returns "camelCase"
方法是一个(函数对象是描述符)。
描述符是定义foo
(以及可选的__get__
和__set__
)方法的类的实例。这些方法控制当你在存储的类的实例上查找desciptor时会发生什么。
我认为一个例子可以说明这一点:
__delete__
class DescriptorClass:
def __get__(*args):
print("__get__ was called")
return "whatever"
class OtherClass:
descriptor_instance = DescriptorClass() # the descriptor instance is a class variable
other_instance = OtherClass()
# this calls the descriptor's __get__ method, which prints "__get__ was called"
result = other_instance.descriptor_instance
print(result) # will print "whatever", since that's what the __get__ method returned
方法每次调用时都不需要返回相同的内容。事实上,它通常不会。在函数被用作描述符(即方法)的特定情况下,每次查看函数时都会创建一个新的“绑定方法”对象。因此,__get__
运算符不会将多个绑定方法看作同一个对象,即使它们可能将同一个函数绑定到同一个实例。