[python]python进阶编程(2)-匿名函数和闭包
说明
python的一大特性是,其具备函数式编程语言的特性,这意味着function在python的世界中也是作为一等公民而存在的,今天就来讨论匿名函数和闭包。
lambda函数
lambda函数也称为匿名函数,多使用于只有一行逻辑的函数,可以使得代码简短易读。一个使用的场景如下所示:
将列表 ['abc', 'def', 'g']按照首字母排序,如果是按照sorted的方法,那么对应的排序函数应该设置为:
def get_first(s):
return s[0]
但是这一行的代码较为简单,且只使用一次,所以可以使用lambda来代替:
l = ['hbc', 'kef', 'g']
sorted_l = sorted(l, key= lambda s:s[0])
print(sorted_l)
lambda本身是一个匿名函数,一般只有一行,可以代替那些简单的函数。其格式为lambda param: return.其中param为对应参数,return为返回值。
lambda函数赋值
因为lambda函数是匿名的,所以可以通过赋值的方式进行传递,但是一般不推荐这么做,因为即便是匿名函数被赋值后,其本质上还是匿名函数,如果要使用带有名称的函数,还是使用def来定义。
foo = lambda x, y: x + y
print(foo) # <function test_lambda_type.<locals>.<lambda> at 0x0000021D000FEEE0>
可以看出,即便是赋值,相应的函数仍然是lambda,这可能在某些场景下造成困惑。
另外一个场景是通过lambda来禁用内置函数,如以下所示:
time.sleep = lambda x: None
上述函数禁用了sleep函数,但这样做是违背python的原则,不应当直接去覆盖内置函数,这样在使用的时候容易造成混乱,而一般的禁用方式则为继承+方法覆盖。
lambda函数作为返回值传递
因为函数在python里也是一等公民,所以可以返回值方式进行传递。
def foo():
return lambda x, y : x + y
上述的代码中foo函数返回的是一个具有加法逻辑的匿名函数,这实际上是python闭包的概念。我们稍微讲解一下,以下就是一个普通的闭包:
def foo():
def bar():
# do something
return
return bar
其中闭包中的bar函数可以使用foo函数中的参数,那么bar也可以根据foo的参数变换功能,具体来讲,就是需要根据参数来变换函数的场景。同样地,也可以对lambda函数进行嵌套来实现闭包:
lambda x: lambda y : x + y
不过这样一定程度上会使得可读性变差。
lambda函数作为参数使用
在map/filter/reduce的内置函数中,是接受lambda函数作为参数来使用的,但是通常情况下这些内置函数可以通过其他方式来代替,比如以下几种情况:
- map:
data = [1,2,3,4,5]
result = map(lambda v:v**2, data)
result = (v**2 for v in data) # 与map+lambda方法等效
- filter
data = [1,2,3,4,5]
result = filter(lambda v:v>3, data)
result = (v for v in data if v > 3) # 与filter+lambda方法等效
- reduce
data = [1,2,3,4,5]
result = reduce(lambda x, y : x + y, data)
result = sum(data) # 与reduce+lambda方法等效
从上述的情况可以看出,大部分的map/filter/reduce操作都可以被生成器或其他内置函数所代替,当作为参数来使用的使用的时候,应尽量考虑有没有其他的可替代写法或者更有效的内置方法。