装饰器
高级函数
1函数名和变量名一样,只是一个变量标识符,它指向函数定义对应的内容存地址。
2 函数定义中存在调用其他函数,并不会立刻调用该函数
3 在执行一个调用了其他函数的函数时候,在内存中没有找到被调用函数的定义,会报错。(如下代码示例)
def foo():
print('in foo')
boo()
foo()
def boo():
print('in boo')
装饰器
定义:用来装饰其他函数,即为其他函数添加特定功能的函数。输出输出都为单一函数
装饰器基本原则:
1、装饰器不能修改被装饰函数源码;
2、装饰器不能修改被装饰函数的调用方式;
代码示例
import time
def timer(timer_type):
print(timer_type)
def outer(func):
def inner(*args, **kwargs):
time_start = time.time()
res = func(*args, **kwargs)
time_end = time.time()
print("运行时间:",timer_type, time_end - time_start)
return res
return inner
return outer
@timer(timer_type='minites') #等同于foo=timer(timer_type='minites')(foo)
def foo(name, age):
time.sleep(3)
print('in foo', name, age)
return name
print(foo('xx',11))
说明:通过内嵌函数定义一个函数,把原函数包装上,返回新函数。
详细见:
Python进阶教学——装饰器与闭包
python函数(5)— 可变参数 *args 和 **kwargs
闭包
用来在一个函数与一组私有变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保证持久性。
装饰器和闭包对比:
装饰器 | 闭包 |
---|---|
装饰器外层主要是提供被装饰函数的引用。如foo=timer(timer_type=‘minites’)(foo) | 闭包外层主要是提供自有变量 |
装饰器外层函数不一定提供变量 | 闭包外层函数必须提供变量,否则无意义 |
装饰器目的:为被装饰函数提供额外功能 | 闭包目的:为函数保存运行环境和局部变量 |
迭代器
可迭代对象:只要定义了一个可返回迭代器的__iter__方法,或者定义了__getitem__方法,就是一个可迭代对象。
判断是否可以迭代:
print(hasattr([],'__getitem__'))
print(hasattr([],'__iter__'))
getitem:根据传入的int参数,返回一个列表中的元素
iter:返回一个可迭代对象
next:当被迭代时,返回下一个迭代的对象
class Empolyee:
def __init__(self,names):
self.names = names
def __getitem__(self,item):
return self.names[item]
empolyee = Empolyee(['a','b'])
for i in empolyee: print(i)
迭代器:实现了__next__方法和__iter__方法(缺一不可)的对象。__iter__方法返回迭代器自身,__next__方法返回迭代器的下一值,直到没有元素,会抛出StopIteration异常(for循环会自动处理StopIteration异常)
迭代器一定是可迭代对象,可迭代对象不一定是迭代器。迭代器可以每次调用的使用生成迭代元素,而不是提前准备好所有的迭代元素,从而大大降低内存消耗。
from itertools import count
counter = count(start=10) #count没有len方法,可以一直迭代下去
print(type(counter))
print(dir(counter))
print(next(counter))
可以通过iter方法把一个可迭代对象变为迭代器(补全__next__方法和__iter__方法),同时也会去掉包括len,append,add,reverse,copy等方法
my_list = [1,2,3]
my_list_iter = iter(my_list)
print(set(dir(my_list_iter))-set(dir(my_list)))
print(set(dir(my_list))-set(dir(my_list_iter)))
print(type(my_list_iter))
print(next(my_list_iter))
打印结果:
{'__next__', '__setstate__', '__length_hint__'}
{'remove', '__imul__', '__rmul__', 'clear', '__class_getitem__', '__mul__', '__getitem__', 'sort', 'append', 'index', '__len__', 'pop', '__contains__', '__add__', 'extend', '__setitem__', '__iadd__', 'reverse', 'copy', '__reversed__', '__delitem__', 'insert', 'count'}
<class 'list_iterator'>
生成器
生成器是一种特殊的迭代器,不需要显式写__next__方法和__iter__方法,只需要yield关键字。
yield作用:
1、程序每次迭代中遇到yield, 会返回结果;
2、保留函数当前运行状态,等下一次调用,会从上一次返回yield语句处开始执行后面语句。
3、预激活机制,生成器在没有调用next方法之前,是不执行的
4、可以通过send方法,从调用放往生成器中传入参数。send会和next一样,会调用一次生成器,到下一次yield,同时给生成器传递参数。
5、throw,如果throw(StopIteration)代表跳过中间数值,结束生成器。自定义异常(ValueError和TypeError),抛出后执行返回下一个值
6、手动结束迭代器可以使用g.close() ,结束迭代器后g.next()会报错。
def count_down(n):
print("count down from {}".format(n))
while n > 0:
new_value = yield n
if new_value is not None:
n = new_value
else:
n -= 1
c = count_down(10) #预激活
for x in c:
print(x)
if x == 10:
print(c.send(3))
结果:
count down from 10
10
3
2
1
raise exception in generator,return next yielded value or StopIteration,即在生成器中抛出异常,并且这个throw函数会返回下一个要迭代的值或者是StopIteration。
def my_generator():
while True:
try:
yield 'a'
yield 'b'
yield 'c'
yield 'd'
yield 'e'
except ValueError:
print('触发“ValueError"了')
except TypeError:
print('触发“TypeError"了')
g=my_generator()
print(next(g))
print(next(g))
print('-------------------------')
print(g.throw(ValueError))
print('-------------------------')
print(next(g))
print(next(g))
print('-------------------------')
print(g.throw(TypeError))
print('-------------------------')
print(next(g))
'''运行结果为:
a
b
-------------------------
触发“ValueError"了
a
-------------------------
b
c
-------------------------
触发“TypeError"了
a
-------------------------
b
'''