Summary
本章主要详细介绍了Python的动态数据类型(Dynamic Typing)。之所以将这个概念单独拎出来说是因为作者认为Dynamic Typing是Python灵活性的根,是Python语言多态性的必要条件。
Dynamic Typing这一特性的直接表现就是你无需在使用变量前声明数据类型,只要在使用前给变量赋值就可以了。在这一过程中,Python底层主要做了下面几件事:
- 建立变量名。从技术层面讲,Python会在运行代码前探测一些变量名,但是在这里我们可以理解成赋值时的一个步骤。
- 在内存里建立对象(Object)。数据类型是一直跟着Object的,而跟变量名无关。因此一个变量名可以前后被赋很多个不同类型的值
- References,也其实就是C里的指针,将变量名指向对应的对象。
跟大多数高级语言一样Python也是有Garbage Collection机制。当内存里的某个对象已经不再被任何变量引用,那它就会被“回收”。其实也就是标记为此空间可用,之后在需要用空间的时候这块空间就能被再次利用。
那既然Python的变量、对象体系是这样的一个构造,我们势必可以想到多个变量可以共享同一个对象。代码的实现其实很简单:
>>> b = a
指针共享那就带来另一个问题,就是数据的正直完整性,即当a的值改变,b会不会也改变。这就需要分两种情况讨论。我之前在介绍各种Python内建类型时说到过Python下有可变性和不可变性的区别。比如整数、字符串就是不可变的,而list、dictionary就是可变的。
对于不可变数据类型,改变其值时,实际上Python会建立个新的对象并用新的指针指向新对象。因此遇到共享指针的情况时,其他的变量不会因为当中的一个变量改变而改变。如图:

对于可变数据类型,改变其值时,对象的内部值会改变,但是指针不变,于是共享指针的其他变量也会因此而改变其值。如下:
>>> L2 = L1 # Make a reference to the same object
>>> L1[0] = 24 # An in-place change
>>> L1 # L1 is different
[24, 3, 4]
>>> L2 # But so is L2!
[24, 3, 4]
当然,我们有时候也会遇到想要想让可变类型不影响到其他共用指针的变量的情况,作者提供了两种方法,但其实是同一种思路的不同实现。思路就是复制对象。一种是用list的切割(连续型的变量都能用这种切割方式)
>>> L2 = L1[:] # Make a copy of L1
一种是用Python自带的copy():
X = copy.copy(Y) # Make top-level "shallow" copy of any object Y
X = copy.deepcopy(Y) # Make deep copy of any object Y: copy all nested parts
有必要强调一下的是比较变量的值和比较变量所指向的对象,看他们是否一样,看代码:
>>> M = [1, 2, 3] # M and L reference different objects
>>> L == M # Same values
True
>>> L is M # Different objects
False
最后就是Python对一些小整数和小字符串都采用共享对象的方法,我想这样更加高效地利用内存吧:
>>> Y = 42 # Should be two different objects
>>> X == Y
True
>>> X is Y # Same object anyhow: caching at work!
True
Quiz
1. Consider the following three statements. Do they change the value printed for A?
A = “spam”
B = A
B = “shrubbery”
No.
2. Consider these three statements. Do they change the printed value of A?
A = [“spam”]
B = A
B[0] = “shrubbery”
Yes.
3. How about these—is A changed now?
A = [“spam”]
B = A[:]
B[0] = “shrubbery”
No.
–EOF–

Pingback: [Learning Python 4th Edition] 重定义 | conanBlog.me();