0. 前言
参考资料:
《流畅的Python》第五、六、七章 《Python Cookbook》第七、九章 《深入理解Python特性》第三章 TODO(目前不太关心的):
1. 函数
1.1. 基本概念
(编程语言中的)一等对象:运行时创建、能赋值给变量或数据结构中的元素、能作为参数传给函数、能作为函数返回结果。 函数是一等对象。
高阶函数:接受函数作为参数,或把函数作为结果返回的函数。 函数对象及其名称是相互独立的实体,换句话说,指向函数的变量和函数本身实际上是彼此独立的。 闭包 :
即词法闭包,在程序流不在闭包范围内的情况下,也能记住封闭作用域中的值。 内部函数不仅可以从父函数返回,还可以捕获并携带父函数的某些状态。 普通对象也可以作为函数使用,即有些对象不是函数,也可以调用。
实现方式:实现__call__
方法。 其他:Python内置函数 callable
用于检查一个对象是否可以调用。 可调用函数包括:用于定义的函数、内置函数、内置方法、方法、类、类的实例、生成器函数。
1.2. lambda 表达式
作用:快速声明小型匿名函数,根据功能也有人称之为单表达式函数 。
匿名函数:猜测就是没有函数名的函数。 与匿名函数相对的是具名函数 。 lambda只是语法糖。 实例:(lambda x, y: x+y)(5, 3)
使用场景:
可迭代对象进行排序时,使用lambda表达式定义简短的key函数,如 sorted(ruples, key=lambda x: x[1])
其他好像推荐用得比较少。 注意事项:
不应过度使用 lambda。 使用前总是先问问自己:使用普通具名函数或列表解析式是否更加清晰。 在匿名函数中绑定变量的值:
x = 10
a = labmda y: x + y
x = 20
b = lambda y: x + y
a( 10 )
b( 10 )
x = 10
a = labmda y, x= x: x + y
x = 20
b = lambda y, x= x: x + y
a( 10 )
b( 10 )
1.3. * 和 **
作为函数参数时,经常使用*args
和**kwargs
这两种形式,功能是让函数接受可选 参数,使得代码更灵活。
args和kwargs只是约定俗成的名称,可以修改。 *args
获取的对象是元组,**kwargs
获取的对象是字典。 可用于解包
*
可用于解包序列。**
可用于解包字典。高效参数解包有助于模块和函数编写更灵活。 以*
打头的参数只能作为最后一个位置参数,但可以存在其他参数;以**
打头的参数只能作为最后一个参数出现。
单独的星号可以作为分隔符,用于分隔位置参数与命名关键字参数。
1.4. 变量作用域
从作用域角度看,变量分为局部变量和全局变量。 函数内部出现的变量默认为局部变量。
如果同名局部变量不存在,且存在同名全局变量,也不会直接调用全局变量。 如果想在局部作用域中使用全局变量,必须在局部作用域中先使用global
关键字声明全局变量
a = 1
b = 2
def f ( ) :
c = 3
global b
print ( a)
print ( b)
print ( c)
2. 装饰器
2.1. 基本概念
作用:
用来临时扩展和修改可调用对象(函数、方法、类)的行为,同时又不会永久修改可调用对象本身。 将通用功能应用到现有的类或函数的行为上。 应用举例:日志、访问控制与授权、计算执行时间、限制请求速率、缓存。 本质:
定义内部函数,扩充原函数的功能,并替代原函数。 装饰器就是语法糖,简化上述过程。 多装饰器修饰应用顺序从下到上,可称为装饰器栈 。
2.2. 基本形式举例
2.2.1 形式一:最简单的装饰器,不实现任何功能。
该装饰器不能实现任何功能,只是用于帮助理解装饰器本质。 从该实例可以看出,装饰器其实就是语法糖。
def null_decorator ( func) :
return func
@null_decorator
def greet ( ) :
return 'Hello!'
def greet ( ) :
return 'Hello!'
greet = null_decorator( greet)
2.2.2. 形式二:装饰器的基本形式。
实际起作用的装饰器形式如下。 从该实例中可以参数,基本装饰器就是定义内部函数,通过内部函数来扩充源函数的功能。 通常,装饰器会把函数替换成另一个函数。
def uppercase ( func) :
def wrapper ( ) :
original_result = func( )
modified_result = original_result. upper( )
return modified_result
return wrapper
@uppercase
def greet ( ) :
return 'Hello!'
2.2.3. 形式三:参数化装饰器。
直观的看,所谓参数化装饰器,其实就是定义了内部函数的内部函数。 另外一种理解参数化装饰器,其实就是构建一个装饰器工厂函数,把参数传给它,返回一个装饰器。
registry = set ( )
def register ( active= True ) :
def decorate ( func) :
print ( 'running register(active=%s)->decorate(%s)' % ( active, func) )
if active:
registry. add( func)
else :
registry. discard( func)
return func
return decorate
@register( active= False )
def f1 ( ) :
print ( 'running f1()' )
@register( )
def f2 ( ) :
print ( 'running f2()' )
def f3 ( ) :
print ( 'running f3()' )
2.2.4. 形式四:多种形式装饰器。
编写一个单独的装饰器,既可以使用@decorator
,也可以使用@decorator(x, y, z)
def logged ( func= None , * , level= logging. DEBUG, name= None , message= None ) :
if func is None :
return partial( logged, level= level, name= name, message= message)
. . .
2.2.5. 形式五:类中定义装饰器。
class A :
def decorator1 ( self, func) :
@wraps( func)
def wrapper ( * args, ** kwargs) :
print ( 'Decorator 1' )
return func( * args, ** kwargs)
return wrapper
@classmethod
def decorator2 ( cls, func) :
@wraps( func)
def wrapper ( * args, ** kwargs) :
print ( 'Decorator 2' )
return func( * args, ** kwargs)
return wrapper
a = A( )
@a. decorator1
def greet ( ) :
return 'Hello!'
@A. decorator2
def spam ( ) :
pass
2.3. 装饰器执行时间
装饰器的一个关键特性,是在被装饰的函数定义之后立即执行 ,通常是在导入时。 换个说法:函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。 这突出了Python程序员所说的导入时 和运行时 之间的区别。 具体查看以下实例:
def register ( func) :
print ( 'running register(%s)' % func)
return func
@register
def f1 ( ) :
print ( 'running f1()' )
@register
def f2 ( ) :
print ( 'running f2()' )
def main ( ) :
print ( 'running main()' )
f1( )
f2( )
2.5. 无法调试(无法获取元数据)
如果使用最朴素的方法定义装饰器,可能会导致函数无法调试 ,即函数的元数据(如文档、原函数名称、参数列表)被隐藏。
解决方案:使用functools.wraps
装饰器,如下例子。
def uppercase ( func) :
@functools. wraps( func) :
def wrapper ( ) :
return func( ) . upper( )
return wrapper