对象和基本类型的分配

scd*_*dmb 7 python

有这个代码:

# assignment behaviour for integer
a = b = 0
print a, b # prints 0 0
a = 4
print a, b # prints 4 0 - different!

# assignment behaviour for class object
class Klasa:
    def __init__(self, num):
        self.num = num

a = Klasa(2)
b = a
print a.num, b.num # prints 2 2
a.num = 3
print a.num, b.num # prints 3 3 - the same!
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 为什么赋值运算符对基本类型和类对象的工作方式不同(对于基本类型,它按值复制,对于通过引用复制的类对象)?
  2. 如何只按值复制类对象?
  3. 如何为C++ int&b = a中的基本类型引用?

Nou*_*him 11

这是许多Python用户的绊脚石.对象引用语义与C程序员习惯的不同.

我们来看第一个案例.当你说a = b = 0,int创建一个带有值的新对象,并创建0两个对它的引用(一个是a另一个b).这两个变量指向同一个对象(我们创建的整数).现在,我们跑了a = 4.创建一个新int的有价值对象,4a使其指向该对象.这意味着,引用的数量4是1,引用的数量0减少了一个.

将此与a = 4在C中进行比较,其中a写入"指向" 的存储区域.a = b = 4在C中意味着4写入两个内存 - 一个用于a,另一个用于b.

现在第二种情况,a = Klass(2)创建一个类型的对象Klass,将其引用计数递增1并a指向它.b = a简单地得到什么a指向,b指向同一个东西,并将事物的引用计数递增一.这和你做的一样a = b = Klass(2).由于您要取消引用相同的对象并打印属性值a.num,b.num因此尝试打印并且是相同的.您可以使用id内置函数来查看该对象是相同的(id(a)并且id(b)将返回相同的标识符).现在,您可以通过为其中一个属性赋值来更改对象.因为ab指向同一个对象,所以当通过a或访问对象时,您希望值的变化可见b.这就是它的确切方式.

现在,回答你的问题.

  1. 对于这两者,赋值运算符的工作方式不同.它只是添加对RValue的引用并使LValue指向它.它总是 "通过引用"(虽然这个术语在参数传递的上下文中比在简单的赋值中更有意义).
  2. 如果要复制对象,请使用复制模块.
  3. 正如我在第1点所说,当你完成作业时,你总是转移参考.除非您要求复制,否则永远不会复制.


Abh*_*jit 6

引自数据模型

对象是Python的数据抽象.Python程序中的所有数据都由对象或对象之间的关系表示.(从某种意义上说,并且与Von Neumann的"存储程序计算机"模型一致,代码也由对象表示.)

从Python的角度来看,基本数据类型与C/C++有根本的不同.它用于将C/C++数据类型映射到Python.所以让我们暂时离开讨论,并考虑所有数据都是对象并且是某些类的表现.每个对象都有一个ID(有点像地址),Value和Type.

所有对象都通过引用复制.对于前者

>>> x=20
>>> y=x
>>> id(x)==id(y)
True
>>>
Run Code Online (Sandbox Code Playgroud)

拥有新实例的唯一方法是创建一个实例.

>>> x=3
>>> id(x)==id(y)
False
>>> x==y
False
Run Code Online (Sandbox Code Playgroud)

这可能听起来很复杂,但为了简化一点,Python使一些类型不可变.例如,您无法更改string.您必须将其切片并创建一个新的字符串对象.

通常通过引用复制会给出意外的结果.

x=[[0]*8]*8可能会让你感觉它创建了一个二维的0s 列表.但实际上它创建了一个相同列表对象[0]的引用列表.所以做x [1] [1]最终会同时改变所有重复的实例.

复制模块提供了一个名为deepcopy的创建对象,而不是浅实例的新实例方法.当您打算拥有两个不同的对象并按照您在第二个示例中的预期单独操作时,这非常有用.

扩展你的例子

>>> class Klasa:
    def __init__(self, num):
         self.num = num


>>> a = Klasa(2)
>>> b = copy.deepcopy(a)
>>> print a.num, b.num # prints 2 2
2 2  
>>> a.num = 3
>>> print a.num, b.num # prints 3 3 - different!
3 2
Run Code Online (Sandbox Code Playgroud)