status

草稿

HuangYi

30%

1. Python 大统一理论

1.1. 对象 名字与绑定

python 中有一条不成文的定律,那就是*万物皆对象*!不光是大家熟悉的实例对象是对象,连类、模块、包这些,甚至包括基本的数值类型,都被一视同仁,当作对象看待。不再有值类型与引用类型的区别,也不再需要什么 boxing/unboxing 的操作。

为了方便说明,在 python 中我们换几个术语,我们把变量叫做*名字*,把变量与对象之间的关系叫做*绑定*(你也可以把它简单地理解为指针或引用)!名字与绑定这两个词语能够更准确得表达出 python 的特点,在这里,所谓变量就只是单纯的名字而已,它没有类型,也没有更多其他的意义。我们可以把名字绑定到任意的对象,也可以随时改变主意,把它绑定到另外的对象。

程序员总是通过名字对对象进行操纵。而没有名字的对象那肯定是内存泄露了,不过不用担心,Python 会自动回收掉那些没有名字的家伙 ;-)

1.2. 名字空间

介绍完名字与对象的关系,我们要开始介绍 python 对名字的管理了,这就是所谓的*名字空间*。

python 程序中任何一个名字都存在于某一个名字空间之中。对于一个普通 python 函数来说,只存在着三层嵌套的名字空间,由里而外分别为局部名字空间、全局名字空间、内置名字空间。不过对于嵌套函数或是嵌套类来说,就不止三层了,每一层嵌套都是多一层名字空间。

内置函数 locals() 总是返回当前名字空间的内容,globals() 函数则返回全局名字空间的内容,如果你想看内置名字空间的内容,你可以试试这个: __builtins__.__dict__

   1 >>> global_name = 1
   2 >>> def foo():
   3 ...     local_name = 2
   4 ...     print '全局名字空间:'
   5 ...     print globals()
   6 ...     print '局部名字空间:'
   7 ...     print locals()
   8 ...
   9 >>> foo()
  10 
  11 {'global_name': 1, 'foo': <function foo at 0x00B4C0B0>, ...}
  12 
  13 {'local_name': 2}
  14 >>> def foo():
  15 ...     foo_name = 2
  16 ...     def bar():
  17 ...         bar_name = 3
  18 ...         print 'bar名字空间:'
  19 ...         print locals()
  20 ...     print 'foo名字空间:'
  21 ...     print locals()
  22 ...     bar()
  23 ...
  24 >>> foo()
  25 foo
  26 {'foo_name': 2, 'bar': <function bar at 0x00B4C130>}
  27 bar
  28 {'bar_name': 3}

聪明的你也许已经从代码中看出来了,函数的定义建立了一个函数名与函数对象绑定。实际上绑定名字的办法不光只有普通的赋值,定义类、定义函数的时候也在发生着名字绑定,甚至 forwhileexcept 等这些流程控制语句中也都发生着名字绑定。

   1 >>> class FooBar(object):
   2 ...     pass
   3 ...
   4 >>> def foo_bar():
   5 ...     pass
   6 ...
   7 >>> locals()
   8 {'foo_bar': <function foo_bar at 0x00B4C0B0>, 'FooBar': class '__main__.FooBar'>, ... }

绑定一个名字的时候,默认总是绑定当前名字空间中的名字,如果名字不存在则创建新名字。不过你可以使用 global 关键字来显示指定该名字所在名字空间为全局名字空间。(TODO:Python3000 的 nonlocal)

不过当读取一个名字——即通过名字获取其绑定的对象——时,默认则总是从当前名字空间开始向外进行查找。当然你仍然可以使用 global 关键字来显式指明该名字存在于全局名字空间,这样可以免去查找的过程了。

   1 >>> a = 'global'
   2 >>> def foo():
   3 ...     a = 'foo' # 在 foo 名字空间中创建名字 a
   4 ...     def bar():
   5 ...         # 输出来自 foo 名字空间的名字 a
   6 ...         print a
   7 ...     bar()
   8 ...
   9 >>> foo()
  10 foo
  11 >>> def foo():
  12 ...     a = 'foo' # 在 foo 名字空间中创建名字 a
  13 ...     def bar():
  14 ...         global a # 显示指定名字 a 处于全局名字空间之中
  15 ...         # 输出来自全局名字空间的名字 a
  16 ...         print a
  17 ...     bar()
  18 ...
  19 >>> foo()
  20 global

其实当我们把视野放大,把程序看作是一个个的模块,就会发现所谓全局名字空间其实并不是全局的,而只是模块级的,所以我们也常把它叫做模块级名字空间。内置名字空间才是真正是全局的名字空间。

1.3. 对象可变性

现在传值还是传引用这个经典问题不复存在了,但 c程序员却要发问了:

   1 >>> a=1
   2 >>> b=a
   3 >>> a+=1
   4 >>> a
   5 2
   6 >>> b
   7 1

既然 a、b 两个名字绑定着同一个对象(整数1),那么当通过名字 a 修改(加1)了该对象之后,为何 b 所绑定的对象却还是 1 呢?

这就涉及到了 python 对象的两个派别:可变对象与不可变对象。不可变就是不可以修改的意思。对于任何修改不可变对象的意图,或者是抛出异常,或者就是返回一个新的对象。整数便是属于不可变对象这一派的。

   1 >>> a=b=1
   2 >>> a+=1
   3 >>> id(a)==id(b)
   4 False

由此可见,名字 a、b 所绑定的已不是同一个对象了。这一派的对象还包括:字符串(str)、元组(tuple) 等。

   1 >>> a=b='hello'
   2 >>> a[0]='a'
   3 Traceback (most recent call last):
   4   File "<stdin>", line 1, in ?
   5 TypeError: object does not support item assignment
   6 >>> a+='hello'
   7 >>> id(a)==id(b)
   8 False

1.4. 类型与对象

介绍完“万物皆对象”的理论,我们要引入第二条定律了,那就是“每一个对象都有类型”。

类型这个概念想必大家不会陌生,几乎所有的程序设计语言中都有类型这个概念,然而类型与类型是不同的,Python 独特的类型系统是其灵活性与强大力量的重要来源。

...

1.4.1. 所谓 Duck Typing

如果一个东西看起来像鸭子,走起来像鸭子,叫起来也像鸭子,那它就是个鸭子。

2. 讨论

Name Password4deL ;) :( X-( B-)