2018-02-21 16:15:56
定义:本质是函数,(装饰其他函数)为其他函数增加附加功能
装饰器原则
- 不能修改被装饰函数的源代码
- 不能修改被装饰函数的调用方式
说白了,就是被装饰函数不知道装饰器的存在
装饰器的知识储备
函数即变量
高阶函数
把一个函数名当作实参传给另外一个函数
def ball():
# print('I am ball')
# # return 15
# def text11(hh):
# hh()
# text11(ball)
# (函数后面有括号是这个函数本身和return,text11(ball())不符合高阶函数 没有括号是内存地址)
返回值可以是函数名
嵌套函数
装饰器本质上是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值是一个函数对象. 经常用于有切面需求的场景,比如:插入日志,性能测试,事物处理,缓存,权限校验等场景. 装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续使用. 装饰器就是为已经存在的对象添加额外的功能
@符号是装时器的语法糖,在定义函数时使用,避免再一次赋值操作
1起源
我们想在login中输入调试信息,我们可以这样做
def login():
print('in login')
def printdebug(fun):
print('enter the login')
fun()
print('exit the login')
printdebug(login)
2让代码变得优美一点
def login():
print('in login')
def printdebug(fun):
def a():
print('enter the login')
fun()
print('exit the login')
return a
debug_login = printdebug(login)
debug_login()
3 让代码变得更加优美(python提供了@u语法糖符号)
def printdebug(fun):
def a():
print('enter the login')
fun()
print('exit the login')
return a
@printdebug
def login():
print('in login')
login()
4.加上参数
1)被装饰函数加参数
python会将login的参数直接传给函数a. 我们可以在函数a中使用user变量
def printdebug(fun):
def a(user):
print('enter the login in ')
fun(user)
print('exit the login')
return a
@printdebug
def login(user):
print('in login'+ user)
4.2装饰器本身有参数(为了接受传来的参数,需要在原本的printdebug函数上面添加一个函数来接收参数)
def printdebug_level(level):
def printdebug(fun):
def a(user):
print('enter the login, and debug level is %s'%level)
fun(user)
print('exit the login')
return a
return printdebug
@printdebug_level('it')
def login(user):
print('in login %s'%user)
login('dsaf')
5 装饰有返回值的函数(在装饰器中,将被装饰函数赋给一个变量,然后返回这个变量)
def printdebug_level(level):
def printdebug(fun):
def a(user):
print('enter the login, and debug level is %s'%level)
fun(user)
retuu = fun(user)
print('exit the login')
return retuu
return a
return printdebug
@printdebug_level('it')
def login(user):
print('in login %s'%user)
return '555'
res = login('dsaf')
print('my name is %s'%res)
闭包
如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,称为闭包
def outter():
name = 'slz'
def inner():
print(name)
return inner
res = outter()
res()
print(res.__closure__) 如果res是闭包的话,会返回一个由cell对象组成的元组对象
print(res.__closure__[0].cell_contents) cell_contents属性是闭包中的自由变量
列表生成器
将列表中的每个值加一
a = [i+1 for i in range(10)]
print(a)
生成器
通过列表生成器,我们直接创建了一个列表.但是受到内存限制,列表容量肯定是有限是的.
而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅访问前面的几个元素,那后面的大多数元素占用的空间就白白浪费了
所以,如果列表和i元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
这样就不必创建完整的list,从而节省大量的空间
在python中,这种一边循环一边计算的机制,称为生成器: generator
要创建一个generator,有很多种方法,第一种很简单,只要把列表生成式的[]改为()
b = (i+1 for i in range(10))
print(b)

那么我们如何把b的值打印出来呢
b = (i+1 for i in range(10))
print(b)
for n in b:
print(n)
定义generator的另一种方法,如果一个函数定义中包含yield关键字,那么这个函数就不在是一个普通函数,而是一个generator
def fib(max):
n,a,b = 0,0,1
while n < max:
#print(b)
yield b
a,b = b,a+b
n += 1
return 'done'
还是通过循环来调用
for i in fib(19):
print(i)
可迭代对象
就是可以用for循环的
for a in 'abc':
print(a)
一类是集合数据类型,如list,tuple,dict,set,str
一类是generator,包括生成器
测试某个数据是否可迭代
1,
就是上面的可以直接作用于for循环的统称为可迭代对象: Iterable
>>>
from
collections
import
Iterable
>>>
isinstance
([], Iterable)
True
>>>
isinstance
({}, Iterable)
True
>>>
isinstance
(
'abc'
, Iterable)
True
>>>
isinstance
((x
for
x
in
range
(
10
)), Iterable)
True
>>>
isinstance
(
100
, Iterable)
False
2 for i in 100:
print(i)
迭代器
*可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
可以使用isinstance()
判断一个对象是否是Iterator
对象:
1
2
3
4
5
6
7
8
9
|
>>> from collections import Iterator >>> isinstance ((x for x in range ( 10 )), Iterator) True >>> isinstance ([], Iterator) False >>> isinstance ({}, Iterator) False >>> isinstance ( 'abc' , Iterator) False |
通过上面的表可以看到list,dict,str虽然是Iterable,但不是Iterator
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
Iterator是只有需要返回下一步运算的时候才会计算
小结
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python的for
循环本质上就是通过不断调用next()
函数实现的,例如:
1
2
|
for x in [ 1 , 2 , 3 , 4 , 5 ]: pass |
实际上完全等价于:
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break