Python 为什么变量=对象不';t像variable=number那样工作

Python 为什么变量=对象不';t像variable=number那样工作,python,python-2.7,variables,object,python-3.x,Python,Python 2.7,Variables,Object,Python 3.x,这些变量分配工作与我预期的一样: >>> a = 3 >>> b = a >>> print(a, b) (3, 3) >>> b=4 >>> print(a, b) (3, 4) 但是,这些任务的行为不同: >>> class number(): ... def __init__(self, name, number): ... self.name = name

这些变量分配工作与我预期的一样:

>>> a = 3
>>> b = a
>>> print(a, b)
(3, 3)
>>> b=4
>>> print(a, b)
(3, 4)
但是,这些任务的行为不同:

>>> class number():
...     def __init__(self, name, number):
...         self.name = name
...         self.number = number
... 
>>> c = number("one", 1)
>>> d = c
>>> print(c.number, d.number)
(1, 1)
>>> d.number = 2
>>> print(c.number, d.number)
(2, 2)
为什么
c
d
相同,不同于
(a,b)
示例?我如何在
(a,b)
中执行
(c,d)
类示例中的操作?也就是说,复制对象,然后更改其中一部分(这不会影响我从中借用属性的对象)?

这些行:

c = number("one", 1)
d = c
…实际上是:

  • 创建
    number
    的新实例,并将其分配给
    c
  • 将名为
    c
    的现有引用分配给新变量
    d
您没有更改或修改有关
c
的任何内容
d
是指向同一实例的另一个名称

如果不克隆实例或创建新实例,就无法执行与原语int类似的操作


为了纠正一点信息,上面的解释是不完整的,尽管它主要描述了10000英尺的高度

为了进一步了解,我们必须了解一些关于Python变量或“名称”的事情,以及它们如何与这个程序交互

如上所述,这是非常简单的理由:

a = 3
b = a
在此上下文中,
a
是名称,
b
是对
a
的绑定。我们没有修改或更改有关
a
的任何内容

如前所述,Python中有两种类型的数据:可变和不可变。指向不可变数据(如原语和元组)的名称可以重新分配,而不会对其上存在的任何其他绑定产生任何不良影响,因为绑定的状态没有改变

这就是为什么这次重新分配会达到我们预期的效果:

print(a, b)
b = 4
print(a, b)
b=4
的结果是
b
现在指向一个整数的新副本,即值4

回想一下,我确实提到元组是不可变的数据。无法更改元组中特定实体的绑定

t = ('foo', 'bar')
t[0] = 'baz' # illegal
…但您可以将可变数据结构作为这些绑定的一部分

t = ([1, 2, 3], 'bar')
t[0].append([4, 5, 6]) # ([1, 2, 3, [4, 5, 6]], 'bar')

那么,我们的例子会怎样呢

c = number("one", 1)
d = c
number
是一个名为
c
可变的类型,它的值可以在多个不同的
c
绑定之间随意更改

实际上,我们有一个名称和一个名称的绑定:

  • 我们有一个新的
    number
    实例,并通过名称
    c
    引用它
  • 将引用
    c
    绑定到另一个名称
    d
同样,关于
c
,没有任何更改,但可以通过另一个名称引用它

与不可变数据不同,当我们重新分配
d.number
的值时,我们重新分配的绑定与
c
知道的绑定相同:

>>> id(d.number)
36696408
>>> id(c.number)
36696408
这就是为什么需要新实例或副本的原因。您必须引用另一个
number
实例。使用这种简单的绑定,您无法实现这一点

from copy import copy
c = number("one", 1)
d = copy(c)
id(c) # 140539175695784
id(d) # 140539175695856

您关注的是这两对线是相同的(都使用普通的
=
):

您缺少的是这两行内容不同:

# one
b = 4

# two
d.number = 2
它们不一样的原因是
d.number
中有一个点,而
b
没有

设置
d=c
与设置b=a具有相同的效果。区别在于执行
d.number=2
与执行
b=4
不同。执行
b=4
操作时,将为名称
b
指定一个新对象。执行
d.number=2
操作时,可以修改名称
d
已引用的对象,而无需指定新对象。如果将第二个示例更改为
d=2
,使用普通赋值而不是属性赋值,您将看到
c
不受影响,就像第一个示例中
a
不受影响一样

尽管可能会让人困惑,
=
在Python的所有上下文中并不总是意味着相同的事情。分配给裸名称(
blah=…
)与分配给属性(
blah.attr=…
)或项目(
blah[item]=…
)不同。要理解
=
的含义,您需要查看左侧(赋值目标),看看它是一个简单的名称还是某种表达式

至于如何在c/d示例中获得a/b示例的效果,这完全取决于您想要的效果。如果您想以
d
c
指向具有不同
number
属性的不同对象结束,您可以执行以下操作:

d = number("one", 2)

请注意,这现在与
b=4
并行(因为它使用对裸名称的赋值)。还有其他更复杂的解决方案,包括复制现有的
d
对象;查看标准库中的模块。具体做什么取决于您试图用代码完成什么。

在Python中,所有内容都是参考。举个例子:

a = '1221398210p3'
b = a
print(id(a) == id(b)) # True
c = number("one", 1)
d = c
...
d.number = 2
现在,当您执行此操作时:

b = 4
你只是在更改编号b的参考资料。不是数字本身。现在,在后面的示例中:

a = '1221398210p3'
b = a
print(id(a) == id(b)) # True
c = number("one", 1)
d = c
...
d.number = 2
d=c
将d设置为参考c。现在,当您设置
d.number
时,您正在设置c和d引用的对象的属性。就像我说的,一切都是参考


在Python中,变量更像标签(或者,用C术语来说,指针):它们不是值。它们只是指向实际值。

其他答案中没有阐明这一点,但如果我没记错的话,python中的整数实际上不是原语。它们是不可变的整数对象。因此,当有多个变量都保持值3时,实际上有多个对I的单个实例的引用
c = number("one", 1)
d = c
b = 4
d.number = 2
import copy
c = number("one", 1)
d = c
e = copy.copy(c)

print(c.number, d.number, e.number)
d.number = 2
e.number = 5
print(c.number, d.number, e.number)
1 1 1
2 2 5
>>> x = 1  # x points to the object int(1).
>>> y = x  # So does y.
>>> assert x is y
>>> y = 2
>>> assert x is not y
>>>    
>>> x = []
>>> y = x
>>> assert x is y  # x and y reference the same object.
>>> y.append(0)  # We append 0 to the list that both x and y reference.
>>> x
[0]
>>> y
[0]
>>>
>>> y = [0]  # Creating a new list object.
>>> assert x is not y  # x and y are different objects...
>>> assert x == y  # ...but they are equal.
>>>    
a = 3
b = a

print(a, b)
b=4
c = number("one", 1)
d = c
d.number = 2
a = 3
b = a
c = number("one", 1)
d = c
b = 4
d.number = 2
import copy
d = copy.copy(c)
l = []
a = 1
b = a  
copy.copy(x)
copy.deepcopy(x)
>>> import copy
>>> c = number("one", 1)
>>> d = copy.copy(c)        # Make a copy of object c  
>>> id(d), id(c)
(42898856, 43279384)  
>>> x = 10**50
>>> y = 10**50
>>> z = x
>>> x is y
False
>>> x is z
True