Python特性

来自KlniuWiki
跳转到: 导航, 搜索

目录

1 动态类型

Python并不声明对象的类型,当在运行时,类型才被解释器判断,变量会自动成为其被指定的类型而使用,这也是其灵活性与方便的一种体现。

Python在声明一个变量时,例如 a = 3, 会执行以下三步:

  1. 生成一个对象来表示数值3;
  2. 当变量a不存在时,生成变量a;
  3. 把变量a与第一步的对象连接起来,也可以说,变量a现在是上述对象的一个引用。

因此,可以说,类型是随着对象的存在而存在的,而不是变量,变量只是在合适的时间表现出不同的类型而已,如下例,变量随着被赋值的不同而表现不同的类型:

a = 3             # It's an integer
a = 'spam'        # Now it's a string
a = 1.23          # Now it's a floating point

2 内存回收

Python的数据类型是动态的,不像其他静态语言一样,如果是C++或C,就会出现内存泄漏的情况,那Python是如何回收内存呢?

Python的类型只与对象相关联,变量只是一个引用,而这个引用就存在与对象之中,对象里面有一个计数器,表示了指向这个对象的引用,如果一个对象的所有引用都指向别的对象或者被删除,那么这个对象的计数器就会被置0,系统就会回收这部分内存了。

3 共享引用

因为Python是类型独立的,与变量无关,因此就会出现以下这种情况:

a = 3
b = a             # 3
a = 1.23          # Now it's a floating point
b                 # 仍然是3
b = a             # 1.23
a = a + 2         # a is 3.23, a指向了一个新的对象
b                 # 仍然是1.23

变量始终指向对象,而不是它被赋值时的引用。另外需要注意一点的是,上面代码里的数值3, 1.23, 3.23都是不可改变的(immutable),也就是说,不能通过变量对这个对象进行覆盖,a = a + 2只是使a指向了一个新的对象。这也引出的一个值的可变性的话题,请查看#数值的可变性(mutable or immutable)

但对于可变类型的数据,比如list, dict, set等,却是可以通过该类型数据允许的方法修改的,也就是说,修改这个对象并不是在内存里新开辟一个区域,而是在原区域更改的,这就是可修改的数据。 当然,如果将L1直接赋值另一类型的对象,那么,L2指向的仍然是原list对象,如:

L1 = [2, 3 ,4]
L2 = L1
L2              # [2, 3, 4]
L1 = 1
L2              # [2, 3, 4]

使用list的方法修改list,就会产生覆盖了:

L1 = [2, 3, 4]        # A mutable object
L2 = L1               # Make a reference to the same object
L1[0] = 24            # An in-place change
L1                    # [24, 3, 4], L1 is different
L2                    # [24, 3, 4], But so is L2!

上面的代码,L1修改了list的值,L2的值也跟着改变了,因为list是可修改的,它是原来的对象,并不是新的对象。

如果要避免L2被修改,可以通过拷贝对象的方法,有两种方法:

切片,切片只能应用于list,对dict和set是无效的:

L1 = [2, 3, 4]
L2 = L1[:]            # Make a copy of L1
L1[0] = 24
L1                    # [24, 3, 4]
L2                    # [2, 3, 4], L2 is not changed

拷贝,可应用于任何可修改对象:

import 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

4 共享引用与相等性测试

Python有两个相等的测试符,一个是==,一个是is,前者是值的测试,也就是值相等就会返回true,后者是对象的测试,只有两者指向相同的对象才返回true。

L = [1, 2, 3]
M = [1, 2, 3]         # M and L reference different objects
L == M                # True, Same values
L is M                # False, Different objects

但例外的情况时有发生:

X = 42
Y = 42                # Should be two different objects
X == Y                # True
X is Y                # True, Same object anyhow: caching at work!

为什么对第一段代码好用的情况,在第二段代码却不好用了呢?呵呵,源于Python的cache技术,Python会对一些小的整数或者字符串放入缓存中,以备之后使用,这样可以提高效率,因此,有时即使一个对象的所有引用都消失了,这个对象仍有可能存在于内存之中,回到上例,此处Python的缓存就起作用了,它们直接指向了相同的对象。

另外我们可以使用sys.getrefcount方法查看一个对象有多少引用,但此处并不是仅在你所运行的脚本或对象里,而是你所运行的程序的整个进程里:

import sys
sys.getrefcount('klniu')    # 3, 3 pointers to this shared piece of memory

5 数值的可变性(mutable or immutable)


条目内容不完整,待编……

6 参考文献

  • Mark Lutz. Learning Python, Fourth Edition[M]. United States of America:Newgen North America,2009.09.[2011-08-10]. ISBN:978-0-596-15806-4.
个人工具
分类
化学
[×] 國學
学佛
[×] 数学
物理
生活
[×] 英语
读书
辞典
廣告