为什么以下在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运算符可以区分.为什么泄漏抽象?当我不知道它们是否是数字时,比较两个任意对象以查看它们是否相同的更好的方法是什么?
该
is运营商不匹配变量的值,但这些实例本身.
它到底意味着什么?
我声明了两个变量命名x并y在两个变量中分配相同的值,但是当我使用is运算符时它返回false .
我需要澄清一下.这是我的代码.
x = [1, 2, 3]
y = [1, 2, 3]
print x is y #It prints false!
Run Code Online (Sandbox Code Playgroud) 虽然这个问题在实践中没有任何实际用途,但我很好奇Python如何进行字符串实习.我注意到以下内容.
>> "string" is "string"
>> True
Run Code Online (Sandbox Code Playgroud)
这是我所期待的.
你也可以这样做.
>> "strin"+"g" is "string"
>> True
Run Code Online (Sandbox Code Playgroud)
这非常聪明!
但你不能这样做.
>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False
Run Code Online (Sandbox Code Playgroud)
为什么Python不会评估s1+"g",意识到它是相同的s1并指向同一个地址?在最后一个块中实际发生了什么让它返回False?
深入研究Python的源代码后,我发现它维护了一个PyInt_Objects 数组,范围从int(-5)到int(256)(@src/Objects/intobject.c)
一个小实验证明了这一点:
>>> a = 1
>>> b = 1
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False
Run Code Online (Sandbox Code Playgroud)
但是如果我在py文件中一起运行这些代码(或者用分号连接它们),结果会有所不同:
>>> a = 257; b = 257; a is b
True
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么它们仍然是同一个对象,所以我深入研究语法树和编译器,我想出了一个下面列出的调用层次结构:
PyRun_FileExFlags()
mod = PyParser_ASTFromFile()
node *n = PyParser_ParseFileFlagsEx() //source to cst
parsetoke()
ps = PyParser_New()
for (;;)
PyTokenizer_Get()
PyParser_AddToken(ps, ...)
mod = PyAST_FromNode(n, ...) //cst to ast
run_mod(mod, ...)
co = PyAST_Compile(mod, ...) //ast to CFG …Run Code Online (Sandbox Code Playgroud) 根据我的意识,使用[], {}或()实例化对象会分别返回一个list, dict或新的实例tuple; 具有新标识的新实例对象.
这对我来说非常清楚,直到我实际测试它并且我注意到() is ()实际返回True而不是预期False:
>>> () is (), [] is [], {} is {}
(True, False, False)
Run Code Online (Sandbox Code Playgroud)
正如所料,与创建对象时,这种行为还表现list(),dict()并tuple()分别为:
>>> tuple() is tuple(), list() is list(), dict() is dict()
(True, False, False)
Run Code Online (Sandbox Code Playgroud)
我可以在状态文档中tuple()找到的唯一相关信息:
[...]例如,
tuple('abc')退货('a', 'b', 'c')和tuple([1, 2, 3])退货(1, 2, 3).如果没有给出参数,构造函数会创建一个新的空元组().
可以说,这还不足以回答我的问题.
那么,为什么空元组具有相同的身份,而其他像列表或词典不具有相同的身份?
考虑以下代码:
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
Run Code Online (Sandbox Code Playgroud)
我希望它能显示出真实.为什么显示False?
>>> a=1
>>> b=1
>>> id(a)
140472563599848
>>> id(b)
140472563599848
>>> x=()
>>> y=()
>>> id(x)
4298207312
>>> id(y)
4298207312
>>> x1=(1)
>>> x2=(1)
>>> id(x1)
140472563599848
>>> id(x2)
140472563599848
Run Code Online (Sandbox Code Playgroud)
直到这一点,我认为只有一个不可变对象的副本,并且将由所有变量共享(指向).
但是当我尝试时,以下步骤我明白我错了.
>>> x1=(1,5)
>>> y1=(1,5)
>>> id(x1)
4299267248
>>> id(y1)
4299267320
Run Code Online (Sandbox Code Playgroud)
任何人都可以向我解释内幕吗?
试图了解以下内容
为什么Python分配的ID对于相同的列表是不同的?
x = [1, 2, 3]
y = [1, 2, 3]
id(x) != id(y)
True
id(x)
11428848
id(y)
12943768
Run Code Online (Sandbox Code Playgroud) 我被介绍是运营商给我的学生时,我注意到,在Python(3.6版以上)和(3.7版)之间的行为不一致.
启动python shell并运行:
5/2 is 2.5
Run Code Online (Sandbox Code Playgroud)
要么:
(1, 2, 3) is (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
在v3.6.X中,你得到False了两者,但在v3.7中他们结果是True.
我的期望是结果应该是True,因为我认为不可变数字对象(或它们的元组)只有一个实例.
似乎至少我的想法在以前的Python版本中是不对的.
有谁知道解释这种新行为的变化是什么?
考虑以下:
var1 = 'test test'
var2 = 'test test'
list1=[10,12,12,"Test"]
list2=[10,12,12,"Test"]
print(id(var1) == id(var2)) # True
print(id(list1) == id(list2)) # False
Run Code Online (Sandbox Code Playgroud)
该布尔表达式为False。这意味着list1和list2的存储位置不同。为什么具有相同值的变量指向相同的内存位置,而列表却指向不同的位置?
当我执行以下步骤时,即使重新分配旧值(),两个元组(a和b)也都没有保留其原始ID (1,2).
>>> a , b = (1,2) , (1,2)
>>> a
(1, 2)
>>> b
(1, 2)
>>> id(a) , id(b)
(80131912, 91541064)
>>> a , b = (3,4) , (3,4)
>>> a
(3, 4)
>>> b
(3, 4)
>>> id(a) , id(b)
(91559048, 91689032)
>>> a , b = (1,2) , (1,2)
>>> a
(1, 2)
>>> b
(1, 2)
>>> id(a) , id(b)
(91556616, 91550408)
Run Code Online (Sandbox Code Playgroud)
但是在下面的例子中,两者都得到了旧ID.
>>> a = (1,2)
>>> b …Run Code Online (Sandbox Code Playgroud)