python学习手册:学习笔记4--The Dynamic Typing Interlude

为什么80%的码农都做不了架构师?>>>   hot3.png

    对于Python来说,当写下:

a = 3
时候,Python如何知道a是代表一个整型呢?实际上Python并不知道,但是Python是运行时候自动进行匹配的,所以运行时候就知道a是整型.这跟C++的RTTI差不多,类似模板的技术.

变量,对象和引用

    变量通常关联三个步骤:1.变量创建,当你第一次对变量进行赋值时候,变量被创建(非赋值而使用变量,则会产生异常). 2.变量类型,变量通常是没有类型的,它关联到整型,则它就是整型,它关联到字符串型,则它就是字符串型. 3.变量使用,只要变量被赋值,那么它就可以被使用.

    但是这里有一个至关重要的概念:引用

>>> a = 3
>>> id(a)
33120312L
>>> a = 4
>>> id(a)
33120288L
    这里a = 3,实际上是将变量a指向了 对象3,而如果我们重新给a赋值4,则会发现其id已经改变(因为3和4是不同的两个对象).可形象化的表示如下:

python学习手册:学习笔记4--The Dynamic Typing Interlude_第1张图片

可用以下三个步骤解释上图:

1. 变量进入系统表,用于存储一个链接指向对象.

2. 对象存在于所分配的内存中.

3. 引用自动关联其变量和对象.

类型存活于对象之中,而非变量

    我们可以使用如下的代码轻而易举的说明:为什么类型存活于对象之中,而非变量:

>>> a = 3
>>> id(a)
33120312L
>>> a = 'spam'
>>> id(a)
39014152L
>>> a = 1.23
>>> id(a)
35872888L
对象是垃圾收集的

    Python是使用引用计数方式来进行垃圾收集.例如上例中当a重新被赋值'spam'时候,由于对象3的引用计数从1到0(给a赋值3时候3的引用计数加1),所以自动进行了垃圾回收.

    但是有个问题是:如果Python中发生,两个对象互相引用,那么引用计数的方式是否会失效?还是Python本身也可以使用"离开作用域则对象失效"的垃圾收集方式.

    这确实无法避免(互相引用),所以有些Python实现使用了"离开作用域则进行变量销毁"的垃圾收集机制.

共享引用

    当我们执行以下代码的时候,就产生了对象的共享:

>>> a = 3
>>> b = a
>>> id(a), id(b)
(33120312L, 33120312L)
用流程图表示如下:

python学习手册:学习笔记4--The Dynamic Typing Interlude_第2张图片

    但是,当我们执行以下代码的时候,对象改变了:

>>> a = 3
>>> b = a
>>> a = 'spam'
>>> id(a), id(b)
(41457024L, 33120312L)

流程图如下:

python学习手册:学习笔记4--The Dynamic Typing Interlude_第3张图片

这里我们是将a指向了新的对象.但是如果a和b本身所指向的对象是可改变的,则会产生Python中著名的"浅拷贝和深拷贝"问题:

>>> person = ["name", ["savings", 100.00]]
>>> hubby = person[:]
>>> wifey = list(person)
>>> [id(x) for x in (person,hubby,wifey)]
[40895560L, 40894920L, 40889032L]
>>> hubby[0] = "joe"
>>> wifey[0] = "jane"
>>> hubby, wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby, wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 50.0]])
    而一般这时候,我们需要的是深拷贝:
>>> person = ["name", ["savings", 100.00]]
>>> hubby = person
>>> import copy
>>> wifey = copy.deepcopy(person)
>>> [id(x) for x in (person, hubby, wifey)]
[40889608L, 40889608L, 40863624L]
>>> hubby[0] = "joe"
>>> wifey[0] = "jane"
>>> hubby, wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby, wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])
备注:所谓的深拷贝,就是不同对象具有相同的值而已(值的对象也不同)

共享引用和相等

    对于垃圾回收来说,如果回收的对象不可改变(如整型,集合,字符串等等,这里以42举例),则Python解释器一般不回收,而让42一直存在于系统表中直到重新被赋值.

    Python中有两种判断的方法:==和is.==等于号用于判断两个对象的值是否相等,而is用来判断两个对象是否属于同一个对象类型:

>>> L = [1, 2, 3]
>>> M = L
>>> L == M
True
>>> L is M
True
    但是,当L和M指向不同的可改变对象时候,情况就不一样了:
>>> L = [1, 2, 3]
>>> M = [1, 2, 3]
>>> L == M
True
>>> L is M
False
    而下列代码恰恰说明了不可改变对象通常并没有被回收:
>>> X = 42
>>> Y = 42
>>> X == Y
True
>>> X is Y
True
    而我们可以通过方法getrefcount来查看对象被引用的次数:
>>> import sys
>>> sys.getrefcount(42)
13


转载于:https://my.oschina.net/voler/blog/378661

你可能感兴趣的:(python学习手册:学习笔记4--The Dynamic Typing Interlude)