当前位置: 首页 > 面试题库 >

当字符串中有一个点时,为什么“ is”关键字具有不同的行为?

虞滨海
2023-03-14
问题内容

考虑以下代码:

>>> x = "google"
>>> x is "google"
True
>>> x = "google.com"
>>> x is "google.com"
False
>>>

为什么会这样呢?

为确保以上内容正确无误,我刚刚在Windows上的Python 2.5.4、2.6.5、2.7b2,Python 3.1和Linux上的Python
2.7b1上进行了测试。

看起来所有这些对象之间都具有一致性,所以这是设计使然。我想念什么吗?

我只是从我的一些个人域过滤脚本中发现失败了。


问题答案:

is验证对象的身份,和Python,任何执行时,它符合字面不变类型的,是完全自由 要么 做出不可变类型的新对象,
通过该类型的现有对象觅见,如果他们中的一些可重复使用(通过添加对相同基础对象的新引用)。这是优化的一个务实的选择并 没有
受到语义约束,所以你的代码不应该依赖于该路径的给予实施可能要(或者它可能与Python的bug修正/优化版本破门!)。

考虑例如:

>>> import dis
>>> def f():
...   x = 'google.com'
...   return x is 'google.com'
... 
>>> dis.dis(f)
  2           0 LOAD_CONST               1 ('google.com')
              3 STORE_FAST               0 (x)

  3           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               1 ('google.com')
             12 COMPARE_OP               8 (is)
             15 RETURN_VALUE

因此,在此特定实现中, 在function内 ,您的观察结果不适用,并且为文字(任何文字)仅创建了一个对象,并且实际上:

>>> f()
True

实用上讲,这是因为在函数中通过常量的本地表(通过不制作多个足以满足要求的常量不可变对象来节省内存)非常便宜和快速,并且由于可以重复调用该函数,因此可以提供良好的性能返回之后。

但是, 在交互式提示符下 ,实现了相同的实现( 编辑 :我本来以为这也会在模块的顶层发生,但是@Thomas的评论使我正确了,请参阅下文):

>>> x = 'google.com'
>>> y = 'google.com'
>>> id(x), id(y)
(4213000, 4290864)

不必费心尝试以这种方式节省内存id-s是不同的,即不同的对象。可能会有更高的成本和更低的回报,因此此实现的优化程序的启发式方法告诉它不要费心搜索,而只是继续进行。

编辑 :根据@Thomas的观察,在模块顶层,例如:

$ cat aaa.py
x = 'google.com'
y = 'google.com'
print id(x), id(y)

再次,我们在此实现中看到基于常量表的内存优化:

>>> import aaa
4291104 4291104

(根据@Thomas的观察,编辑结束)。

最后,再次在相同的实现上:

>>> x = 'google'
>>> y = 'google'
>>> id(x), id(y)
(2484672, 2484672)

启发式方法在这里是不同的,因为文字字符串“看起来像是一个标识符”-因此它可能在需要进行intern操作的操作中使用…因此,优化程序仍然会对其进行intern(并且一旦intern,查找它就会变得非常快课程)。确实,令人惊讶……

>>> z = intern(x)
>>> id(z)
2484672

x 已经intern编在第一次(正如你看到的,返回值intern相同的
对象xy,因为它具有相同id())。当然,你不应该依赖此任-优化并不 具备 自动实习生什么,它只是一个优化启发式;
如果您需要interned字符串,则必须intern明确指定它们,以确保安全。当您显式地 执行内部 字符串时…:

>>> x = intern('google.com')
>>> y = intern('google.com')
>>> id(x), id(y)
(4213000, 4213000)

…然后您 可以 确保id()每次都获得完全相同的对象(即相同的)结果-
因此您可以应用微优化,例如使用进行检查,is而不是==(我几乎从未发现微不足道的性能提升值得麻烦;-)。

编辑 :只是为了澄清一下,这是我正在谈论的性能差异,在慢速的Macbook Air上…:

$ python -mtimeit -s"a='google';b='google'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.107 usec per loop
$ python -mtimeit -s"a='goo.gle';b='goo.gle'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.106 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a is b'
10000000 loops, best of 3: 0.0966 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a == b'
10000000 loops, best of 3: 0.126 usec per loop

……最多两种方式都只有几十纳秒。因此,即使仅在最极端的情况下也要 考虑 “从此[删除的性能]性能瓶颈中优化[删除的性能]”!-)



 类似资料:
  • 假设我有这个模型: 用户一次只能借一本书。如果用户被删除,我希望这个模型的实例被删除,但是如果一本书被删除,我不希望它们被删除(错误地,只是一个预防措施)。 使用上述约束删除用户时,预期的行为是什么?我得到: 无法删除模型“UserBook”的某些实例,因为它们是通过受保护的外键引用的 有没有办法实现我想要的?我试图删除UserBook上的/信号与作为发送者,但都不工作。

  • 问题内容: 例如: 问题答案: 这是因为从索引0 in开始的长度为0的子字符串等于空字符串: 当然,任何字符串的长度为零的 每个 子字符串都等于空字符串。

  • 问题内容: 我有一个Python程序,其中两个变量被设置为值’public’。在条件表达式中,比较var1是var2,但如果将其更改为var1==var2,则返回True。 现在,如果我打开Python解释器并进行相同的比较,则此操作成功。 我错在哪里? 问题答案: 1481 是身份测试,是平等测试。你的代码中发生的情况将在解释器中进行模拟,如下所示: 所以,难怪他们不一样吧? 换句话说:

  • 问题内容: 我从书中看到以下代码: 但没有提到为什么“一个”大于“四个”。我试过了,它小于a和b。我想知道JavaScript如何比较这些字符串。 问题答案: 因为和许多编程语言一样,字符串是按字典顺序进行比较的。 你可以认为这是一个空想家版本的字母顺序,区别在于字母排序仅覆盖了26个字符通过。

  • 问题内容: 我试图用来创建我的,以确保我的构建/项目的质量。该项目也需要使用和。一切在我的本地计算机上都可以正常运行,但是现在我正在尝试使环境一致,可重现。当我尝试在新的虚拟机中运行时,会中断一个在本机中正常运行但 不在 新vm中运行的。 我检查了版本,,,(其)一切都是一样的。但是,我的Maven项目在此测试中失败了。 我在这里想念什么?任何想法,建议都会受到赞赏,因为我现在还没有想法,到目前为

  • 问题内容: 我需要采取目前的hql: 并将其更改为 我的问题是与distinct关键字有关。它在使用新的Object查询类型的hql查询中属于什么位置。一种想法是使用子选择,让我与众不同。我试过添加,但不起作用。 问题答案: 好的,对感兴趣的人来说,正确的语法是