为什么以下在Python中出现意外行为?
>>> a = 256
>>> b = 256
>>> a is b
True # This is an expected result
>>> a = 257
>>> b = 257
>>> a is b
False # What happened here? Why is this False?
>>> 257 is 257
True # Yet the literal numbers compare properly
Run Code Online (Sandbox Code Playgroud)
我使用的是Python 2.5.2.尝试一些不同版本的Python,似乎Python 2.3.3显示了99到100之间的上述行为.
基于以上所述,我可以假设Python在内部实现,使得"小"整数以不同于大整数的方式存储,is运算符可以区分.为什么泄漏抽象?当我不知道它们是否是数字时,比较两个任意对象以查看它们是否相同的更好的方法是什么?
请看一个简单的例子:
class A:
def __init__(self, flag):
self.flag = flag
def func(self):
print self.flag
a = A(1)
b = A(2)
callback_a = a.func
callback_b = b.func
callback_a()
callback_b()
Run Code Online (Sandbox Code Playgroud)
结果是:
1
2
Run Code Online (Sandbox Code Playgroud)
它按预期运行.但我有一个问题.在C中,回调函数作为指针传递.在Python中,它应该有类似的方法来执行此操作,因此调用者知道函数的地址.但在我的例子中,不仅传递了函数指针,而且传递了参数(self),因为同一类的相同方法打印出不同的结果.所以我的问题是:
Python中的这种方法在内存中只有一个副本吗?我的意思是任何方法的代码只有一个副本,在我的例子中,该方法不会被克隆.我认为它应该只有一个副本,但在这里我仍然提出这个问题,以获得更多的输入.
我记得Python中的所有内容都是一个对象.所以在我的例子中,是否有两个具有不同参数但只有一个代码副本的函数实例?
我有一个错误,我在使用时依赖于彼此相等的方法is.事实证明并非如此:
>>> class What(object):
def meth(self):
pass
>>> What.meth is What.meth
False
>>> inst = What()
>>> inst.meth is inst.meth
False
Run Code Online (Sandbox Code Playgroud)
为什么会这样?它适用于常规功能:
>>> def func():
pass
>>> func is func
True
Run Code Online (Sandbox Code Playgroud) 为什么这个返回 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) 我试图编写一个测试,检查保存类的绑定方法的变量是否与该方法的另一个引用相同.通常这不是问题,但在同一类的另一个方法中完成时似乎不起作用.这是一个最小的例子:
class TestClass:
def sample_method(self):
pass
def test_method(self, method_reference):
print(method_reference is self.sample_method)
Run Code Online (Sandbox Code Playgroud)
我真的使用的是assert代替print,但是既不是在这里也不是在那里,因为最终的结果是相同的.测试运行如下:
instance = TestClass()
instance.test_method(instance.sample_method)
Run Code Online (Sandbox Code Playgroud)
结果是False即使我期待它True.这个问题在Python 3.5和Python 2.7(在Anaconda下运行)中体现出来.
我知道绑定方法是通过执行类似操作获得的闭包TestClass.test_method.__get__(instance, type(instance)).不过,我希望这self.sample_method已经是这样一个封闭的引用,使self.sample_method和instance.sample_method代表相同的参考.
令我困惑的部分原因是pytest我正在运行的真实测试的输出(处理公关matplotlib):
assert <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> is <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>>
E + where <bound method TestTransformFormatter.transform1 of <matplotlib.tests.test_ticker.TestTransformFormatter object at 0x7f0101077b70>> = <matplotlib.ticker.TransformFormatter object at 0x7f0101077e10>.transform
E + and …Run Code Online (Sandbox Code Playgroud)