我希望能够测试两个可调用对象是否相同.我更喜欢身份语义(使用"是"运算符),但我发现当涉及方法时,会发生不同的事情.
#(1) identity and equality with a method
class Foo(object):
def bar(self):
pass
foo = Foo()
b = foo.bar
b == foo.bar #evaluates True. why?
b is foo.bar #evaluates False. why?
Run Code Online (Sandbox Code Playgroud)
我用Python 2.7和3.3(CPython)重现了这一点,以确保它不是旧版本的实现细节.在其他情况下,身份测试按预期工作(翻译会议从上面继续):
#(2) with a non-method function
def fun(self):
pass
f = fun
f == fun #evaluates True
f is fun #evaluates True
#(3) when fun is bound as a method
Foo.met = fun
foo.met == fun #evaluates False
foo.met is fun #evaluates False
#(4) with a callable data …Run Code Online (Sandbox Code Playgroud) 对象标识的运算符
is和is not测试:x is y当且仅当x和y是同一个对象时才是真的.x is not y产生反向真值.
我们试试看:
>>> def m():
... pass
...
>>> m is m
True
Run Code Online (Sandbox Code Playgroud)
由于自动垃圾收集,空闲列表和描述符的动态特性,您可能会注意到
is操作符的某些使用中看似异常的行为,例如涉及实例方法或常量之间的比较.查看他们的文档了解更多信息.
>>> class C:
... def m():
... pass
...
>>> C.m is C.m
False
Run Code Online (Sandbox Code Playgroud)
我搜索了更多的解释,但我找不到任何解释.
为什么是C.m is C.m假的?
我使用的是Python 2.x. 如下面的答案中所述,在Python 3.x中C.m is C.m是真的.
Python 2.7中的代码结果让我感到矛盾.该is运营商应该与对象的身份工作,所以是id.但是当我查看用户定义的方法时,他们的结果会有所不同.这是为什么?
py-mach >>class Hello(object):
... def hello():
... pass
...
py-mach >>Hello.hello is Hello.hello
False
py-mach >>id(Hello.hello) - id(Hello.hello)
0
Run Code Online (Sandbox Code Playgroud)
我从Python数据模型的描述中发现以下摘录有些用处.但它并没有真正使一切清楚.id如果每次重新构造用户定义的方法对象,为什么函数返回相同的整数?
获取类的属性(可能通过该类的实例),如果该属性是用户定义的函数对象,未绑定的用户定义的方法对象或类方法对象,则可以创建用户定义的方法对象.当属性是用户定义的方法对象时,仅当从中检索它的类与存储在原始方法对象中的类相同或派生类时,才会创建新的方法对象; 否则,原始方法对象按原样使用.
考虑以下代码:
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
Run Code Online (Sandbox Code Playgroud)
我希望它能显示出真实.为什么显示False?
在Python 2.7.9中,当我将未绑定方法分配给新属性并按is语句进行比较时,结果为False:
In [1]: class A(object):
...: def a(self):
...: pass
...:
In [2]: A._a = A.a
In [3]: print A.a, A._a
<unbound method A.a> <unbound method A.a>
In [4]: print id(A.a), id(A._a)
4499595904 4499595904
In [5]: A.a is A._a
Out[5]: False
Run Code Online (Sandbox Code Playgroud)
这是非常反直觉的,我找不到任何参考或文档来解释这种行为.更重要的是,当我在Python 3.4.2中测试相同的代码时,结果变成了True.我猜这是Python 2.7中的一个错误,但在Python 3中得到修复,任何人都可以帮我找到发生这种情况的真正原因吗?
为什么这个返回 False
>>> class A:
... def a_method(self):
... pass
... def b(self):
... print(self.a_method is self.a_method)
...
>>> c = A()
>>> c.b()
False
>>> c.a_method is c.a_method
False
Run Code Online (Sandbox Code Playgroud)
什么时候可以使用is函数
>>> def a(): pass
...
>>> a is a
True
Run Code Online (Sandbox Code Playgroud) 我有一个嵌套函数,我用它作为回调pyglet:
def get_stop_function(stop_key):
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
return stop_on_key
pyglet.window.set_handler('on_key_press', get_stop_function('ENTER'))
Run Code Online (Sandbox Code Playgroud)
但是当我需要再次引用嵌套函数时,我会遇到问题:
pyglet.window.remove_handler('on_key_press', get_stop_function('ENTER'))
Run Code Online (Sandbox Code Playgroud)
由于python处理函数的方式,这不起作用:
my_stop_function = get_stop_function('ENTER')
my_stop_function is get_stop_function('ENTER') # False
my_stop_function == get_stop_function('ENTER') # False
Run Code Online (Sandbox Code Playgroud)
感谢两个类似的 问题我理解发生了什么,但我不确定我的案例的解决方法是什么.我正在查看pyglet源代码,它看起来像pyglet使用相等来找到要删除的处理程序.
所以我的最后一个问题是:如何覆盖内部函数的__eq__方法(或其他一些dunder),以便相同的嵌套函数相等?
(另一种解决方法是自己存储对函数的引用,但这会复制pyglet的工作,会因许多回调而变得混乱,反正我对这个问题很好奇!)
编辑:实际上,在我上面链接的问题中,它解释了方法具有值相等但不具有引用相等性.使用嵌套函数,您甚至无法获得值相等,这就是我所需要的.
编辑2:我可能接受Bi Rico的回答,但有人知道为什么以下不起作用:
def get_stop_function(stop_key):
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
stop_on_key.__name__ = '__stop_on_' + stop_key + '__'
stop_on_key.__eq__ = lambda x: x.__name__ == '__stop_on_' + stop_key + '__'
return stop_on_key
get_stop_function('ENTER') …Run Code Online (Sandbox Code Playgroud) 访问classmethod一个类总是返回一个不同的对象。这与实例或静态方法不同。
class Foo(object):
@classmethod
def foo_classmethod(cls):
pass
def foo_instancemethod(self):
pass
@staticmethod
def foo_staticmethod():
pass
Run Code Online (Sandbox Code Playgroud)
当试图比较
In [37]: print(Foo.foo_instancemethod is Foo.foo_instancemethod)
True
In [38]: print(Foo.foo_staticmethod is Foo.foo_staticmethod)
True
In [39]: print(Foo.foo_classmethod is Foo.foo_classmethod)
False
Run Code Online (Sandbox Code Playgroud)
Python 2和3中的行为相同。这看起来像是bug吗?我在酸洗Python3中的类方法并对未酸洗的is对象进行检查时遇到了这个问题。
比较变量是否包含我想要的可调用对象的正确方法是什么?我应该使用is运算符还是==运算符?
在下面的交互式会话中,我定义了两个可调用对象,f和g。我将一个分配给变量a,另一个分配给变量b。
现在,当我想检查是否a相同时f,两者a == f都a is f可以工作。
>>> def f():
... pass
...
>>> def g():
... pass
...
>>> a = f
>>> b = g
>>> a == f
True
>>> a is f
True
>>> a == g
False
>>> a is g
False
>>> b == f
False
>>> b is f
False
>>> b == …Run Code Online (Sandbox Code Playgroud) python ×9
python-3.x ×4
identity ×3
python-2.7 ×3
class ×1
class-method ×1
comparison ×1
equality ×1
interpreter ×1
nested ×1
object ×1
pickle ×1
pyglet ×1
python-3.7 ×1