在了解装饰器之前,我们必须了解闭包是什么?
如果在一个函数中又定义一个函数,那么又定义的这个函数被称为内部函数,而原本的函数被称为外部函数。
而闭包的概念就是在外部函数中定义了一个内部函数,并且在内部函数中调用了外部函数的变量,最后外部函数的返回值是内部函数的引用。
闭包例子:
1 #闭包的实例 2 # outer是外部函数 a和b都是外函数的临时变量 3 def outer( a ): 4 b = 10 5 # inner是内部函数 6 def inner(): 7 #在内部函数中 用到了外部函数的临时变量 8 print(a+b) 9 # 外部函数的返回值是内部函数的引用 10 return inner 11 12 if __name__ == '__main__': 13 func = outer(1) 14 # 在func变量中是outer的返回值即inner函数的引用 15 func() # 结果11 16 # 调用了inner函数输出结果为11
使用闭包的过程中,一旦外部函数被调用一次,返回了内部函数的引用,虽然每次调用内部函数,是开启一个函数执行,过后消亡,但是闭包变量实际上只有一份,每次开启内部函数都在使用同一份闭包变量。
1 def outer(a): 2 def inner(b): 3 nonlocal a 4 a += b 5 return a 6 return inner 7 o = outer(10) 8 print(o(1)) 9 print(o(3))
闭包的概念已经知道了,那么什么是装饰器呢?
简单的来说装饰器就是对原有的函数根据需要添加新的功能。下面举一个简单的例子:
原有函数
def printinfo(): print('你好')
如果需要计算该函数的执行时间在不改变原有代码的基础上实现
import time def time_sum (printinfo): def inner(): start_time = time.time() printinfo() time.sleep(1) end_time = time.time()-start_time return end_time return inner @time_sum def printinfo(): print('你好') a = printinfo() print(a)
上面的例子是没有参数的,为了使这个程序具有通用性可以对其进行优化,利用不定长参数*args,**kwargs,使得程序能够接受任意参数。
1 def time_sum (func): 2 def inner(*args,**kwargs): 3 start_time = time.time() 4 func(*args,**kwargs) 5 time.sleep(1) 6 end_time = time.time()-start_time 7 return end_time 8 return inner
多个装饰器执行的顺序就是从最后一个装饰器开始,执行到第一个装饰器,再执行函数本身。
列表生成式
列表生成式,是Python内置的一种强大的生成list的表达式。
1 list1 = [i for i in range(0,101) if i%2 == 0] 2 print(list1)
list1 = [i*i for i in range(0,7)] print(list1)
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
在Python中,一边循环一边计算的机制,称为生成器:generator。
生成器
要创建一个简单的generator,只要把一个列表生成式的[]
改成()
,就创建了一个generator,但是对于生成器我们可以利用next()或取到下一个元素。但是基本上永远不会调用next()
,而是通过for
循环来迭代它。
g = (i for i in range(101)) for i in g: print(i)
还有一种方法创建生成器。如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator。
1 def fab(max): 2 n, a, b = 0, 0, 1 3 while n < max: 4 yield b # 使用 yield 5 # print b 6 a, b = b, a + b 7 n = n + 1 8 9 for n in fab(5): 10 print n
1 def triangles(): 2 N=[1] 3 while True: 4 yield N 5 N.append(0) 6 N=[N[i-1] + N[i] for i in range(len(N))] 7 8 if __name__ == '__main__': 9 n=0 10 for t in triangles(): 11 print(t) 12 n=n+1 13 if n == 10: 14 break
迭代器
表示数据流的对象。重复调用迭代器的 __next__()
方法(或将其传递给内置函数 next()
)返回流中的连续项。当没有更多数据可用时,StopIteration
会引发异常。此时,迭代器对象已耗尽,并且对其__next__()
方法的任何进一步调用 StopIteration
再次引发。迭代器需要有一个__iter__()
返回迭代器对象本身的方法,因此每个迭代器也是可迭代的,并且可以在大多数接受其他迭代的地方使用。一个值得注意的例外是尝试多次迭代传递的代码。list
每次将容器对象(例如a )传递给iter()
函数或在函数中使用它时,它都会生成一个全新的迭代器 for
环。使用迭代器尝试此操作只会返回上一次迭代过程中使用的相同耗尽的迭代器对象,使其看起来像一个空容器。
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。