第10章 Python进阶话题
10.1 函数与命名空间
Python中可以通过模块来管理复杂的程序,而将不同功能的函数分布在不同的模块中,那么函数及其全局命名空间决定了函数中引用全局变量的值。函数的全局命名空间始终是定义该函数的模块,而不是调用该函数的命名空间。因此,在函数中引用的全局变量始终是定义该函数模块中的全局变量。
注意要分清函数全局命名空间(定义的模块)与引用的模块之间的关系。
10.2 闭包及其应用
闭包是Python语言中一种特殊的语法现象,使用闭包可以灵活地实现用其他语法不太容易实现的一些功能,比如实现延迟求值和定义泛型函数功能的实现。
10.2.1 闭包概述
闭包是指Python语言中将组成函数的语句和这些语句的执行环境打包到一起所得到的对象。当使用嵌套函数(函数中定义函数)时,闭包将捕获内部函数执行所需的整个环境。此外,嵌套的函数可以使用被嵌套函数中的任何变量,就像普通函数可以引用全局变量一样,而不需要通过参数引入。
>>> x=14 #全局变量x
>>> def foo(): #定义函数(嵌套的外层函数)
... x = 3
... def bar(): #定义函数(嵌套的内层函数)
... print('x is %d' % x) #引用变量x (实际引用的是嵌套的外层函数中的
... bar() #调用嵌套的内层函数
...
>>> if __name__ == '__main__':
... foo()
...
x is 3
>>>
10.2.2 闭包与延迟求值
闭包可以实现先将参数传递给一个函数,而并不立即运行,以达到延迟求值的目的。
>>> def delay_fun(x,y):
... def caculator():
... return x+y
... return caculator
...
>>> if __name__ == '__main__':
... print('返回一个求和函数, 并不求和。')
... msum = delay_fun(3,4)
... print()
... print('调用并求和: ')
... print(msum())
...
返回一个求和函数, 并不求和。
调用并求和:
7
>>>
注意 所谓延迟求值,就是函数返回的是一个函数,而真正需要运行函数中的代码时,其本质还是函数调用。
10.2.3 闭包与泛型函数
闭包的应用除了在装饰器和延迟求值外,还可以利用其特性来定义不同的泛型函数。
>>> def line(a,b):
... def aline(x):
... return a*x + b
... return aline
...
>>> if __name__ == '__main__':
... line23 = lline(2,3)
... line50 = line(5,0)
KeyboardInterrupt
>>> if __name__ == '__main__':
... line23 = line(2,3)
... line50 = line(5,0)
... print(line23(4))
... print(line50(2))
...
11
10
>>>
10.3 上下文管理器
上下文管理器是指实现上下文管理协议方法的对象,它主要用于安全地释放资源(如打开的文件、数据库连接或网络连接、对对象的锁定等);对于上下文管理器对象可以使用with语句来使用它,在with语句中可以使用上下文管理器管理或提供资源,当退出with语句时,由上下文管理器来负责安全地释放资源。
注意 上下文管理器的作用是方便资源管理的一种语法形式。
10.4 用字符串操作对象属性
注意设置类属性时就使用类名进行设置。
注意用字符串操作对象属性,一般在框架的编程中应用比较广泛。一般的编程中,应尽量通过调用类的方法来操纵类的数据。
10.5 用字典构造分支程序
一般来说,分支程序一般要用if语句来写,在Python语言中,函数也是对象,而且是顶层对象,可以作为参数传入并调用的。因此,你可以把它作为数据项放入字典中,并以键值来作为调用(分支)的标志。
注意 用字典构造分支程序虽然可行,但给阅读和理解程序带来麻烦,请慎用。
10.6 重载类的特殊方法
10.7 鸭子类型(duck typing)与 多态
注意鸭子类型虽然方便了使用,但在编程时应给出明确的说明,防止调用错误。
10.8 小结
10.9 本章习题