【问题标题】:How to assign None to object reference in python如何在python中将None分配给对象引用
【发布时间】:2019-04-17 12:44:57
【问题描述】:

我是 python 的新手,对以下代码的输出有点困惑。

class obj:
    def __init__(self, data):
            self.data = data

o1 = obj(2)
o2 = o1

def func1(obj):
    obj.data = 5


func1(o1)
print(o1.data)
print(o2.data)
o2 = None
print(o1)
print(o2)

输出:

5
5
<__main__.obj instance at 0x7f7f6b5e63f8>
None

o1 对象不应该也变成“无”吗??

【问题讨论】:

  • 您可能应该阅读nedbatchelder.com/text/names.html - 赋值不会影响,只会影响标识符
  • "o1 对象不应该也变成 'None' 吗?"没有。
  • o1 不是对象;它是一个引用对象的 name。更改名称 o2 引用的内容不会影响 o2 使用 引用的对象(这是 o1 当前引用的对象)。

标签: python oop pass-by-reference


【解决方案1】:

o1 不应该是None

当您执行o2 = None 行时,o2 不再引用o1 对象。它现在指的是None 对象。 o1o2现在引用内存中的两个不同对象,如id函数所示(身份不同,id返回CPython中的对象内存地址)

print (id(o1)) # 140282748479024
print (id(o2)) # 140282748479024
o2 = None
print (id(o1)) # 140282748479024
print (id(o2)) # 140282774063376

【讨论】:

  • o2 的内存地址没有改变。绑定的对象发生了变化,根据定义,它实际上具有不同的地址。
【解决方案2】:

o2 = None 行有效地重新分配为与o1 不同的对象。观察:

>>> o1 = obj(2)
>>> id(o1)
155034832  
>>> o2 = o1
>>> id(o2)
155034832  # same ID as o1
>>> o1 is o2
True       # the objects are identical

但是一旦你重新分配o2:

>>> o2 = None
>>> id(o2)
262150788  # ID has now changed
>>> o1 is o2
False      # the objects are now different.

一旦你重新分配,对象之间就没有任何关系(除非通过其他方式绑定),因此你不应该期望它们表现相同。

【讨论】:

    【解决方案3】:

    Python 中的变量是对象的名称,而不是 C++ 中的内存位置。重新分配名称只会更改名称所指的内容;它不会更改引用对象或其他别名。


    最接近的等价物是指针:在 CPython 中,分配名称如 o2 = o1 有效地表示 PyObject *o2 = *o1。地址从一个名字复制到另一个名字。分配后的名称之间没有直接关系 - 它们只是碰巧仍然引用同一个对象。

    >>> o1 = {1, 2, 3}
    >>> o2 = o1
    >>> print(id(o1), id(o2))  # the *referents* of o1 and o2 are at the same memory location
    4444160520 4444160520
    

    当两个名称引用同一个对象时,它们表示该对象的相同状态——毕竟只有一种状态。这就是为什么通过 o2 也可以看到更改 o1.data 的原因 - o2o1 所指的 object 已被修改。

    >>> o1.add(16)
    >>> print(o1, o2)  # still the same referent, should have the same state
    {16, 1, 2, 3} {16, 1, 2, 3}
    >>> print(id(o1), id(o2))  # both still have the same referent
    4444160520 4444160520
    

    诀窍在于,虽然 o1o2 是独立的,但 o1.datao2.data 等成员却不是!每个顶级名称都是一个单独的实体。但是,属性等是相对于它们的对象的!


    重新分配时,只会更改分配给的名称。请记住,o2 复制了来自 o1 的引用 - 更改名称 o1 不会影响任何关系。

    >>> o1 = None
    >>> print(o1, o2)  # not the same referent anymore
    None {16, 1, 2, 3}
    >>> print(id(o1), id(o2))  # only o2 still refers to the same referent
    4436169032 4444160520
    

    【讨论】:

      猜你喜欢
      • 2014-10-19
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      相关资源
      最近更新 更多