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

别名有可能让程序读起来有困难,因为在一个位置做出的修改有可能导致另外一个位置发生不可预知的情况。这样也很难去追踪指向一个对象的所有变量。所以就可以不用别名,而用复制对象的方法。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

猜你喜欢

转载自blog.csdn.net/qq_29567851/article/details/83589010