1 关于内存管理的那些事(is VS ==)
首先,变量类型分为一下两个大类。
可变类型,值可以改变:
- 列表 list
- 字典 dict
不可变类型,值不可以改变:
- 数值类型 int, long, float
- 布尔类型 bool
- 字符串 str
- 元组 tuple
1-1 怎么体现是可变/不可变的类型呢?
背景:在python中通过 = 复制的变量,都是同时即把变量的值,也把变量在内存中的地址复制也过去了(这样的说法不是绝对正确的,在命令行中不是通用的)。即 = 复制过的变量不仅内存地址一样,变量的值也一样。但是需要注意的是:对于不可变类型(如 int)的变量,如果要更改变量的值,则会创建一个新值,并且给这个新值分配一个新的内存地址,然后把变量指向这个新值的内存地址上,而旧值如果没有被引用就等待垃圾回收。如果是可变类型变量,若修改变量的值,则可以直接修改变量的值,变量的引用地址不会变。
不可变类型 注意 python 中创建两个内容一样的变量时(变量名不一样),一般都会在内存中分配两个内存地址分别给这两个变量。即两个变量的内容虽然一样,但是变量的引用地址不一样。所以两个变量使用 == 比较成立,但是使用 is 比较不成立。这里有两个特例,小整数和 str,稍后会详细介绍。
以 int 类型为例,当创建完对象后,内存就不可变。所以当要改变值的时候,只能另辟一块内存来存储新计算出来的值。而之前开辟的内存里存储的值不变。
下面代码中 b 的值和地址都没变,也没有随着 a 的值改变而改变,就是这个道理。b 仍指向原来的内存,而 a 指向新的内存。
a = 10
b = a
print(a, id(a), b, id(b))
a += 2
print(a, id(a), b, id(b))
输出:
10 4310353248 10 4310353248
12 4310353312 10 4310353248
可变类型 以列表为代表,内存是可扩充的。因此,当 list1 改变时,是在本来的内存上扩充的,list1 和 list2 仍指向原来的内存。
list1 = ['a']
list2 = list1
print(list1, id(list1), list2, id(list2))
list1.append('b')
print(list1, id(list1), list2, id(list2))
输出:
['a'] 4342566728 ['a'] 4342566728
['a', 'b'] 4342566728 ['a', 'b'] 4342566728
1-2 体现在 is 和 == 上,是什么情况呢?
- == 判断 内容/值是否相同
- is 判断内容/值是否相同 && 内存地址是否相同
所以相应的,对于可变类型,因为赋值时给的是引用,内存大小可以随着值的变化而自动扩容,所以无论是 == 还是 is 都是 True。对于不可变类型,在 PyCharm 中,只要是 == 判定为 True 的,一般 is 也会判定为 True。为什么有个 PyCharm 的前提呢?那就接着往下看吧。
1-3 特例一:使用 is 时注意 python 对于小整数使用对象池存储问题
注意,因为 python 对小整数在内存中直接创建了一份,不会回收。因此所有创建的小整数变量直接从对象池中引用即可。
但是注意 python 仅仅对比较小的整数对象进行缓存(范围 [-5, 256]
)缓存起来,而并非是所有整数对象。也就说只有在这个 [-5,256] 范围内创建的变量值使用 is
比较时候才会成立。
>>> a = 10
>>> b = 10
>>> c is d
True
>>> c = 1000
>>> d = 1000
>>> c is d
False
>>> e ,d ,f ,g = -5 ,-5 ,-6 ,-6
>>> e is d
True
>>> f is g #超过-5的范围不成立
False
注意:上面对于 python 小整数对象池的使用仅仅是在命令行
中执行可以,而在 Pycharm/保存为文件 执行,结果是不一样的,这是因为解释器做了一部分优化。即在使用pycharm时,即使整数超过 256,使用 is 也是成立的。
1-4 特例二:使用 is 时注意 python 关于字符串的 intern 机制存储
python 中虽然字符串对象也是不可变对象,但 python 有个 intern 机制,简单说就是维护一个字典,这个字典维护已经创建字符 (key) 和它的字符串对象的地址 (value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了。相当于 python 对于字符串也是采用了对象池原理。
但是注意:如果字符串(含有空格),不可修改,没开启intern机制,不共用对象。比如"a b"和"a b"。
同样地,这种情况使用 is 不成立的形式只有在命令行
中可以。使用pycharm 同样是 True,因为做了优化。
>>> s1, s2 = 'abc', 'abc'
>>> s1 is s2
True
>>> s1, s2 = 'a b', 'a b'
>>> s1 is s2
False
PS. 本小节参考了 Python中is与==的使用区别详解
2 matplotilb.pyplot 与 pylab 的联系与区别
根据 pyplot 源码 pyplot.py 中的解释部分就可得知:
matplotlib.pylab combines pyplot with numpy into a single namespace.
This is convenient for interactive work, but for programming it is recommended that the namespaces be kept separate.
意思就是说 pylab 结合了 pyplot 和 numpy,对交互式使用来说比较方便,既可以画图又可以进行简单的计算。但是,对于一个项目来说,建议分别倒入使用,即:
import numpy as np
import matplotlib.pyplot as plt
而不是
import pylab as pl
附在使用matplotlib及相关模块时可能用得上的资料网址:
- Matplotlib.pdf http://matplotlib.org/Matplotlib.pdf
- Python科学计算 http://hyry.dip.jp/tech/book/page/scipy/matplotlib.html
网友评论