一、闭包
闭包概念:在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包。
# test1:简单闭包
def outer(a):
def inner(b):
return a + b
return inner
f = outer(1)
print("f.name is:", f.__name__)
print(f(2))
print(f(3))
f.name is: inner
3
4
# test2:闭包无法修改外部函数的局部变量
def outfunc():
x = 0
def infunc():
x = 1
print("infunc x is:", x)
print("outfunc x is:", x)
infunc()
print("outfunc x is:", x)
outfunc()
outfunc x is: 0
infunc x is: 1
outfunc x is: 0
# test3:使用nolocal
def outfunc():
x = 0
def infunc():
nonlocal x
x = 1
print("infunc x is:", x)
print("outfunc x is:", x)
infunc()
print("outfunc x is:", x)
outfunc()
outfunc x is: 0
infunc x is: 1
outfunc x is: 1
# test 4:易错点
'''
按照大家正常的理解,应该输出的是0, 2, 4对吧?但实际输出的结果是:4, 4, 4. 原因是什么呢?
loop在python中是没有域的概念的,flist在像列表中添加func的时候,并没有保存i的值,
而是当执行f(2)的时候才去取,这时候循环已经结束,i的值是2,所以结果都是4。
'''
def outfunc():
flist = []
for i in range(4):
def infunc(x):
return i * x
flist.append(infunc)
return flist
flist = outfunc()
ret = [f(2) for f in flist]
print(ret)
def outfunc():
flist = []
for i in range(4):
def makefunc(i):
def infunc(x):
return i * x
return infunc
flist.append(makefunc(i))
return flist
flist = outfunc()
ret = [f(2) for f in flist]
print(ret)
[6, 6, 6, 6]
[0, 2, 4, 6]
二、装饰器
# 不带参数
def debug(func):
def wrapper():
print("[DEBUG]: befor {}()".format(func.__name__))
func()
print("[DEBUG]: after {}()".format(func.__name__))
return wrapper
@debug
def hello():
print("hello")
hello()
[DEBUG]: befor hello()
hello
[DEBUG]: after hello()
# 装饰函数带参数
def debug(func):
def wrapper(*args, **kwargs):
print("[DEBUG]: befor {}()".format(func.__name__))
func(*args, **kwargs)
print("[DEBUG]: after {}()".format(func.__name__))
return wrapper
@debug
def hello(a, b, c):
print("hello:", a, b, c)
hello("a", "b", "c")
[DEBUG]: befor hello()
hello: a b c
[DEBUG]: after hello()
def debug(level):
def outwrapper(func):
def wrapper(*args, **kwargs):
print("[{}]: befor {}()".format(level, func.__name__))
func(*args, **kwargs)
print("[{}]: after {}()".format(level, func.__name__))
return wrapper
return outwrapper
@debug(level="INFO")
def hello(a, b, c):
print("hello:", a, b, c)
hello("a", "b", "c")
[INFO]: befor hello()
hello: a b c
[INFO]: after hello()
三、迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会退。 迭代器有两个基本的方法:iter() 和 next()。 字符串,列表或元组对象都可用于创建迭代器:
test1:
list_arr = [1, 2, 3, 4]
it = iter(list_arr)
print(type(list_arr), type(it))
print(next(it), next(it))
for i in it:
print(i)
<class 'list'> <class 'list_iterator'>
1 2
3
4
test2:
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__(); __iter__() 方法返回一个特殊的迭代器对象,; 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成;
class MyRange(object):
def __init__(self, end):
self.index = 0
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.index < self.end:
x = self.index
self.index += 1
return x
else:
raise StopIteration
for i in MyRange(5):
print(i)
my_range = MyRange(5)
print(next(my_range), next(my_range))
0
1
2
3
4
0 1
四、生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator) 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。 调用一个生成器函数,返回的是一个迭代器对象。
test1:普通函数实现
def fab_list(max_n):
n, a, b = 0, 0, 1
ret = []
while n < max_n:
ret.append(b)
a, b = b, a + b
n += 1
return ret
f = fab_list(6)
print(f)
[1, 1, 2, 3, 5, 8]
test2:yield实现
def fab_yield(max_n):
n, a, b = 0, 0, 1
while n < max_n:
yield b
a, b = b, a + b
n += 1
f = fab_yield(6)
print(next(f), next(f), next(f), next(f), next(f), next(f))
1 1 2 3 5 8
解释:
yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数, next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的, 所以调用next的时候,生成器并不会从foo函数的开始执行, 只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。
五、参考与总结: