7.函数
7.7在匿名函数中绑定变量的值
x = 10
#lambda表达式中用到的x是一个自由变量,在运行时绑定
a = lambda y: x + y
x = 20
b = lambda y: x + y
print(a(10))#30
print(b(10))#30
#希望匿名函数可以在定义的时候绑定变量并保持值不变,则可作为默认参数
x = 10
a = lambda y, x=x: x+y
x = 20
b = lambda y, x=x: x+y
print(a(10))#20
print(b(10))#30
funcs = [lambda x: x+n for n in range(5)]
for f in funcs:
print(f(0))
#lambda不能记住n的值,只会在运行时绑定,所以lambda表达式中的n全为4
foucs = [lambda x, n=n: x+n for n in range(5)]
for f in foucs:
print(f(0))
7.8让带有N个参数的可调用对象以较少的参数形式调用
def spam(a, b, c, d):
print(a, b, c, d)
from functools import partial
s1 = partial(spam, 1) #a=1
print(s1(2, 3, 4))
print(s1(4, 5, 6))
s2 = partial(spam, d=42) #d=42
print(s2(1, 2, 3))
print(s2(4, 5, 5))
s3 = partial(spam, 1, 2, d=42) #a=1, b=2, d=42
print(s3(3))
print(s3(4))
points = [(1, 2), (3, 4), (5, 6), (7, 8)]
import math
def distance(p1, p2):
x1, y1 = p1
x2, y2 = p2
#返回两点的距离
return math.hypot(x2-x1, y2-y1)
pt = (4, 3)
#key只能和接受单参数的函数一起工作
points.sort(key=partial(distance, pt))
print(points)
7.9用函数替代只有单个方法的的类
'''
我们定义了一个只有一个方法的类(__init__())除外,为了简化代码,希望
只用一个简单的函数替代
'''
#许多情况下,只有单个方法的类可以通过闭包将其转换成函数
from urllib.request import urlopen
class UrlTemplate(object):
def __init__(self, template):
self.template = template
def open(self, **kwargs):
return urlopen(self.template.format_map(kwargs))
yahoo = UrlTemplate('http://financce.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo.open(names='IBM,AAPL,FB', fields='sllclv'):
print(line.decode('utf-8'))
#闭包替代
#闭包会记住定义闭包时的环境,因此opner可以记住template的值
def urltemplate(template):
def opner(**kwargs):
return urlopen(template.format_map(kwargs))
return opner
yahoo = urltemplate('http://financce.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo(names='IBM,AAPL,FB', fields='sllclv'):
print(line.decode('utf-8'))
#当编写代码是遇到需要附加额外状态给函数时,请考虑使用闭包
7.10在回调函数中携带额外的状态
def apply_async(func, args, *, callback):
result = func(*args)
callback(result)
def print_result(result):
print('Got: ', result)
def add(x, y):
return x+y
apply_async(add, (2, 3), callback=print_result)
apply_async(add, ("Hello", "World"), callback=print_result)
#一种在回调函数中携带额外信息的方法是使用绑定方法而不是普通函数
class ResultHandler(object):
def __init__(self):
self.sequence = 0
def handler(self, result):
self.sequence += 1
print('[{}] Got: {}'.format(self.sequence, result))
r = ResultHandler()
apply_async(add, (2, 3), callback=r.handler)
apply_async(add, ("Hello", "World"), callback=r.handler)
#闭包
def make_handler():
sequence = 0
def handler(result):
nonlocal sequence
sequence += 1
print('[{}] Got: {}'.format(sequence, result))
return handler
handler = make_handler()
apply_async(add, (2, 3), callback=handler)
apply_async(add, ("Hello", "World"), callback=handler)
#协程
def make_handler():
sequence = 0
while True:
result = yield
sequence += 1
print('[{}] Got: {}'.format(sequence, result))
handler = make_handler()
#用next()使函数到达yield处,第二次使用时开始真正的使用
next(handler)
apply_async(add, (2, 3), callback=handler.send)
apply_async(add, ("Hello", "World"), callback=handler.send)
#partial
from functools import partial
class SequenceNo:
def __init__(self):
self.sequence = 0
def handler(result, seq):
seq.sequence += 1
print('[{}] Got: {}'.format(seq.sequence, result))
seq = SequenceNo()
apply_async(add, (2, 3), callback=partial(handler, seq=seq))
apply_async(add, ("Hello", "World"), callback=partial(handler, seq=seq))
7.11内联回调函数
'''
正在编写使用回调函数的代码,担心小型函数在代码中泛滥
'''
#通过生成器和协程将回调函数内联到一个函数中
def apply_async(func, args, *, callback):
result = func(*args)
callback(result)
from queue import Queue
from functools import wraps
class Async(object):
def __init__(self, func, args):
self.func = func
self.args = args
def inlined_async(func):
@wraps(func)
def wrapper(*args):
f = func(*args)
result_queue = Queue()
result_queue.put(None)
while True:
result = result_queue.get()
try:
#send()中的参数指定的是上一次被挂起的yield语句的返回值
#当send()方法的参数为None时,他与next方法完全等价
a = f.send(result) #第一次相当于执行next()
apply_async(a.func, a.args, callback=result_queue.put)
except StopIteration:
break
return wrapper
def add(x, y):
return x+y
@inlined_async
def test():
r = yield Async(add, (2, 3))
print(r)
r = yield Async(add, ("Hello", "World"))
print(r)
for n in range(10):
r = yield Async(add, (n, n))
print(r)
print('Goodbye')
test()
7.12访问定义在闭包内的变量
'''
正在编写使用回调函数的代码,担心小型函数在代码中泛滥
'''
#通过生成器和协程将回调函数内联到一个函数中
def apply_async(func, args, *, callback):
result = func(*args)
callback(result)
from queue import Queue
from functools import wraps
class Async(object):
def __init__(self, func, args):
self.func = func
self.args = args
def inlined_async(func):
@wraps(func)
def wrapper(*args):
f = func(*args)
result_queue = Queue()
result_queue.put(None)
while True:
result = result_queue.get()
try:
#send()中的参数指定的是上一次被挂起的yield语句的返回值
#当send()方法的参数为None时,他与next方法完全等价
a = f.send(result) #第一次相当于执行next()
apply_async(a.func, a.args, callback=result_queue.put)
except StopIteration:
break
return wrapper
def add(x, y):
return x+y
@inlined_async
def test():
r = yield Async(add, (2, 3))
print(r)
r = yield Async(add, ("Hello", "World"))
print(r)
for n in range(10):
r = yield Async(add, (n, n))
print(r)
print('Goodbye')
test()
294

被折叠的 条评论
为什么被折叠?



