python - 为什么 `instance_of_object.foo is instance_of_object.foo` 评估为 False?
问题描述
如果我有一个
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>>)
所以没有提示......
解决方案
至少在 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'>
这个类所做的只是存储对实例和未绑定函数的引用,当您调用该类时,它会使用存储的实例(以及您的其他参数)调用未绑定函数。
未绑定的函数,例如A.foo
,只是常规的旧函数 - 没有构造代理类的新实例,因此身份按您的预期工作。
造成这种差异的原因是, 的语义a.foo
取决于两件事, 的值a
和 的值A.foo
。为了能够在以后的任何时间点得到这个含义,这两个值都需要存储。这就是method
班级所做的。
相反, 的含义A.foo
仅取决于单个值:A.foo
. 所以不需要额外的工作来存储任何东西,并且使用值本身。
您可能会考虑预分配绑定方法实例的想法,以便a.foo
始终返回相同的不可变对象 - 但鉴于 Python 的动态特性,每次只构造一个新对象更简单、更便宜,即使它们可能是相同的。
推荐阅读
- regex - 在 sed 和 perl 中替换单引号
- azure - 在处理应用程序网关后面的 Azure Web 应用程序时配置 SSL 证书卸载
- tensorflow - 运行 tensorflow-gpu 设备时几乎没有可用的 1080 ti 内存分配
- matlab - Matlab如何切换多维图像尺寸
- c++ - 在 linux 中,如何在 bash 或 c 或 c++ 中观察窗口创建事件
- python - csv.DictReader 错误“_csv.Error:行包含 NULL 字节”
- vb.net - VB.NET 多线程
- mysql - 如何使用来自另一个数据库的数据来选择数据?
- powershell - 用于设置 ms 访问的属性 PriorityClass 的 powershell 脚本
- batch-file - 如何使用命令提示符添加一行文本并保存?