【问题标题】:"is" operator not working as intended"is" 运算符未按预期工作
【发布时间】:2015-05-11 21:34:54
【问题描述】:

看看这段代码:

import re

ti = "abcd"
tq = "abcdef"
check_abcd = re.compile('^abcd')
print id(check_abcd.search(ti))
print id(check_abcd.search(tq))
print check_abcd.search(ti)
print check_abcd.search(tq)
if check_abcd.search(ti) is check_abcd.search(tq):
    print "Matching"
else:
    print "not matching"

输出:

41696976
41696976
<_sre.SRE_Match object at 0x00000000027C3ED0>
<_sre.SRE_Match object at 0x00000000027C3ED0>
not matching

is的定义:

`is` is identity testing, == is equality testing. 
 is will return True if two variables point to the same object

1) 现在为什么is 不返回True 当id 和对象引用相同时。

2)当is== 替换时,它仍然返回false。这是使用== 比较对象时的预期行为。

【问题讨论】:

  • 由于垃圾收集
  • Python 在清除变量时重用 id 值。
  • @AshwiniChaudhary Garbage collection??????任何链接或更多信息?
  • @MartijnPieters 什么时候清除变量?
  • @vks: 当引用计数下降到 0 时。

标签: python


【解决方案1】:

您从未分配返回值,因此在打印 check_abcd.search() 调用的返回值的 id() 值后,Python 丢弃返回值对象,因为没有任何引用它了。 CPython 对象的生命周期直接由对它们的引用数量控制;一旦该引用计数降至 0,该对象就会从内存中删除。

可以重复使用废弃的内存位置,因此您会希望在id() 调用中看到相同的值。见id() documentation

返回对象的“身份”。这是一个整数(或长整数),保证该对象在其生命周期内是唯一且恒定的。 生命周期不重叠的两个对象可能具有相同的id() 值。

在您的代码中,您实际上没有一个对象,您有两个独立的对象,它们的生命周期不重叠。

如果您想确保id() 值不被重用,请分配返回值:

>>> import re
>>> ti = "abcd"
>>> tq = "abcdef"
>>> check_abcd = re.compile('^abcd')
>>> ti_search = check_abcd.search(ti)
>>> tq_search = check_abcd.search(tq)
>>> id(ti_search), id(tq_search)
(4378421952, 4378422056)
>>> ti_search, tq_search
(<_sre.SRE_Match object at 0x104f96ac0>, <_sre.SRE_Match object at 0x104f96b28>)
>>> ti_search is tq_search
False

通过分配check_abcd.search()(正则表达式MatchObjects)的返回值,创建了一个额外的引用,Python 无法重用内存位置。

【讨论】:

  • 如果让我们说id's 被重用.....为什么is 运算符没有返回matched
  • @vks: 因为它不是同一个对象is 不测试内存位置。它测试某物是否实际上是完全相同的对象。
  • 在每种情况下除了条件语句,值都是在语句中创建和释放的。但是条件不能释放第一个值,直到它评估 both 值,这就是为什么在该单个表达式中,Python 从 .search() 创建两个不同的结果值。在单独的答案中查看我的注释代码。
  • 非常感谢.....这很有帮助!!!!!!...你能不能给点启发或分享一些关于什么是引用计数的文档
  • @vks:这可能会有所帮助:Reference Counts
【解决方案2】:

当你这样做时: print id(check_abcd.search(ti)) 在一行中并且不要将search 的返回值存储在任何地方,它的引用计数变为零并且被销毁。下面一行中的调用创建了另一个对象,该对象恰好位于相同的内存地址(CPython 将其用作对象 ID) - 但它不是同一个对象。

当您使用is 运算符时,前一个对象仍然必须存在才能进行比较,并且其地址会有所不同。

只需将调用 check_abcd.search 的结果放入变量中,然后打印它们的 ID(并使用不同的变量),您就可以看到实际发生了什么。

此外:如果您想了解“is”和对象 ID 的行为,继续这些行可能会很有指导意义 - 但如果您想比较字符串并返回值,只需使用 == 运算符,不要使用 @ 987654326@: 后续函数调用,即使返回相同的值也不应该返回相同的对象 - is 比较仅在与“None”(作为单例实现)比较时推荐使用

【讨论】:

  • 非常感谢......如果您可以发布一些关于reference count 的链接以及它的范围是什么
  • 不用担心引用计数——它是由 Python 自动为您实例化的任何对象完成的。您需要知道的是,如果任何变量/对象中没有对对象的引用,则该对象将被销毁,并且其内存可用于创建其他对象。
  • 'is 比较仅在与“None”'比较时推荐使用 → 或任何预定义的枚举,真的(例如使用object() 作为标记)。
【解决方案3】:

Martjin 已为您提供了正确答案,但为了进一步说明,这里是您的代码中发生的事情的注释版本:

# this line creates returns a value from .search(), 
# prints the id, then DISCARDS the value as you have not 
# created a reference using a variable.
print id(check_abcd.search(ti)) 

# this line creates a new, distinct returned value from .search()
# COINCIDENTALLY reusing the memory address and id of the last one.
print id(check_abcd.search(tq))

# Same, a NEW value having (by coincidence) the same id
print check_abcd.search(ti)

# Same again
print check_abcd.search(tq)

# Here, Python is creating two distinct return values.  
# The first object cannot be released and the id reused
# because both values must be held until the conditional statement has 
# been completely evaluated.  Therefore, while the FIRST value will
# probably reuse the same id, the second one will have a different id.
if check_abcd.search(ti) is check_abcd.search(tq):
    print "Matching"
else:
    print "not matching"

【讨论】:

  • 很好的答案,有很多我喜欢的 cmets。但你确定是巧合
  • 我想添加一个注释——显然它是可复制的,因此不是真正的巧合; Python 一直在重用最后一个 id。但我决定留下巧合这个词,因为这就是它应该被对待的方式。真正的巧合是代码创建并丢弃了两个对象,以便看起来彼此相关。
猜你喜欢
  • 2019-06-20
  • 2021-04-13
  • 1970-01-01
  • 2020-12-29
  • 2021-04-30
  • 2019-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多