今日学习进度: 闭包,装饰器,lambda表达式,装饰器,生成器
1.闭包:
是指在一个函数内部中,对外部作用域的变量进行引用,并且一般内部函数作为外部函数的返回值,那么内部函数就被认为是闭包。
>>> def power(exp):
... def exp_of(base):
... return base ** exp
... return exp_of
...
>>> square = power(2)
>>> cube = power(3)
>>> square
<function power.<locals>.exp_of at 0x000001CF6A1FAF70>
>>> square(2)
4
>>> square(5)
25
>>> cube(2)
8
>>> cube(5)
125
2.装饰器:
在不修改函数的情况下添加新功能,拿函数当参数。
import time
def time_master(func):
def call_func():
print("开始运行程序...")
start = time.time()
func()
stop = time.time()
print("结束程序运行...")
print(f"一共耗费了 {(stop-start):.2f} 秒。")
return call_func
@time_master
def myfunc():
time.sleep(2)
print("I love you")
myfunc()
实现如下:
开始运行程序...
I love you.
结束程序运行...
一共耗费了 2.01 秒
其实等价于:
import time
def time_master(func):
def call_func():
print("开始运行程序...")
start = time.time()
func()
stop = time.time()
print("结束程序运行...")
print(f"一共耗费了 {(stop-start):.2f} 秒。")
return call_func
def myfunc():
time.sleep(2)
print("I love you.")
myfunc = time_master(myfunc)
myfunc()
多个装饰器也可以用在同一函数上:
def add(func):
def inner():
x = func()
return x + 1
return inner
def cube(func):
def inner():
x = func()
return x * x * x
return inner
def square(func):
def inner():
x = func()
return x * x
return inner
@add
@cube
@square
def test():
return 2
print(test())
这样的话,就是先计算平方(square?装饰器),再计算立方(cube?装饰器),最后再加 1(add?装饰器)。 ?
添加多一层嵌套函数来给装饰器传递参数:
import time
def logger(msg):
def time_master(func):
def call_func():
start = time.time()
func()
stop = time.time()
print(f"[{msg}]一共耗费了 {(stop-start):.2f}")
return call_func
return time_master
@logger(msg="A")
def funA():
time.sleep(1)
print("正在调用funA...")
@logger(msg="B")
def funB():
time.sleep(1)
print("正在调用funB...")
funA()
funB()
正在调用funA...
[A]一共耗费了 1.01
正在调用funB...
[B]一共耗费了 1.04
去掉语法糖是这个样子的:
import time
def logger(msg):
def time_master(func):
def call_func():
start = time.time()
func()
stop = time.time()
print(f"[{msg}]一共耗费了 {(stop-start):.2f}")
return call_func
return time_master
def funA():
time.sleep(1)
print("正在调用funA...")
def funB():
time.sleep(1)
print("正在调用funB...")
funA = logger(msg="A")(funA)
funB = logger(msg="B")(funB)
funA()
funB()
3.lambda表达式
语法:
lambda arg1, arg2, arg3, ... argN : expression
lambda 是个关键字,然后是冒号,冒号左边是传入函数的参数,冒号后边是函数实现表达式以及返回值。 如果使用传统的函数定义方式,应该是这样: def <lambda>(arg1, arg2, arg3, ... argN): ... ? ? return expression
举个例子:
>>> def squareX(x):
... return x * x
...
>>> squareX(3)
9
>>> squareY = lambda y : y * y
>>> squareY(3)
9
前者是函数定义的方法,后者是使用lambda表达式
4.lambda 是一个表达式,因此它可以用在常规函数不可能存在的地方:
举个例子,比如放在列表之中:
>>> y = [lambda x : x * x, 2, 3]
>>> y[0](y[1])
4
>>> y[0](y[2])
9
5.与map(),filter()函数混合使用
>>> list(mapped = map(lambda x : ord(x) + 10, "FishC"))
[80, 115, 125, 114, 77]
>>> list(filter(lambda x : x % 2, range(10)))
[1, 3, 5, 7, 9]
6.生成器
在 Python 中,使用了?yield?语句的函数被称为生成器(generator)。
与普通函数不同的是,生成器是一个返回生成器对象的函数,它只能用于进行迭代操作,更简单的理解是 —— 生成器就是一个特殊的迭代器。
在调用生成器运行的过程中,每次遇到?yield?时函数会暂停并保存当前所有的运行信息,返回?yield?的值, 并在下一次执行?yield?方法时从当前位置继续运行。
定义一个生成器,很简单,就是在函数中,使用?yield?表达式代替?return?语句即可。
>>> def counter():
... i = 0
... while i <= 5:
... yield i
... i += 1
现在我们调用?counter()?函数,得到的不是一个返回值,而是一个生成器对象:
>>> counter()
<generator object counter at 0x0000025835D0D5F0>
我们可以把它放到一个?for?语句中:
>>> for i in counter():
... print(i)
...
0
1
2
3
4
5
支持?next()?函数:
>>> c = counter()
>>> next(c)
0
>>> next(c)
1
>>> next(c)
2
>>> next(c)
3
>>> next(c)
4
>>> next(c)
5
next(c)
Traceback (most recent call last):
File "<pyshell#51>", line 1, in <module>
next(c)
StopIteration
由于生成器每调用一次获取一个结果这样的特性,导致生成器对象是无法使用下标索引这样的随机访问方式
7.生成器表达式
>>> t = (i ** 2 for i in range(10))
>>> next(t)
0
>>> next(t)
1
>>> next(t)
4
>>> next(t)
9
>>> next(t)
16
>>> for i in t:
... print(i)
...
25
36
49
64
81
这种利用推导的形式获取生成器的方法,我们称之为生成器表达式。 ?
|