ch19函数的高级话题(python)
#函数设计概念
耦合性:对于输入使用参数,对于输出使用return语句
耦合性:只有在真正必要的情况下使用全局变量
耦合性:不要改变可变类型的参数,除非调用者希望如此。
聚合性:每一个函数都应该有一个单一的,统一的目标
大小:每一个函数应该相对较小
耦合性:避免直接改变在另一个模块文件中的变量。
#使函数和其他编程组件中的外部依赖最小化。
#利用递归求和
>>> def mysum(L):
... if not L:
... return 0
... else:
... return L[0] + mysum(L[1:]) # Call myself
>>> mysum([1, 2, 3, 4, 5])
15
#输出L查看
>>> def mysum(L):
... print(L) # Trace recursive levels
... if not L: # L shorter at each level
... return 0
... else:
... return L[0] + mysum(L[1:])
...
>>> mysum([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5]
[2, 3, 4, 5]
[3, 4, 5]
[4, 5]
[5]
[]
15
#编码替代方案,使用if/else表达式
def mysum(L):
return 0 if not L else L[0] + mysum(L[1:]) # Use ternary expression
def mysum(L):
return L[0] if len(L) == 1 else L[0] + mysum(L[1:]) # Any type, assume one
def mysum(L): #可以传入任何可迭代对象
first, *rest = L
return first if not rest else first + mysum(rest) # Use 3.0 ext seq assign
#支持+的任何对象都可以当参数传入
>>> mysum([1]) # mysum([]) fails in last 2
1
>>> mysum([1, 2, 3, 4, 5])
15
>>> mysum(('s', 'p', 'a', 'm')) # But various types now work
'spam'
>>> mysum(['spam', 'ham', 'eggs'])
'spamhameggs'
#递归也可以间接调用自身(这里通过nonempty函数调用自身)
>>> def mysum(L):
... if not L: return 0
... return nonempty(L) # Call a function that calls me
...
>>> def nonempty(L):
... return L[0] + mysum(L[1:]) # Indirectly recursive
...
>>> mysum([1.1, 2.2, 3.3, 4.4])
11.0
#循环语句VS递归
>>> L = [1, 2, 3, 4, 5]
>>> sum = 0
>>> while L:
... sum += L[0]
... L = L[1:]
...
>>> sum
15
#for迭代
>>> L = [1, 2, 3, 4, 5]
>>> sum = 0
>>> for x in L: sum += x
...
>>> sum
15
#递归消耗时间和堆栈空间
#递归处理任意结构
#求这个列表的和
[1, [2, [3, 4], 5], 6, [7, 8]] # Arbitrarily nested sublists
def sumtree(L):
tot = 0
for x in L: # For each item at this level
if not isinstance(x, list):
tot += x # Add numbers directly
else:
tot += sumtree(x) # Recur for sublists
return tot
L = [1, [2, [3, 4], 5], 6, [7, 8]] # Arbitrary nesting
print(sumtree(L)) # Prints 36
# Pathological cases
print(sumtree([1, [2, [3, [4, [5]]]]])) # Prints 15 (right-heavy)
print(sumtree([[[[[1], 2], 3], 4], 5])) # Prints 15 (left-heavy)
#类中的一些运算符重载方法,例如__setattr__和__getattribute__,如果使用不正确的话,都有潜在的可能会递归的循环。
#函数对象:属性和注解
#函数是对象,自身存储在内存块中
#间接函数调用
#在def运行之后,函数名直接是一个对象的引用
>>> def echo(message): # Name echo assigned to function object
... print(message)
...
>>> echo('Direct call') # Call object through original name
Direct call
>>> x = echo # Now x references the function too
>>> x('Indirect call!') # Call object through name by adding ()
Indirect call!
#由于参数通过赋值对象来传递,这就像把函数作为参数传递给其他函数一样容易
>>> def indirect(func, arg):
... func(arg) # Call the passed-in object by adding ()
...
>>> indirect(echo, 'Argument call!') # Pass the function to another function
Argument call!
把函数对象填入数据结构中
>>> schedule = [ (echo, 'Spam!'), (echo, 'Ham!') ]
>>> for (func, arg) in schedule:
... func(arg) # Call functions embedded in containers
...
Spam!
Ham!
#一个函数可以返回一个函数对象,嵌套函数
>>> def make(label): # Make a function but don't call it
... def echo(message):
... print(label + ':' + message)
... return echo
...
>>> F = make('Spam') # Label in enclosing scope is retained
>>> F('Ham!') # Call the function that make returned
Spam:Ham!
>>> F('Eggs!')
Spam:Eggs!
#函数内省
>>> def func(a):
... b = 'spam'
... return b * a
...
>>> func(8)
'spamspamspamspamspamspamspamspam'
#函数内省
>>> func.__name__
'func'
>>> dir(func)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
...more omitted...
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
#函数附加的code对象包含了函数的本地变量和参数等方面的细节
>>> func.__code__
<code object func at 0x0257C9B0, file "<stdin>", line 1>
>>> dir(func.__code__)
['__class__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__',
...more omitted...
'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename',
'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab',
'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
>>> func.__code__.co_varnames
('a', 'b')
>>> func.__code__.co_argcount
1
#函数属性
#函数不仅仅有前面的系统定义属性,也可以添加自定义属性
>>> func
<function func at 0x0257C738>
>>> func.count = 0
>>> func.count += 1
>>> func.count
1
>>> func.handles = 'Button-Press'
>>> func.handles
'Button-Press'
>>> dir(func)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
...more omitted...
__str__', '__subclasshook__', 'count', 'handles']
#这样的属性可以直接用来把状态信息附加到函数对象,而不必使用全局,非本地和类等其他技术。
#这也是模拟其他语言的"静态本地变量"的一种方式,这种变量的名称对于一个函数来说是本地的,其值在函数退出后还保留。属性与对象相关而不是与作用域相关。
#python3.0中的函数注解
#函数注解是与函数参数和返回值相关的任意的用户定义的数据
#函数注解会附加到函数对象的__annotations__属性上以供其他用户使用
#不带函数注解
>>> def func(a, b, c):
... return a + b + c
...
>>> func(1, 2, 3)
6
#带有函数注解的函数头
>>> def func(a: 'spam', b: (1, 10), c: float) -> int:
... return a + b + c
...
>>> func(1, 2, 3)
6
#查看函数注解
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#a,b带有函数注解
>>> def func(a: 'spam', b, c: 99):
... return a + b + c
...
>>> func(1, 2, 3)
6
#遍历函数注解 func.__annotations__返回的就是字典
>>> func.__annotations__
{'a': 'spam', 'c': 99}
>>> for arg in func.__annotations__:
... print(arg, '=>', func.__annotations__[arg])
...
a => spam
c => 99
#即使有函数注解,还是可以有默认值
>>> def func(a: 'spam' = 4, b: (1, 10) = 5, c: float = 6) -> int:
... return a + b + c
...
>>> func(1, 2, 3)
6
>>> func() # 4 + 5 + 6 (all defaults)
15
>>> func(1, c=10) # 1 + 5 + 10 (keywords work normally)
16
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#提高代码可读性
>>> def func(a:'spam'=4, b:(1,10)=5, c:float=6)->int:
... return a + b + c
...
>>> func(1, 2) # 1 + 2 + 6
9
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#注解只对def有效,对lambda无效
#匿名函数:lambda
#lambda创建了一个之后能够调用的函数,返回了一个函数对象
#lambada表达式形式:
lambda argument1,argument2,...:expression using arguments
#lambda是一个表达式,不是语句。能出现在def不能出现的地方。
#lambda的主体是一个单个的表达式,而不是一个代码块。将结果写成一个顺畅的表达式。连if语句都不能使用。lambda为编写简单的函数而设计。
#def创建的函数
>>> def func(x, y, z): return x + y + z
...
>>> func(2, 3, 4)
9
#使用lambda表达式
>>> f = lambda x, y, z: x + y + z
>>> f(2, 3, 4)
9
#lambda也能够使用默认参数
>>> x = (lambda a="fee", b="fie", c="foe": a + b + c)
>>> x("wee")
'weefiefoe'
#lambda主体中的代码象在def内的代码一样都遵循相同的作用域查找法则LEGB。
>>> def knights():
... title = 'Sir'
... action = (lambda x: title + ' ' + x) # Title in enclosing def
... return action # Return a function
...
>>> act = knights()
>>> act('robin')
'Sir robin'
#为什么使用lambda
#lambda写在常量表达式中,这种常量表达式中不可嵌入def
L = [lambda x: x ** 2, # Inline function definition
lambda x: x ** 3,
lambda x: x ** 4] # A list of 3 callable functions
for f in L:
print(f(2)) # Prints 4, 8, 16
print(L[0](3)) # Prints 9
#def的形式
def f1(x): return x ** 2
def f2(x): return x ** 3 # Define named functions
def f3(x): return x ** 4
L = [f1, f2, f3] # Reference by name
for f in L:
print(f(2)) # Prints 4, 8, 16
print(L[0](3)) # Prints 9
#lambda作为字典的值存在
>>> key = 'got'
>>> {'already': (lambda: 2 + 2),
... 'got': (lambda: 2 * 4),
... 'one': (lambda: 2 ** 6)}[key]()
8
#def形式
>>> def f1(): return 2 + 2
...
>>> def f2(): return 2 * 4
...
>>> def f3(): return 2 ** 6
...
>>> key = 'one'
>>> {'already': f1, 'got': f2, 'one': f3}[key]()
64
#lambda主体必须是单个表达式(而不是语句),所以仅能将有限的逻辑封装到以恶搞lambda中。
#在lambda中进行print,直接编写sys.stdout.write(str(x)+'\n'),而不是使用print(x)
#在lambda中写逻辑嵌套的时候,使用if/else三元表达式或者对等的and/or组合
>>> lower = (lambda x, y: x if x < y else y)
>>> lower('bb', 'aa')
'aa'
>>> lower('aa', 'bb')
'aa'
如果要在lambda中执行循环,能够潜入map调用或者列表解析表达式。
>>> import sys
>>> showall = lambda x: list(map(sys.stdout.write, x)) # Use list() in 3.0
>>> t = showall(['spam\n', 'toast\n', 'eggs\n'])
spam
toast
eggs
>>> showall = lambda x: [sys.stdout.write(line) for line in x]
>>> t = showall(('bright\n', 'side\n', 'of\n', 'life\n'))
bright
side
of
life
#上面的代码容易造成晦涩难懂。
#lambda出现在def中,通过LEGB法则可以获取上层函数作用域中x的值
>>> def action(x):
... return (lambda y: x + y) # Make and return function, remember x
...
>>> act = action(99)
>>> act
<function <lambda> at 0x00A16A88>
>>> act(2) # Call what action returned
101
#lambda嵌套lambda的形式,第二个lambda能访问x,通过LEGB
>>> action = (lambda x: (lambda y: x + y))
>>> act = action(99)
>>> act(3)
102
>>> ((lambda x: (lambda y: x + y))(99))(4)
103
#lambda的另一个常用的应用就是Python的tkinter GUI API(python2.6中是Tkinter)
import sys
from tkinter import Button, mainloop # Tkinter in 2.6
x = Button(
text ='Press me',
command=(lambda:sys.stdout.write('Spam\n')))
x.pack()
mainloop()
#因为嵌套的作用域法则对lambda有效,使回调处理变得简单易用
class MyGui:
def makewidgets(self):
Button(command=(lambda: self.onPress("spam")))
def onPress(self, message):
...use message...
>>> counters = [1, 2, 3, 4]
>>>
>>> updated = []
>>> for x in counters:
... updated.append(x + 10) # Add 10 to each item
...
>>> updated
[11, 12, 13, 14]
#上面例子的map版本:map函数会对序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表
>>> def inc(x): return x + 10 # Function to be run
...
>>> list(map(inc, counters)) # Collect results
[11, 12, 13, 14]
#使用lambda
>>> list(map((lambda x: x + 3), counters)) # Function expression
[4, 5, 6, 7]
#自己的映射工具函数
>>> def mymap(func, seq):
... res = []
... for x in seq: res.append(func(x))
... return res
#测试上面的自己的映射工具函数
>>> list(map(inc, [1, 2, 3])) # Built-in is an iterator
[11, 12, 13]
>>> mymap(inc, [1, 2, 3]) # Ours builds a list (see generators)
[11, 12, 13]
#提供多个序列
>>> pow(3, 4) # 3**4
81
>>> list(map(pow, [1, 2, 3], [2, 3, 4])) # 1**2, 2**3, 3**4
[1, 8, 81]
#对于多个序列,map期待N参数的函数用于N序列
#函数式编程工具:filter和reduce
#函数式编程的意思是对序列应用一些函数的工具
>>> list(range(-5, 5)) # An iterator in 3.0
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
>>> list(filter((lambda x: x > 0), range(-5, 5))) # An iterator in 3.0
[1, 2, 3, 4]
#等效的for实现
>>> res = []
>>> for x in range(-5, 5):
... if x > 0:
... res.append(x)
...
>>> res
[1, 2, 3, 4]
#reduce在python2.6是一个内置函数,在python3中位于functools模块中
>>> from functools import reduce # Import in 3.0, not in 2.6
>>> reduce((lambda x, y: x + y), [1, 2, 3, 4])
10
>>> reduce((lambda x, y: x * y), [1, 2, 3, 4])
24
>>> L = [1,2,3,4]
>>> res = L[0]
>>> for x in L[1:]:
... res = res + x
...
>>> res
10
#自己的reduce版本
>>> def myreduce(function, sequence):
... tally = sequence[0]
... for next in sequence[1:]:
... tally = function(tally, next)
... return tally
...
>>> myreduce((lambda x, y: x + y), [1, 2, 3, 4, 5])
15
>>> myreduce((lambda x, y: x * y), [1, 2, 3, 4, 5])
120
>>> import operator, functools
>>> functools.reduce(operator.add, [2, 4, 6]) # Function-based +
12
>>> functools.reduce((lambda x, y: x + y), [2, 4, 6])
12
耦合性:对于输入使用参数,对于输出使用return语句
耦合性:只有在真正必要的情况下使用全局变量
耦合性:不要改变可变类型的参数,除非调用者希望如此。
聚合性:每一个函数都应该有一个单一的,统一的目标
大小:每一个函数应该相对较小
耦合性:避免直接改变在另一个模块文件中的变量。
#使函数和其他编程组件中的外部依赖最小化。
#利用递归求和
>>> def mysum(L):
... if not L:
... return 0
... else:
... return L[0] + mysum(L[1:]) # Call myself
>>> mysum([1, 2, 3, 4, 5])
15
#输出L查看
>>> def mysum(L):
... print(L) # Trace recursive levels
... if not L: # L shorter at each level
... return 0
... else:
... return L[0] + mysum(L[1:])
...
>>> mysum([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5]
[2, 3, 4, 5]
[3, 4, 5]
[4, 5]
[5]
[]
15
#编码替代方案,使用if/else表达式
def mysum(L):
return 0 if not L else L[0] + mysum(L[1:]) # Use ternary expression
def mysum(L):
return L[0] if len(L) == 1 else L[0] + mysum(L[1:]) # Any type, assume one
def mysum(L): #可以传入任何可迭代对象
first, *rest = L
return first if not rest else first + mysum(rest) # Use 3.0 ext seq assign
#支持+的任何对象都可以当参数传入
>>> mysum([1]) # mysum([]) fails in last 2
1
>>> mysum([1, 2, 3, 4, 5])
15
>>> mysum(('s', 'p', 'a', 'm')) # But various types now work
'spam'
>>> mysum(['spam', 'ham', 'eggs'])
'spamhameggs'
#递归也可以间接调用自身(这里通过nonempty函数调用自身)
>>> def mysum(L):
... if not L: return 0
... return nonempty(L) # Call a function that calls me
...
>>> def nonempty(L):
... return L[0] + mysum(L[1:]) # Indirectly recursive
...
>>> mysum([1.1, 2.2, 3.3, 4.4])
11.0
#循环语句VS递归
>>> L = [1, 2, 3, 4, 5]
>>> sum = 0
>>> while L:
... sum += L[0]
... L = L[1:]
...
>>> sum
15
#for迭代
>>> L = [1, 2, 3, 4, 5]
>>> sum = 0
>>> for x in L: sum += x
...
>>> sum
15
#递归消耗时间和堆栈空间
#递归处理任意结构
#求这个列表的和
[1, [2, [3, 4], 5], 6, [7, 8]] # Arbitrarily nested sublists
def sumtree(L):
tot = 0
for x in L: # For each item at this level
if not isinstance(x, list):
tot += x # Add numbers directly
else:
tot += sumtree(x) # Recur for sublists
return tot
L = [1, [2, [3, 4], 5], 6, [7, 8]] # Arbitrary nesting
print(sumtree(L)) # Prints 36
# Pathological cases
print(sumtree([1, [2, [3, [4, [5]]]]])) # Prints 15 (right-heavy)
print(sumtree([[[[[1], 2], 3], 4], 5])) # Prints 15 (left-heavy)
#类中的一些运算符重载方法,例如__setattr__和__getattribute__,如果使用不正确的话,都有潜在的可能会递归的循环。
#函数对象:属性和注解
#函数是对象,自身存储在内存块中
#间接函数调用
#在def运行之后,函数名直接是一个对象的引用
>>> def echo(message): # Name echo assigned to function object
... print(message)
...
>>> echo('Direct call') # Call object through original name
Direct call
>>> x = echo # Now x references the function too
>>> x('Indirect call!') # Call object through name by adding ()
Indirect call!
#由于参数通过赋值对象来传递,这就像把函数作为参数传递给其他函数一样容易
>>> def indirect(func, arg):
... func(arg) # Call the passed-in object by adding ()
...
>>> indirect(echo, 'Argument call!') # Pass the function to another function
Argument call!
把函数对象填入数据结构中
>>> schedule = [ (echo, 'Spam!'), (echo, 'Ham!') ]
>>> for (func, arg) in schedule:
... func(arg) # Call functions embedded in containers
...
Spam!
Ham!
#一个函数可以返回一个函数对象,嵌套函数
>>> def make(label): # Make a function but don't call it
... def echo(message):
... print(label + ':' + message)
... return echo
...
>>> F = make('Spam') # Label in enclosing scope is retained
>>> F('Ham!') # Call the function that make returned
Spam:Ham!
>>> F('Eggs!')
Spam:Eggs!
#函数内省
>>> def func(a):
... b = 'spam'
... return b * a
...
>>> func(8)
'spamspamspamspamspamspamspamspam'
#函数内省
>>> func.__name__
'func'
>>> dir(func)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
...more omitted...
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
#函数附加的code对象包含了函数的本地变量和参数等方面的细节
>>> func.__code__
<code object func at 0x0257C9B0, file "<stdin>", line 1>
>>> dir(func.__code__)
['__class__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__',
...more omitted...
'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename',
'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab',
'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
>>> func.__code__.co_varnames
('a', 'b')
>>> func.__code__.co_argcount
1
#函数属性
#函数不仅仅有前面的系统定义属性,也可以添加自定义属性
>>> func
<function func at 0x0257C738>
>>> func.count = 0
>>> func.count += 1
>>> func.count
1
>>> func.handles = 'Button-Press'
>>> func.handles
'Button-Press'
>>> dir(func)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
...more omitted...
__str__', '__subclasshook__', 'count', 'handles']
#这样的属性可以直接用来把状态信息附加到函数对象,而不必使用全局,非本地和类等其他技术。
#这也是模拟其他语言的"静态本地变量"的一种方式,这种变量的名称对于一个函数来说是本地的,其值在函数退出后还保留。属性与对象相关而不是与作用域相关。
#python3.0中的函数注解
#函数注解是与函数参数和返回值相关的任意的用户定义的数据
#函数注解会附加到函数对象的__annotations__属性上以供其他用户使用
#不带函数注解
>>> def func(a, b, c):
... return a + b + c
...
>>> func(1, 2, 3)
6
#带有函数注解的函数头
>>> def func(a: 'spam', b: (1, 10), c: float) -> int:
... return a + b + c
...
>>> func(1, 2, 3)
6
#查看函数注解
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#a,b带有函数注解
>>> def func(a: 'spam', b, c: 99):
... return a + b + c
...
>>> func(1, 2, 3)
6
#遍历函数注解 func.__annotations__返回的就是字典
>>> func.__annotations__
{'a': 'spam', 'c': 99}
>>> for arg in func.__annotations__:
... print(arg, '=>', func.__annotations__[arg])
...
a => spam
c => 99
#即使有函数注解,还是可以有默认值
>>> def func(a: 'spam' = 4, b: (1, 10) = 5, c: float = 6) -> int:
... return a + b + c
...
>>> func(1, 2, 3)
6
>>> func() # 4 + 5 + 6 (all defaults)
15
>>> func(1, c=10) # 1 + 5 + 10 (keywords work normally)
16
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#提高代码可读性
>>> def func(a:'spam'=4, b:(1,10)=5, c:float=6)->int:
... return a + b + c
...
>>> func(1, 2) # 1 + 2 + 6
9
>>> func.__annotations__
{'a': 'spam', 'c': <class 'float'>, 'b': (1, 10), 'return': <class 'int'>}
#注解只对def有效,对lambda无效
#匿名函数:lambda
#lambda创建了一个之后能够调用的函数,返回了一个函数对象
#lambada表达式形式:
lambda argument1,argument2,...:expression using arguments
#lambda是一个表达式,不是语句。能出现在def不能出现的地方。
#lambda的主体是一个单个的表达式,而不是一个代码块。将结果写成一个顺畅的表达式。连if语句都不能使用。lambda为编写简单的函数而设计。
#def创建的函数
>>> def func(x, y, z): return x + y + z
...
>>> func(2, 3, 4)
9
#使用lambda表达式
>>> f = lambda x, y, z: x + y + z
>>> f(2, 3, 4)
9
#lambda也能够使用默认参数
>>> x = (lambda a="fee", b="fie", c="foe": a + b + c)
>>> x("wee")
'weefiefoe'
#lambda主体中的代码象在def内的代码一样都遵循相同的作用域查找法则LEGB。
>>> def knights():
... title = 'Sir'
... action = (lambda x: title + ' ' + x) # Title in enclosing def
... return action # Return a function
...
>>> act = knights()
>>> act('robin')
'Sir robin'
#为什么使用lambda
#lambda写在常量表达式中,这种常量表达式中不可嵌入def
L = [lambda x: x ** 2, # Inline function definition
lambda x: x ** 3,
lambda x: x ** 4] # A list of 3 callable functions
for f in L:
print(f(2)) # Prints 4, 8, 16
print(L[0](3)) # Prints 9
#def的形式
def f1(x): return x ** 2
def f2(x): return x ** 3 # Define named functions
def f3(x): return x ** 4
L = [f1, f2, f3] # Reference by name
for f in L:
print(f(2)) # Prints 4, 8, 16
print(L[0](3)) # Prints 9
#lambda作为字典的值存在
>>> key = 'got'
>>> {'already': (lambda: 2 + 2),
... 'got': (lambda: 2 * 4),
... 'one': (lambda: 2 ** 6)}[key]()
8
#def形式
>>> def f1(): return 2 + 2
...
>>> def f2(): return 2 * 4
...
>>> def f3(): return 2 ** 6
...
>>> key = 'one'
>>> {'already': f1, 'got': f2, 'one': f3}[key]()
64
#lambda主体必须是单个表达式(而不是语句),所以仅能将有限的逻辑封装到以恶搞lambda中。
#在lambda中进行print,直接编写sys.stdout.write(str(x)+'\n'),而不是使用print(x)
#在lambda中写逻辑嵌套的时候,使用if/else三元表达式或者对等的and/or组合
>>> lower = (lambda x, y: x if x < y else y)
>>> lower('bb', 'aa')
'aa'
>>> lower('aa', 'bb')
'aa'
如果要在lambda中执行循环,能够潜入map调用或者列表解析表达式。
>>> import sys
>>> showall = lambda x: list(map(sys.stdout.write, x)) # Use list() in 3.0
>>> t = showall(['spam\n', 'toast\n', 'eggs\n'])
spam
toast
eggs
>>> showall = lambda x: [sys.stdout.write(line) for line in x]
>>> t = showall(('bright\n', 'side\n', 'of\n', 'life\n'))
bright
side
of
life
#上面的代码容易造成晦涩难懂。
#lambda出现在def中,通过LEGB法则可以获取上层函数作用域中x的值
>>> def action(x):
... return (lambda y: x + y) # Make and return function, remember x
...
>>> act = action(99)
>>> act
<function <lambda> at 0x00A16A88>
>>> act(2) # Call what action returned
101
#lambda嵌套lambda的形式,第二个lambda能访问x,通过LEGB
>>> action = (lambda x: (lambda y: x + y))
>>> act = action(99)
>>> act(3)
102
>>> ((lambda x: (lambda y: x + y))(99))(4)
103
#lambda的另一个常用的应用就是Python的tkinter GUI API(python2.6中是Tkinter)
import sys
from tkinter import Button, mainloop # Tkinter in 2.6
x = Button(
text ='Press me',
command=(lambda:sys.stdout.write('Spam\n')))
x.pack()
mainloop()
#因为嵌套的作用域法则对lambda有效,使回调处理变得简单易用
class MyGui:
def makewidgets(self):
Button(command=(lambda: self.onPress("spam")))
def onPress(self, message):
...use message...
>>> counters = [1, 2, 3, 4]
>>>
>>> updated = []
>>> for x in counters:
... updated.append(x + 10) # Add 10 to each item
...
>>> updated
[11, 12, 13, 14]
#上面例子的map版本:map函数会对序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表
>>> def inc(x): return x + 10 # Function to be run
...
>>> list(map(inc, counters)) # Collect results
[11, 12, 13, 14]
#使用lambda
>>> list(map((lambda x: x + 3), counters)) # Function expression
[4, 5, 6, 7]
#自己的映射工具函数
>>> def mymap(func, seq):
... res = []
... for x in seq: res.append(func(x))
... return res
#测试上面的自己的映射工具函数
>>> list(map(inc, [1, 2, 3])) # Built-in is an iterator
[11, 12, 13]
>>> mymap(inc, [1, 2, 3]) # Ours builds a list (see generators)
[11, 12, 13]
#提供多个序列
>>> pow(3, 4) # 3**4
81
>>> list(map(pow, [1, 2, 3], [2, 3, 4])) # 1**2, 2**3, 3**4
[1, 8, 81]
#对于多个序列,map期待N参数的函数用于N序列
#函数式编程工具:filter和reduce
#函数式编程的意思是对序列应用一些函数的工具
>>> list(range(-5, 5)) # An iterator in 3.0
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
>>> list(filter((lambda x: x > 0), range(-5, 5))) # An iterator in 3.0
[1, 2, 3, 4]
#等效的for实现
>>> res = []
>>> for x in range(-5, 5):
... if x > 0:
... res.append(x)
...
>>> res
[1, 2, 3, 4]
#reduce在python2.6是一个内置函数,在python3中位于functools模块中
>>> from functools import reduce # Import in 3.0, not in 2.6
>>> reduce((lambda x, y: x + y), [1, 2, 3, 4])
10
>>> reduce((lambda x, y: x * y), [1, 2, 3, 4])
24
>>> L = [1,2,3,4]
>>> res = L[0]
>>> for x in L[1:]:
... res = res + x
...
>>> res
10
#自己的reduce版本
>>> def myreduce(function, sequence):
... tally = sequence[0]
... for next in sequence[1:]:
... tally = function(tally, next)
... return tally
...
>>> myreduce((lambda x, y: x + y), [1, 2, 3, 4, 5])
15
>>> myreduce((lambda x, y: x * y), [1, 2, 3, 4, 5])
120
>>> import operator, functools
>>> functools.reduce(operator.add, [2, 4, 6]) # Function-based +
12
>>> functools.reduce((lambda x, y: x + y), [2, 4, 6])
12
评论
发表评论