我在让它工作时遇到了一些问题:
# Shortened for brevity
def _coerce_truth(word):
TRUE_VALUES = ('true','1','yes')
FALSE_VALUES = ('false','0','no')
_word = word.lower().strip()
print "t" in _word
if _word in TRUE_VALUES:
return True
elif _word in FALSE_VALUES:
return False
我发现:
In [20]: "foo" is "Foo".lower()
Out[20]: False
In [21]: "foo" is "foo".lower()
Out[21]: False
In [22]: "foo" is "foo"
Out[22]: True
In [23]: "foo" is "foo".lower()
Out[23]: False
这是为什么呢?我知道身份与平等不同,但身份是什么时候形成的?语句 22 应该False
,除非由于字符串的静态性质,id == eq。在这种情况下,我对语句 23 感到困惑。
请提前解释和感谢。
问:"身份是什么时候形成的?"
一个。创建对象时。
你看到的实际上是Cpython的实现细节——它缓存小字符串并重用它们以提高效率。 其他有趣的案例是:
"foo" is "foo".strip() # True
"foo" is "foo"[:] # True
最终,我们看到的是字符串文字"foo"
已被缓存。 每次键入 "foo"
时,您都在引用内存中的同一对象。 但是,一些字符串方法会选择始终创建新对象(如.lower()
),如果方法没有进行任何更改(如.strip()
),一些方法会巧妙地重用输入字符串。
这样做的一个好处是,字符串相等可以通过指针比较(极快)来实现,如果指针比较为 false,则逐字符比较。 如果指针比较为 True,则可以避免逐字符比较。
至于is
和in
之间的关系:
__contains__
方法(位于运算符后面in
)用于查找匹配项时tuple
和list
,首先检查标识,如果失败,则检查相等性。即使对象与自身不相等,这也将为您提供理智的结果:
>>> x = float("NaN")
>>> t = (1, 2, x)
>>> x in (t)
True
>>> any(x == e for e in t) # this might be suprising
False
假设您有一堆方法可以创建字符串值为 'foo' 的对象:
def f(s): return s.lower()
li=['foo', # 0
'foo'.lower(), # 1
'foo'.strip(), # 2
'foo', # 3
'f'+'o'*2, # 4
'{}'.format('foo'), # 5
'f'+'o'+'o', # 6
intern('foo'.lower()), # 7
'foo'.upper().lower(), # 8
f('foo'), # 9
'FOO'.lower(), # 10
'foo', # 11
format('foo'), # 12
'%s'%'foo', # 13
'%s%s'%('fo','o'), # 14
'f' 'oo' # 15
]
is
仅当对象具有相同的 id 时解析为 True
。您可以对此进行测试,并查看哪些字符串对象在运行时已暂留到同一个不可变字符串中:
def cat(l):
d={}
for i,e in enumerate(l):
k=id(e)
d.setdefault(k,[]).append(i)
return 'n'.join(str((k,d[k])) for k in sorted(d))
指纹:
(4299781024, [0, 2, 3, 6, 7, 11, 12, 13, 15])
(4299781184, [5])
(4299781784, [1])
(4299781864, [4])
(4299781904, [9])
(4299782944, [8])
(4299783064, [10])
(4299783144, [14])
您可以看到大多数解析(或被扣留)到同一个字符串对象,但有些则没有。这取决于实现。
您可以使用函数 intern 使它们都成为相同的字符串对象:
print cat([intern(s) for s in li])
指纹:
(4299781024, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])