转载请注明: TheViper http://www.cnblogs.com/TheViper
变量,对象和引用
在python中,类型是在运行过程中自动决定的,而不是通过代码声明。这意味着没有必要事先声明变量。
a=3解析的过程:
- 变量创建:这里的变量a,当代码第一次给它赋值时就创建了它,之后的赋值将会已创建的变量的值。
- 变量类型:变量永远不会有任何和它关联的类型信息或约束。类型的概念存在于对象中而不是变量。变量原本是通用的,它只是在一个特定的时间点,简单的引用了一个特定的对象而已。
- 变量使用:当变量出现在表达式中,它马上被当前引用的对象所替代,无论这个对象是什么类型。注意,所有变量必须在其使用前明确的赋值。
总之,变量在赋值的时候才创建,它可以引用任何类型的对象,并且必须在引用前赋值。
上面的代码的赋值操作:
- 创建一个对象(这里是数字)代表值3.
- 创建一个变量a,如果它还没有创建的话。
- 将变量与新对象3连接。
如上图所示,变量和对象保存在内存的不同部分,它们通过连接相关联(图中箭头)。
具体的,在运行a=3后,变量a变成对象3的一个引用。在内部,变量事实上是到对象内存空间(通过运行常量表达式3创建)的一个指针。
以具体的术语来讲,
- 变量是系统表的元素,拥有指向对象的连接空间。
- 对象是分配的一块内存,有足够的空间表示它所代表的值。
- 引用是自动形成的从变量到对象的指针。
事实上,python并不是对创建的所有对象都会重新申请新的一块内存空间。作为一种优化,python会缓存不变的对象(如数值较小的数字,字符串,元组等)并对其进行复用。
类型属于对象,而不是变量
a=3 a=‘viper‘ a=1.333
变量a刚开始是整数,然后是字符串,最后是浮点数,但是这段代码可以运行。这是因为,在python中,情况很简单,变量名没有类型。
上面的代码,我们只是把变量a修改为对不同对象的引用,从而让变量a引用了不同类型的对象而已。
共享引用
a=3 b=a
可以看到变量a,b引用了同一个对象。这时,让变量a引用另一个对象。
a=3 b=a a=‘viper‘
a=‘viper‘创建了一个新的对象‘viper’,并让变量a对这个新对象引用,而变量b仍然引用原来的对象3.所以这时变量b的值是3.
共享引用和在原处修改
有一些对象和操作确实会在原处改变对象,例如,在一个列表中对一个偏移赋值就会改变这个列表对象,而不是生成一个新的列表对象。对于这种可以在原处修改的对象,共享引用的时候要小心,因为对一个变量名的修改会影响其他和它引用同一对象的变量。
L1=[1,2,3] L2=L1 L1[0]=33
这时变量L1,L2的值都会变成[33,2,3].
这种行为通常不是我们想要的,但是这种行为是默认的,如果不想这种行为发生,就需要拷贝对象,而不是创建引用。
L1=[1,2,3] L2=L1[:] L1[0]=‘viper‘ print(L2)# [1,2,3]
因为L2引用的是L1引用对象的一个拷贝,这里两个变量指向不同的内存区域。所以L1的改变不会影响L2.
注意上面用到了分片,其他的有些可变的核心类型(如字典,集合)不能分片,这时就使用copy()方法。
共享对象和相等
由于python的引用模型,在python程序中有两种不同的方法检查是否相等。==和is
==检查两个被引用的对象是否拥有相同的值,这种方法被用作相等的检查。
is会比较实现引用的指针,是检测共享引用的一种方法。如果变量的引用值相等,但是是不同的对象,那is就返回false.比如,
变量M和L虽然值相同,但它们两个不同的对象,在不同的内存区域。
另外
这个验证了前面说的 python会缓存不变的对象(如数值较小的数字,字符串,元组等)并对其进行复用。y=3只是让变量y引用已经创建的对象3.