【问题标题】:Reference vs Assignment in Python mutable objectsPython可变对象中的引用与赋值
【发布时间】:2023-03-10 17:09:02
【问题描述】:

作业:

>>> a = ['spam']
>>> b = ['spam']
>>> a is b
False

参考:

>>> c = ['spam']
>>> d = c
>>> c is d
True
  1. 以上两者有什么区别?
  2. 为什么分配结果False
  3. 为什么要参考结果True

【问题讨论】:

    标签: python reference variable-assignment


    【解决方案1】:

    您的第一个 sn-p 创建了 两个 唯一的列表对象,它们并不相同。因此 a is b 返回 false 因为 ab 指向不同的对象:

    +------+ ------> |列表 | +------+ +------+ b ------> |列表 | +------+

    您的第二个 sn-p 创建一个列表对象,并将 cd 指向该对象,因此 c is d 返回 true:

    +------+ c ------> |列表 | &lt-----d +------+

    请注意以下内容,来自http://docs.python.org/3/reference/datamodel.html

    每个对象都有一个标识、一个类型和一个值。对象的身份一旦创建就永远不会改变;您可能会将其视为对象在内存中的地址。 is 运算符比较两个对象的身份; id() 函数返回一个表示其标识的整数。

    所以is== 是非常不同的;前者比较对象身份,后者比较对象值。实际上,您的 sn-ps 中的 == 测试会返回 true。


    鉴于上面的解释,故事与字符串略有不同可能会让人感到惊讶:

    >>> a = 'str'
    >>> b = 'str'
    >>> 
    >>> a is b
    True
    

    这是由于string interning,它发生在 CPython 中(即它是特定于实现的)。因此,如果相同的字符串字面量出现在两个不同的位置,则相同的字符串对象将用于两者(有限制)。

    这在"Python string interning"中有更详细的解释。

    【讨论】:

    • 那么,如果我在上面尝试像 str spam 这样的不可变对象而不是 list ['spam'],为什么两者的结果都是 True
    • @YousufMemon 那是因为strings are interned in CPython
    • 我是否应该将上述评论添加到主要问题中。您还可以为我的问题建议一个正确的标题吗?
    • @YousufMemon 也可以使用字符串 'spam.com' 再试一次,你会发现不同的结果 ;)
    • @wim 是的,它不同。为什么会这样?
    【解决方案2】:

    当与is比较时,如a is b,与id(a) == id(b)相同,代码xx=['spam']每次创建一个新列表并分配给xxid每次都会变化,所以a is b 给出 False

    【讨论】:

      【解决方案3】:

      让我在您最初所做的工作中添加一些函数调用。我想你会捡起来的。

      >>> a = ['spam']
      >>> b = ['spam']
      >>> a is b
      False
      >>> id(a)
      4552359808
      >>> id(b)
      4552446176
      >>> a == b
      True
      >>> c = ['spam']
      >>> d = c
      >>> id(c)
      4552513296
      >>> id(d)
      4552513296
      >>> c is d
      True
      >>> c == d
      True
      >>> print id.__doc__
      id(object) -> integer
      
      Return the identity of an object.  This is guaranteed to be unique among
      simultaneously existing objects.  (Hint: it's the object's memory address.)
      

      【讨论】:

        【解决方案4】:

        这与一些(不存在的)“分配与参考”问题无关。

        >>> a = ['spam']
        

        创建一个包含字符串“spam”的列表,并将其绑定到当前范围内的名称“a”。

        >>> b = ['spam']
        

        创建另一个包含字符串“spam”的列表,并将其绑定到当前范围内的名称“b”。

        你创建了两个列表,你有两个列表。很简单。

        >>> c = ['spam']
        

        创建另一个列表,其中包含字符串“spam”,并将其绑定到当前范围内的名称“c”。

        >>> d = c
        

        将名称“d”绑定到当前范围内当时绑定的任何“c”。

        在这里,您创建一个列表并将 2 个名称绑定到它。两个名称都指向同一个对象。

        重点是:Python 的“变量”不是命名的内存地址,只是指向对象的名称。在给定时间,一个对象可以绑定(指向)任意数量的名称(甚至根本没有名称)。

        【讨论】:

          猜你喜欢
          • 2015-08-18
          • 2014-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-26
          • 2021-03-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多