为什么一个方法与其自身不相同?
运算符
is
和is not
测试 对象标识:x is y
为 true,如果且 仅当x
和y
是同一对象时。x 不是 y
产生相反的事实 值。
让我们尝试一下:
>>> def m():
... pass
...
>>> m is m
True
由于自动垃圾收集, 空闲列表和动态特性 描述符,你可能会注意到 某些用途中的异常行为
is
运算符,例如涉及 实例方法之间的比较, 或常数。检查他们的 文档以获取更多信息。
>>> class C:
... def m():
... pass
...
>>> C.m is C.m
False
我搜索了更多解释,但找不到任何解释。
为什么Cm is Cm
是假的?
我正在使用 Python 2.x。正如下面的答案中所指出的,在 Python 3.x 中 Cm is Cm
是正确的。
The Python documentation about the is
operator says:
The operators
is
andis not
test for
object identity:x is y
is true if and
only ifx
andy
are the same object.x is not y
yields the inverse truth
value.
Let's try that:
>>> def m():
... pass
...
>>> m is m
True
The Python documentation also says:
Due to automatic garbage-collection,
free lists, and the dynamic nature of
descriptors, you may notice seemingly
unusual behaviour in certain uses of
theis
operator, like those involving
comparisons between instance methods,
or constants. Check their
documentation for more info.
>>> class C:
... def m():
... pass
...
>>> C.m is C.m
False
I searched for more explanations, but I was not able to find any.
Why is C.m is C.m
false?
I am using Python 2.x. As noted in the answers below, in Python 3.x C.m is C.m
is true.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您请求一个作为函数的实例属性时,您会得到一个绑定方法:一个可调用对象,它包装类中定义的函数并将实例作为第一个参数传递。在 Python 2.x 中,当您请求一个作为函数的类属性时,您会得到一个类似的代理对象,称为未绑定方法:
这个特殊对象是在您请求时创建的,并且显然不是缓存在任何地方。这意味着当您这样做时,
您将创建两个不同的未绑定方法对象并测试它们的身份。
请注意,这些工作正常:
并且
(
im_func
是未绑定方法对象所包装的原始函数。)顺便说一句,在 Python 3.x 中,
Cm is Cm
为 True,因为(有点无意义的)未绑定方法代理对象被完全删除,您只得到您定义的原始函数。这只是 Python 中属性查找的动态特性的一个示例:当您请求对象的属性时,可以运行任意代码来计算该属性的值。这是您的测试失败的另一个示例,其中原因更清楚:
When you ask for an instance attribute which is a function, you get a bound method: a callable object which wraps the function defined in the class and passes the instance as the first argument. In Python 2.x, when you ask for a class attribute which is a function, you get a similar proxy object called an unbound method:
This special object is created when you ask for it, and not apparently cached anywhere. That means that when you do
you are creating two distinct unbound method objects and testing them for identity.
Notice that these work fine:
and
(
im_func
is the original function which the unbound method object is wrapping.)In Python 3.x, incidentally,
C.m is C.m
is True, because the (somewhat pointless) unbound method proxy objects were removed entirely and you just get the original function which you defined.This is just one example of the very dynamic nature of attribute lookup in Python: when you ask for an attribute of an object, it is possible to run arbitrary code to calculate the value of that attribute. Here's another example where your test fails in which it is much clearer why:
我假设你使用的是Python 2?在 Python 3 中,
Cm is Cm
(但C().m is C().m
仍然为 false)。如果您在 REPL 中仅输入Cm
,我敢打赌您会看到类似于
的内容。 UnboundMethod 包装器除了检查 isinstance(self, cls) 之外几乎不做任何事情。 (为此创建一个包装器似乎毫无意义?确实如此,所以它在 Python 3 中被删除 -Cm
只是一个函数)。每当访问该方法时,就会按需创建一个新的包装器实例 -Cm
创建一个,另一个Cm
创建另一个。由于它们是不同的实例,Cm 不是 Cm
。密切相关的是绑定方法,它允许您执行 f = obj.method; f(*args) 但也会导致
instance.method 不是 instance.method
。实例化后,类中定义的所有函数(即:所有方法,当然除了猴子补丁的方法)都成为实例的属性。当您访问它们时,您会获得一个围绕普通函数的包装器(绑定方法)的新实例。该包装器会记住实例 (self
),并且当使用(arg1, arg2, ..., argN)
调用时,只需将它们传递给函数 - 使用self
添加为第一个参数。您通常不会注意到,因为您立即调用该方法 - 但这就是允许隐式传递self
的原因,而无需诉诸语言级技巧。有关更多详细信息,请参阅 Python 的历史 , 历史。
I assume you are using Python 2? In Python 3,
C.m is C.m
(butC().m is C().m
is still false). If you enter justC.m
at the REPL, I bet you see something like<UnboundMethod... >
. An UnboundMethod wrapper does very little, except checkingisinstance(self, cls)
. (Seems pretty pointless to create a wrapper for this? It is, so it was dropped in Python 3 -C.m
is just a function). A fresh wrapper instance is created on-demand whenever the method is accessed -C.m
creates one, anotherC.m
creates another one. Since they're different instances,C.m is not C.m
.Closely related are the bound methods, which allow you to do
f = obj.method; f(*args)
but also causeinstance.method is not instance.method
. Upon instanciation, all functions defined in the class (read: all methods, except of course monkeypatched ones) become properties of the instance. When you access them, you instead get a fresh instance of a wrapper (the bound method) around the plain function. This wrapper remembers the instance (self
) and when called with(arg1, arg2, ..., argN)
just hands these on to the function - withself
added as first argument. You usually don't notice because you call the method right away - but this is what allows passingself
implicitly without resorting to language-level trickery.See the history of Python for more details and, well, history.
因为 Cm() 不是类 C 的静态方法:
请像这样尝试:
因为静态方法就像类变量,所以我们只需要它们的一个引用,这样,如果我们更改它们的绑定值,则此更改应该在所有 C 类中自动进行。类和该类的实例。
另一方面,在您的示例中,
Cm
不是静态方法,因此 Python 假设它应该被视为非静态方法,因此每当您调用Cm
>,它将返回一个新实例:注意:静态方法不像类方法!
Because C.m() is not a static method of the class C:
Try it like this:
Because static methods are like class variables, we only want one reference for them so that if we change their bound value this change should be automatic in all the class and instance of this class.
On the other hand, in your example,
C.m
is not a static method so Python makes the assumption that it should be treated like a non-static method, so whenever you callC.m
, it will return a new instance:N.B: static methods are not like class methods!