【练习题】第十五章--类和对象(Think Python)

本文深入探讨了Python中对象复制的概念,包括浅复制和深复制的区别。通过实例演示了如何使用copy模块进行对象复制,以及在复制过程中如何避免别名带来的问题。同时,介绍了调试对象属性错误的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

别名有可能让程序读起来有困难,因为在一个位置做出的修改有可能导致另外一个位置发生不可预知的情况。这样也很难去追踪指向一个对象的所有变量。所以就可以不用别名,而用复制对象的方法。copy 模块包含了一个名叫 copy 的函数,可以复制任意对象:

>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0
>>> import copy
>>> p2 = copy.copy(p1)

 

p1和 p2包含的数据是相同的,但并不是同一个点对象。

>>> print_point(p1)
(3, 4)
>>> print_point(p2)
(3, 4)
>>> p1 is p2
False
>>> p1 == p2
False

is 运算符表明 p1和 p2不是同一个对象,这就是我们所预料的。但你可能本想着是==运算符应该得到的是 True 因为这两个点包含的数据是一样的。这样的话你就会很失望地发现对于实例来说,==运算符的默认行为就跟 is 运算符是一样的;它也还是检查对象的身份,而不是对象的相等性。这是因为你用的是用户自定义的类型,Python 不值得如何去衡量是否相等。至少是现在还不能。

(译者注:==运算符的实现需要运算符重载,也就是多态的一种,来实现,也就是对用户自定义类型,需要用户自定义运算符,而不能简单地继续用内置运算符。因为自定义类型的运算是 Python 没法确定的,得用户自己来确定。)

如果你用 copy.copy 复制了一个矩形,你会发现该函数复制了矩形对象,但没有复制内嵌的点对象,所以里面点的指向是同一个对象。

>>> box2 = copy.copy(box)
>>> box2 is box
False
>>> box2.corner is box.corner
True

这种运算叫做浅复制,因为复制了对象与对象内包含的所有引用,但不复制内嵌的对象。 

所幸的是 copy 模块还提供了一个名为 deepcopy (深复制)的方法,这样就能把内嵌的对象也复制了。你肯定不会奇怪了,这种运算就叫深复制了。

>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False

box3和 box 就是完全隔绝开,没有公用内嵌对象,彻底不会相互干扰的两个对象了。

调试:

当你开始使用对象的时候,你就容易遇到一些新的异常。如果你试图读取一个不存在的属性,就会得到一个属性错误AttributeError:

>>> p = Point()
>>> p.x = 3
>>> p.y = 4
>>> p.z
AttributeError: Point instance has no attribute 'z'

如果不确定一个对象是什么类型,可以『问』一下:

>>> type(p)
<class '__main__.Point'>

还可以用 isinstance 函数来检查一下一个对象是否为某一个类的实例:

>>> isinstance(p, Point)
True

如果不确定某一对象是否有一个特定的属性,可以用内置函数 hasattr:

>>> hasattr(p, 'x')
True
>>> hasattr(p, 'z')
False

hasattr 的第一个参数可以是任意一个对象;第二个参数是一个字符串,就是要判断是否存在的属性名字。

用 try 语句也可以试验一个对象是否有你需要的属性:

try:
    x = p.x
except AttributeError:
    x = 0

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值