【问题标题】:Why IPython behavior is different than Python's one?为什么 IPython 的行为与 Python 的不同?
【发布时间】:2020-11-03 20:01:16
【问题描述】:

在 Python 3.8.5 shell 中,我有:

>>> id([])
140370451791744
>>> id([])
140370451791744
>>> id([])

在运行 Python 3.8.5 的 IPython 7.18.1 中,我有:

In [1]: id([])
Out[1]: 139870334633536

In [2]: id([])
Out[2]: 139870334633152

这让我想到了以下问题:为什么 IPython 的行为与 python 的不同?

这与我之前提出的Which interpreter is used by ipython? 的问题有关,表明 IPython 和 Python 交互式 shell 使用相同的 Python 实现,即 CPython。

对我来说,IPython 只是一个外壳程序,应该只是将 Python 代码的解释转发给与 Python 相同的底层解释器。因此,对相同代码求值的结果应该是相同的(当然不是对象的地址,而是重用相同的事实)

注意:我可以很容易地想出一些原因来解释为什么有时解释器能够为新对象重用相同的内存位置,而有时却不能,但我无法解释为什么这里的行为会有所不同,因为两者都使用相同的实现。

这是重复的吗:对于询问这是否与How unique is Python's id()? 重复的人,答案显然是否定的,我已尽力解释上述原因。也许不清楚?

【问题讨论】:

  • 这能回答你的问题吗? How unique is Python's id()?
  • 两个不同的对象,具有不相交的生命周期,是否具有相同的 id 是对于所有目的完全无关。绝对没有保证会发生的情况,绝对没有保证会发生的情况。在这种情况下,IPython 恰好比普通的 CPython 执行更多的 Python 代码(例如,生成那些花哨的 In/Out 提示),所以只能说这是两种不同的情况。
  • 是的,IPython 是用 Python 编写的。 Python,甚至,或者至少是我刚刚检查的版本。
  • downvoting 最好在心理学论坛中解释。但用我自己的话来说,一般来说,人们不喜欢提出不便的问题的人。
  • ipython 维护了较长的输出历史,这可能会影响内存使用和重用的细节。生成具有不同 id 的空列表的最可靠方法是将它们收集在一个列表中,例如。 alist = [[],[],[]]。现在看看[id(i) for i in alist]。一般来说,查看id() 并没有多大价值。

标签: python ipython


【解决方案1】:

尝试在 IPython 中通过一个源文件运行 id([]) 两次。它应该为您提供与常规 Python 相同的结果。 由于上述行为,IPython 也不会导致任何错误。 您可以在每个命令后检查 locals() 和 globals() 以进一步排除故障或了解更多信息。 似乎 IPython 垃圾会立即收集第一个。

【讨论】:

    【解决方案2】:

    这是一个非常有趣的观察,并没有多少人知道 IPython 在执行语句时使用两个线程。一个线程用于历史记录,另一个用于新的执行。每当您一个接一个地调用id 时,第二个会在不同的线程中执行,这使得它具有不同的 id。

    你可以玩弄你的发现:

    在 IPython 中:

    import threading
    print(threading.activeCount())  # Should print "2"
    
    # The statetement below should be printing alternating id numbers
    # Such as "1 2 1 2" or smthng like that
    print(id([])); print(id([])); print(id([])); print(id([]));
    

    但是,普通的旧 python shell 使用单线程,这意味着相同对象的 id 将始终相同。

    在 Python 外壳中

    import threading
    print(threading.activeCount())  # Should print "1"
    
    # The statetement below should be printing the same values
    # Such as "1 1 1 1" or smthng like that
    print(id([])); print(id([])); print(id([])); print(id([]));
    

    更多信息:

    【讨论】:

    • 你错过了几个括号,但我只是尝试使用 ipython 并每次看到一个新 id,而不是两个交替的 id In [1]: print(id([])); print(id([])); print(id([])) 139808971501632 139808971823744 139808971503296 每次新 id
    • 谢谢——修复了括号。对于不同的 ID,请检查您的机器正在运行的线程数
    • 另外,尝试打印 > 3 条语句——通常如果计算机速度太快,线程会在执行下一条语句之前加入并释放。放更多的语句会在释放锁之前强制重叠,并且其中的id应该是重复的
    【解决方案3】:

    这是一个有趣的发现。 Interactive shell 的id 确实显得更稳定一些。然而,如果你在 shell 中多做一些修改,即使在交互式 Python shell 的同一个会话中,你也可以观察到不同的空列表的 id。

    >>> id([])
    140490599993424
    >>> [] is []
    False
    >>> id([])
    140490599925376
    >>> id([])
    140490599925376
    >>> [] is []
    False
    >>> id([])
    140490599993424
    

    iPython 中较低的 id 稳定性可能与垃圾收集有关,但最好询问 iPython 开发人员,无论哪种方式,很明显 iPython 比 shell 更复杂。

    身份是一个有点松散的概念,不要太依赖它

    >>> 123456789 is 123456789
    True
    >>> 12345678923456789 is 123456789123456789
    False
    >>> frozenset({}) is frozenset({})
    True
    >>> tuple() is tuple()
    True
    >>> list() is list()
    False
    >>> set() is set()
    False
    >>> id(12345678923456789)
    139811567040912
    >>> id(12345678923456789)
    139811567040912
    >>> id(123456789234567893)
    139811567040912
    

    更多信息请访问 Two variables in Python have same id, but not lists or tuples

    已编辑:我删除了关于计算中角色非确定性的段落,该段落引起了离题的讨论。

    【讨论】:

    • 现代计算机在定义上是确定性的。任何缺陷(例如缺陷或缺乏护理)都不应(并且几乎永远不会)引入诸如不同 ID 之类的差异。这是通过许多保障措施来实现的。快速说明——我不是在谈论代码错误,而是一般消费电子产品中的非确定性。
    • 谁告诉你关于现代(或古代)计算机的谎言?为什么id应该是一样的?只要行为有据可查,就可以拥有 volatile id
    • 这不是关于id的波动性,而是它背后的推理。 id 不同的原因已记录在案,这不是计算机的非确定性。这一切都是在多线程执行的上下文中执行内存管理。关于“谎言”——现代计算机对所有消费者应用程序都是确定性的。如果它看起来是不确定的,那么它是可解释和可预测的,假设您了解当前状态和实现。如果您想继续讨论,我们可以将此对话移至单独的聊天室
    • python shell 运行一个线程。然而,是的,多线程和并发是不确定性的重要来源。
    • 我认为这里的定义丢失了一些东西:如果您说确定性还包括直接用户的知识,那么电子设备中的所有内容实际上都是非确定性的——任何内存分配都变成非确定性的。但是,在 CS 中,确定性被明确定义为“给定特定的初始状态,最终状态始终相同”。这就是为什么没有真正的随机数生成器,这就是为什么我们可以将 pi 计算到数百万位的原因。而且只有非常不幸的硬件缺陷(如您所提到的)会影响这种行为。
    猜你喜欢
    • 1970-01-01
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多