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