考虑以下代码:'is'运算符为什么说这些方法不一样?
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
我希望它表现出真正的。它为什么显示错误?
考虑以下代码:'is'运算符为什么说这些方法不一样?
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
我希望它表现出真正的。它为什么显示错误?
方法对在运行势必实例。当您运行以下代码时:
print(Person().sayHello is Person().sayHello)
您创建两个实例并且每次有不同的内存地址时。
>>> Person().sayHello
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640410>>
>>> Person().sayHello
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640490>>
注意:我们所有的Python都是运行时;有没有这样的事情作为一个单独的编译时间。
[如果你有一个实例,你会*仍然*得到'False',因为你在每次访问时都会得到一个新的方法对象。](http://stackoverflow.com/questions/15977808/why-dont-methods -have-reference-equality) – user2357112 2014-11-22 01:35:44
@ user2357112是的,当然。 – Kasramvd 2014-11-22 06:08:52
*在python *中是单独的编译时间。例如,名称范围在编译时确定。各种文字变成常数,并在编译时应用窥视孔优化。这里不适用,但不要求它不存在。 – 2014-11-25 08:04:23
这将是True
如果你叫sayHello
:
print(Person().sayHello() is Person().sayHello())
在你的代码实际上是比较上的对象的方法,并检查它们是否具有相同的身份(他们没有)。另外要注意的区别:
"Hello" is "Hello"
和
"Hello" == "Hello"
在第一个,你要比较的对象的身份(这是由于相同的字符串被重用,调用id("Hello")
多次看到这一点)。第二,你比较字符串的内容以查看它们是否相等(即,具有相同的字符)。现在,相同的字符串也会有相同的标识,但我不确定这个假设是否适用于所有Python实现。
它是一样的“你好”是“你好”,我相信他想比较功能而不是结果 – Andres 2014-11-21 20:13:29
@Test:在我的机器上是'False'...? – 2014-11-21 20:13:45
@SimeonVisser Python的一些实现会记忆短字符串 – 2014-11-21 20:14:57
的是运算符表示两个变量指向同一个对象,而不是具有相同值的。请参阅堆栈溢出问题Understanding Python's “is” operator。
这并不能解释为什么实例方法比较不等。 – davidism 2014-11-21 20:19:59
我会假设你是有意比较方法对象本身,而不是那你真的想比较输出字符串,只是忘了()
sayHello
后。
试试这个实验:
a = Person()
b = Person()
a.sayHello
b.sayHello
你会看到a.sayHello
显示为类似
<bound method Person.sayHello of <__main__.Person instance at 0x102cc8ef0>>
...而b.sayHello
显示器类似,但具有不同的父实例指针:
<bound method Person.sayHello of <__main__.Person instance at 0x102d31908>>
的0一个实例的结合方法本身是一个不同实例(方法)从同一个名字的从不同的Person
实例绑定的方法。你可以用id(a.sayHello)
和id(b.sayHello)
来确认,它返回两个绑定方法的标识哈希 - 它们将会不同。由于您的代码Person().sayHello is Person().sayHello
创建了两个不同的Person
实例,因此情况与我的命名实例示例a
和b
相同。
没有关系,有不同的情况。即使只有一个实例,如果您访问该方法两次,您也会得到两个不同的方法对象。 – 2014-11-25 07:54:50
好点。 'a.sayHello'中隐含的'getattr'操作是每次你创建一个新的绑定方法实例。对于我来说,这被一个事实掩盖了(可能取决于平台/实现),如果你说'id(a.sayHello)'两次,你会得到相同的id号码两次。但是如果你不让第一个方法实例超出范围,你会得到*不同的* id号。所以'as1 = a.sayHello; as2 = a.sayHello; print([id(as1),id(as2)])'给了我不同的数字,而'print([id(a.sayHello),id(a.sayHello)])'给了我相同的数字。 – jez 2014-11-25 19:02:28
如果对象已被删除,'id()'值可以重用。总是先创建一个对象,然后再测试。 – 2014-11-25 19:25:47
它们是同一类的两个不同实例。 sayHello
函数是绑定方法。
也就是说,如果你有一个类的实例:
p = Person()
,你就可以查找一个属性:
p.sayHello
那么Python首先着眼于实例的实际属性,如果它没有找到那里的属性,它看着这个类。 如果它找到该名称的类方法,它会将其变成绑定方法,绑定到此实例。这是导致对象实例作为第一个参数(self
)传递到sayHello
的魔法。
因此Person().sayHello is Person().sayHello
创建两个实例,根据类上定义的相同方法创建两个不同的绑定方法,因此is
返回False
,因为它们是不同的方法。
即使在相同的实例中,每次访问它们时都会重新创建方法。无所谓这里有两个传出实例。 – 2014-11-25 07:53:39
如果你想它返回一个表达式True
你可以试试这个:
print(Person.sayHello is Person.sayHello)
只是为了增加混乱,执行:
>>> say = Person.sayHello
>>> say()
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
say()
TypeError: sayHello() missing 1 required positional argument: 'self'
,甚至:
>>> say(say)
'Hello'
>>> say(None)
'Hello'
>>>
这是因为:
>>> say
<function Person.sayHello at 0x02AF04B0>
say
指的是Person.sayHello
这是一个函数,可以调用,但需要一个参数,但在这种情况下参数是不相关的。现在
,如果你不想让供应无用的参数,你可以有一个自动绑定:
>>> p=Person()
>>> p.sayHello()
'Hello'
是的,但有很多表达式可以打印True,就像'print(True)'。 OP的问题是为什么方法似乎有身份危机。 – tdelaney 2014-11-21 21:15:03
在Python 2中,返回未绑定方法的情况下仍会失败。 – 2014-11-25 07:56:42
看到这个问题http://stackoverflow.com/a/133024/1394473 – tom 2014-11-21 20:15:32
@汤姆,虽然这并不能真正解释比较实例方法 – davidism 2014-11-21 20:18:29
@Test你为什么期望你的表达式为真?你必须期待这两个子表达式是同一个对象。是什么导致你这个断言? – quamrana 2014-11-21 21:20:29