这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)
Posted
技术标签:
【中文标题】这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)【英文标题】:Is this a bug? Variables are identical references to the same string in this example (Python) 【发布时间】:2011-05-09 02:50:17 【问题描述】:这适用于 Python 2.6。
我不明白为什么 a 和 b 是相同的:
>>> a = "some_string"
>>> b = "some_string"
>>> a is b
True
但如果字符串中有空格,则不是:
>>> a = "some string"
>>> b = "some string"
>>> a is b
False
如果这是正常行为,请有人解释发生了什么。
编辑:免责声明! 这不用于检查是否相等。我实际上想向其他人解释“是”只是为了检查身份,而不是平等。 从文档中我了解到,以这种方式创建的引用会有所不同,每次都会创建一个新字符串。 当我无法证明自己的观点时,我给出的第一个例子让我大吃一惊!
编辑: 我知道这不是错误,实习对我来说是一个新概念。 This 似乎是一个很好的解释。
【问题讨论】:
见***.com/questions/306313/… “错误?”问题真的让我很恼火……但我想这不是标记问题的理由……是吗? @cobbal:这与这里发生的情况略有不同。 @Ignacio:不同的根本原因,虽然基本类别相同:一些不可变的对象被缓存,而另一些则没有,基于一些未指定的启发式或其他。 众多示例之一:How is the 'is' keyword implemented in Python? 【参考方案1】:Python 可能会也可能不会自动实习字符串,这决定了字符串的未来实例是否将共享一个引用。
如果它决定实习一个字符串,那么两者都将引用同一个字符串实例。如果没有,它将创建两个恰好具有相同内容的单独字符串。
一般来说,您无需担心是否会发生这种情况;你通常想检查相等性,a == b
,而不是它们是否是同一个对象,a is b
。
【讨论】:
只是出于好奇,你知道Python实习字符串的逻辑是什么吗?我以为它会保留每个字符串文字,但显然不是... @katrielalex:.py 文件中的字符串有点不同:它们存储在一个常量列表中,这些常量由字节码中的索引引用。这意味着如果您在一个 .py 文件的两个位置使用相同的字符串常量,几乎可以保证它们是同一个对象。这和实习不一样。但是,OP 并没有用完 .py 文件,而是从 Python 解释器运行;这意味着它们被解析为单独的“文件”,并且没有共享字符串表。【参考方案2】:TIM PETERS 说:抱歉,我在这里看到的唯一错误是您发布的代码中使用“is”来尝试确定两个字符串是否相等。 "is" 测试对象身份,而不是相等性,以及两个不可变对象是否真的是同一个对象通常不是由 Python 定义的。您应该使用“==”来检查两个字符串是否相等。唯一可以可靠地使用“is”的情况是,当您明确地对所有正在比较的字符串进行了实习时(通过使用 intern() 内置函数)。
从这里:http://mail.python.org/pipermail/python-bugs-list/2004-December/026772.html
【讨论】:
-1:对于像字符串这样的不可变对象,您会期望相等的引用,所以这不是错误。 @Falcon:不。字符串是不可变的允许(高效)实习(=相同对象的相同引用),但它不需要。 @Falcon:那么你的期望是错误的。检查本机 python 代码和 python 包装的 c 库之间的相等性,例如:openssl 库。即使您不知道并非所有字符串都被保留。很遗憾我不能标记你。 为此使用is
永远不可靠。 intern
可能是空操作:Python 实现可能选择不使用字符串实习(让实习生简单地返回其参数),它也可能选择忽略实习字符串的请求。例如,CPython 会默默地忽略对 string
的实习生子类的请求。【参考方案3】:
这实际上应该是对格伦的回答的更多评论,但我还不能做 cmets。我直接在 Python 解释器上运行了一些测试,我看到了一些有趣的行为。根据 Glenn 的说法,解释器将条目视为单独的“文件”,并且在存储以供将来参考时它们不共享字符串表。 这是我运行的:
>>> a="some_string"
>>> b="some_string"
>>> id(a)
2146597048
>>> id(b)
2146597048
>>> a="some string"
>>> b="some string"
>>> id(a)
2146597128
>>> id(b)
2146597088
>>> c="some string" <-----(1)
>>> d="some string"
>>> id(c)
2146597208 <-----(1)
>>> a="some_string"
>>> b="some_string"
>>> id(a)
2146597248 <---- waited a few minutes
>>> c="some_string"
>>> d="some_string"
>>> id(d)
2146597248 <---- still same id after a few min
>>> b="some string"
>>> id(b)
2146597288
>>> b="some_string" <---(2)
>>> id(b)
2146597248 <---(2)
>>> a="some"
>>> b="some"
>>> c="some"
>>> d="some" <---(2) lost all references
>>> id(a)
2146601728
>>> a="some_string" <---(2)
>>> id(a)
2146597248 <---(2) returns same old one after mere seconds
>>> a="some"
>>> id(a)
2146601728 <---(2) Waited a few minutes
>>> a="some_string" <---- (1)
>>> id(a)
2146597208 <---- (1) Reused a "different" id after a few minutes
似乎某些 id 引用可能会在初始引用丢失并且不再“使用”(1) 后被重用,但它也可能与这些 id 引用未被使用的时间有关,因为您可以在我标记为数字 (2) 的内容中看到,根据未使用该 id 的时间长短给出不同的 id 引用。我只是觉得它很好奇,并想发布它。
【讨论】:
以上是关于这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)的主要内容,如果未能解决你的问题,请参考以下文章