Basis -10 funktion unter der funktion
一、高阶函数
- 定义:
- 1.高阶函数就是接收函数作为参数。
- 2.将函数作为返回值返回的函数。
注:两个条件满足其一,就可以称为高阶函数。
演示示例:
‘’‘
将一个指定的列表中的偶数,保存到一个新的列表中返回。
’‘’
- 普通函数法:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def fn(list1):
new_list = []
for i in list1:
if i % 2 == 0:
new_list.append(i)
return new_list
r = fn(list1)
print(r)
打印输出结果:
[2, 4, 6, 8, 10]
- 高阶函数法:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def fn2(i):
if i % 2 == 0:
return True
def fn1(fn):
new_list = []
for i in liat1:
if fn(i):
new_list.append(i)
retrue new_list
res = fn1(list1)
print(res)
打印输出结果:
[2, 4, 6, 8, 10]
函数执行流程:
- 高阶函数法:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def fn1(i):
if i % 2 == 0:
return True # 返回真值(条件满足则继续向下执行,不满足则返回上部重新执行。)
# 外部函数的作用:可以多次使用,避免代码重复。
def fn(fun, list1): # 将实参fn1()传递给形参fun,完成外部函数的调用。
new_list = []
for i in list1:
if fun(i):
new_list.append(i)
return new_list
r = fn(fn1, list1) # 将函数对象fn1()调用(传参)为实参。就是调用函数fn()内部的代码
print(r)
打印输出结果:
[2, 4, 6, 8, 10]
执行流程:
- 高阶函数的执行流程与嵌套函数是一样的。
- 高阶函数只是将之中的调用函数由单一调用,变成了公共调用,其他函数也可以调用放在外部的公共函数参数。
优缺点:
优点:可以将多层高阶函数变得简洁、规整。
缺点:在多人合作的前提下,容易造成函数名重叠报错。
二、匿名函数
1、过滤函数
- filter()–python的内置过滤函数
- 作用:过滤掉不符合条件的元素,返回符合条件的元素组成新的列表。
- 语法:
- 1.传递函数进去
- 2.传递一个需要被过滤的序列(列表)
演示示例:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def fn1(i):
if i % 2 == 0:
return True
print(filter(fn1,list1)) # 得出对象
print(list(filter(fn1,list1))) # 得出结果
打印输出结果:
<filter object at 0x7fafdf642130>
[2, 4, 6, 8, 10]
注:如果想要得到相应的结果则需要对打印输出结果进行相应转换,否则只会得出结果的函数对象。
二、匿名函数
- lambda()–python中的内置匿名函数
- 特性:
- 1.lambda函数是匿名的:所谓匿名函数,就是没有名字的函数。lambda函数没有名字。
- 2.lambda函数有谱输入和输出:输入就是传入参数列表的值,输出就是根据表达式计算得到的值。
- 3.lambda函数一般功能简单:单行代码表达式决定了lambda函数不可能完成某些复杂的逻辑处理,只能完成简单的功能。由于其实现的功能一目了然,甚至不需要专门的名字来说明。
- 语法:lambda(参数 : 表达式)(参数)
演示示例:
示例1:
def fn(a,b)
reture a + b
fn(1 , 2)
print(lambda a, b: a + b)
print(lambda a , b: a + b)(1 , 2)
打印输出结果:
<function <lambda> at 0x7fd54f1ce040>
3
示例2:
res = lambda a, b: a + b
print(res(1, 3))
# 例如2:
res = (lambda a, b: a + b)(1, 3)
print(res)
打印输出结果:
/Volumes/苹果微软公共盘/PycharmProjects/venv/bin/python /Volumes/苹果微软公共盘/PycharmProjects/基础班第11期/day-10/上课代码/02-匿名函数.py
4
4
Process finished with exit code 0
三、函数的闭包
1、闭包
- 闭包:将函数作为返回值也是高阶函数我们称为闭包。
- 闭包的作用:保存外部函数的变量,不会随着外部函数的调用完毕而销毁。
- 闭包的好处:
- 通过闭包可以创建一些只有当前函数能访问的变量。
- 可以将一些私有数据隐藏带闭包中。
- 闭包的条件:
- 函数嵌套
- 将内部函数作为返回值返回
- 内部函数必须要使用到外部函数的变量
- 注意点:由于闭包引用了外部函数的变量(参数),则外部函数的变量没有及时释放,消耗内存。
演示示例:
def fun_out(num1):
# 定义一个内部函数
def fun_inner(num2):
# 内部函数用到了外部函数的变量或者参数
res = num1 + num2
print(res)
print(id(num1))
fun_inner(2)
print(id(num1))
# 返回函数对象fun_inner
return fun_inner
f = fun_out(1)
f(2)
# f(3)体现闭包的作用
f(3)
打印输出结果;
/Volumes/苹果微软公共盘/PycharmProjects/venv/bin/python /Volumes/苹果微软公共盘/PycharmProjects/基础班第11期/day-10/上课代码/03-函数的闭包.py
4469021376
3
4469021376
3
4
Process finished with exit code 0
2、拓展(nonlocal)
- nonlocal 关键字用来在函数或其他作用域中使用外层(非全局)变量。(我是看不懂这句话)
- 1.如果在内部函数中仅仅读取外部变量,可以不在此变量前加nonlocal。
- 2.如果在内部函数中尝试进行修改外部变量,且外部变量为不可变类型,则需要在此变量前加ninlocal.
- 3.如果变量为可变类型,则变量前不需要添加nonlocal.
演示实例:
def fun_out(num1):
def fun_inner(num2):
nonlocal num1
# nonlocal 关键字用来在函数或其他作用域中使用外层(非全局)变量
# 1. 如果在内部函数中仅仅读取外部变量,可以不在此变量前加nonlocal。
# 2. 如果在内部函数中尝试进行修改外部变量,且外部变量为不可变类型,则需要在变量前加nonlocal。
# 3. 如果变量为可变类型,则变量前不需要添加nonlocal。
num1 = 10
r = num1 + num2
print(r)
print(num1)
fun_inner(2)
print(num1)
return fun_inner
r = fun_out(1)
打印输出结果:
1
12
10
四、装饰器
- 装饰器:简言之,装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于他的返回值也是一个函数,使用python装饰器的好处就在于不用修改原函数代码前提下给函数增加新的功能。
- 我们可以直接修改函数中的代码来完成需求,但是会产生一些问题。
- 如果修改的函数多,修改起来会很麻烦
- 不方便后期维护
- 这样做会违反开闭原则
- 程序设计,要求开发程序的扩展,要关闭对程序的修改
- 一般来说,我们想要扩展原来的代码,最直接的方法就是进入原来的代码。
- 装饰器的作用:
- 为程序扩展新的功能
演示实例:
- 无参数:
def fn1():
print('我是fn1')
# 启用装饰器(装饰fn1)
def fn():
print('函数开始执行!')
fn1()
print('函数执行结束!')
fn()
打印输出结果:
函数开始执行!
我是fn1
函数执行结束!
- 有参数;
def fun_out(fn):
def fun_inner(*args, **kwargs):
print('函数开始执行')
r = fn(*args, **kwargs)
print('函数执行结束')
return r
return fun_inner
@fun_out # 装饰器语法糖的写法
def add(a, b):
return a + b
r = add(1, 2)
print(r)
@fun_out
def qiuji():
print(111)
qiuji()
# f = fun_out(add)
# r = f(1, 2)
# print(r)
# 语法糖: @fun_out 等价于 fun_out(fn)
打印输出结果:
/Volumes/苹果微软公共盘/PycharmProjects/venv/bin/python /Volumes/苹果微软公共盘/PycharmProjects/基础班第11期/day-10/老师上课讲解代码/装饰器的使用.py
函数开始执行
函数执行结束
3
函数开始执行
111
函数执行结束
Process finished with exit code 0
五、装饰器的使用
- 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展。
- 在开发中,我们都是通过装饰器来扩展函数的功能的。
演示实例:
1、普通装饰器:
def fn(fun):
def new_fun():
print('函数执行开始')
fun()
print('函数执行结束')
return new_fun
# 需要的新功能
def fn1():
print('我是fn1')
r = fn(fn1)
r()
打印输出结果:
函数执行开始!
我是fn1
函数执行结束!
函数执行流程:
- 1.首先,fnI()函数就是我们的主函数,也就是需要被装饰的函数。
- 2.fn1()函数就是我们需要为fn()函数添加的新功能。
- 3.将fn1()函数进行吊用,使其称为实参,传参为fun形参。
- 4.fun()调用至装饰器函数new_fun()
- 5.实现新功能返回给new_fun,并打印输出。
2、通用装饰器
演示示例:
def fn(fun):
def new_fun(*args,**kwargs):
print('函数执行开始!')
r = fun(*args, **kwargs)
print('函数执行结束!')
return r
return new_fun
# 需要装饰的函数:
def add(a, b):
return a + b
r = fn(add)
r(1,2)
print(r)
打印输出结果:
函数执行结束!
函数执行开始!
<function fn.<locals>.new_fun at 0x7ffb102ce1f0>
函数执行流程:
与普通装饰器同理
值得注意的是虽然我们输入了实参,但是最后结果,并不是我们想要的结果,而是一个对象.
因为我们赋值的1,2都穿参args,kwargs没有值,虽然a 和b。还是1 和2。
但是**kwargs是None,没有值,导致运算变量r无法正常打印出3.
3、进阶
- 装饰器的语法糖:
演示实例:
def fn(fun):
def new_fun(*args,**kwargs):
print('函数执行开始!')
r = fun(*args, **kwargs)
print('函数执行结束!')
return r
return new_fun
# 需要装饰的函数:
def fn1():
print('我是fn1')
def add(a, b):
return a + b
@fn
def speak():
print('好好学习!')
speak()
打印输出结果:
函数执行开始!
好好学习!
函数执行结束!
注意:
@fn 等价于speak = fn(speak)
六、推倒式
- 列表推倒式:
- 将旧的列表生成一个新的列表。
- 语法:
- [表达式 for 变量 in 旧列表 if 条件]
演示示例:
list1 = ['cheney', 'jerry', 'amy', '居然', 'tony', 'anny', 'james','豆腐', 'wolf']
result = [name for name in list1 if len(name) > 4]
print(result)
打印输出结果:
['cheney', 'jerry', 'james']
- 很简单,没什么可说的 。
七、生成器
- 通过列表推倒式我们可以直接创建出一个列表,但是受内存的限制,我们不可能创造一个无限大的列表。而且创建一个有200万个元素的列表,会占用很大的内存空间,而这个时候我们仅仅需要访问列表中的几个元素,那么后年的元组就占用着空间就是一种浪费的行为。那么我们可不可以用几个元素就创建几个元素。这样在一定程度上优化了内存。那么在python中一种边循环边计算的机制就是生成器。
- 创建方法:
- 方式一:通过推倒式创建
# generator = (表达式 for 变量 in 旧列表 if 条件)
# print(next(generator)) next取值得到数据
# 再用推倒式:r = [表达式 for i in generator]
# print(r) 得到想要的结果
- 方式二:用函数的方式 vield
- 特征一:当使用yield关键字之后,函数不再是函数,而是一个生成器。
- 特征二:当程序执行到yield的时候,程序就会停止,与input()类似。
* 模式一:
def fn():
print('fn执行了!')
i = 1
while True:
yield i
i += 1
r = fn()
print(r)# 变成生成器了
print(next(r))
打印输出结果:
<generator object fn at 0x7fdf7357f430>
fn执行了!
1
* 模式二:
def fn():
print('fn执行了!')
i = 1
while True:
yield i
i += 1
r = fn()
# print(r)# 变成生成器了
print(next(r))
print(next(r))
打印输出结果:
fn执行了!
1
2
- 总结1:只要在函数中出现yield关键字它就是一个新的生成器。
- 总结2:生成器会记住你之取到的元素的位置,下一次继续取数据的时候,它会在那个位置继续往下取数据。
****** 生成器的特性:** - 1.生成器相当于一个容器,当你把容器内部的东西全部取出之后,容器内部就不再有数据。
- 2.生成器只能取一次,用完就没有了。需要你自己在重新生成一次。***
八、迭代器
- 迭代器
- 迭代器就是访问集合元素的一种方式。
- 迭代器是一个可以记住便利位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束。
- 可以被next()函数调用并不断返回下一个值的对象称之为迭代器iterator。
- 生成器时可迭代的,也是迭代器。
- 通过iter()函数可以将可迭代的变成下一个迭代器。
演示示例:
# 创建迭代器
list1 = [1, 2, 3, 4, 5, 6]
iterator = iter(list1)
print(type(iterator))
print(next(iterator))
打印输出结果:
<class 'list_iterator'>
1
在结果处,我们可以看到iterator就已经是一个列表迭代器了。
作业
'''
请使用装饰器实现已存在的函数的执行所花费的时间。
'''
- 代码如下:
import time
def time1(fn):
def time2():
print('装饰器开始执行!')
begin = time.time()
fn()
end = time.time()
print('装饰器结束执行!')
print('函数执行时间为{}'.format(end - begin))
return fn
return time2
@ time1
def time3():
j = 0
for i in range(1, 100000):
j = j + i
print(j)
time3()
打印输出结果:
4999650006
4999750003
4999850001
4999950000
装饰器结束执行!
函数执行时间为0.34472131729125977
Process finished with exit code 0