7

我在让它工作时遇到了一些问题:

# 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 感到困惑。

请提前解释并感谢。

4

3 回答 3

7

问:“身份是什么时候形成的?”

A. 创建对象时。

您所看到的实际上是 Cpython 的一个实现细节——它缓存小字符串并重用它们以提高效率。其他有趣的案例是:

"foo" is "foo".strip()  # True
"foo" is "foo"[:]       # True

最终,我们看到的是字符串文字"foo"已被缓存。每次键入"foo"时,您都在引用内存中的同一个对象。但是,一些字符串方法将选择始终创建新对象(如.lower()),如果方法未进行任何更改(如 ),一些字符串方法将巧妙地重新使用输入字符串.strip()


这样做的一个好处是,如果指针比较为假,则可以通过指针比较(非常快)然后逐字符比较来实现字符串相等。如果指针比较为 True,则可以避免逐字符比较。

于 2013-09-19T20:45:01.050 回答
3

is至于和之间的关系in

__contains__方法(位于运算符后面in)在查找匹配项时,首先检查身份,如果失败,则检查是否相等tuplelist即使对象与自身比较不相等,这也会为您提供合理的结果:

>>> x = float("NaN")
>>> t = (1, 2, x)
>>> x in (t)
True
>>> any(x == e for e in t) # this might be suprising
False
于 2013-09-19T21:02:42.603 回答
0

假设您有很多方法可以创建字符串值为 '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
]

isTrue仅当对象具有相同的id时才会解析。您可以对此进行测试并查看哪些字符串对象在运行时已嵌入到相同的不可变字符串中:

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])
于 2013-09-19T20:53:15.187 回答