1 高阶函数
- 含义:接收函数作为参数,或者将函数作为返回的函数就是高阶函数。
- 高阶函数的优点:可以将一个函数作为参数使用,并将该作为参数函数内的代码传递到目标函数中使用。
# -----------------------------举课堂的一个案例----------------------------- #
'''满足用户获得所有偶数的需求'''
the_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 定义一个函数,将制定列表the_lst = [1,2,3,4,5,6,7,8,9,10]中的所有的偶数,保存到一个新的列表中。
def get_even_number(l): # 创建一个get_even_number的函数,用来获取所有的偶数。
new_list = [] # 创建一个新的列表,用来存储原列表中的所有偶数。
for number in l: # 创建一个循环,遍历所有列表中的元素。
if number % 2 == 0: # 创建一个条件,用于判断是否为偶数。
new_list.append(number) # 将偶数添加到该新列表中。
return new_list # 将最后的新列表返回。
print(get_even_number(the_lst)) # 调用get_even_number函数,打印包含了所有偶数的列表。
# ----------------------------------分割线----------------------------------
'''满足用户获得所有大于5的数的需求'''
the_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 定义一个函数,将制定列表the_lst = [1,2,3,4,5,6,7,8,9,10]中的所有大于5的数,保存到一个新的列表中。
def bigger_number(l): # 创建一个bigger_numbe的函数,用来获取所有的大于5的数。
new_list = [] # 创建一个新的列表,用来存储原列表中的所有大于5的数。
for number in l: # 创建一个循环,遍历所有列表中的元素。
if number > 5: # 创建一个条件,用于判断是否为大于5的数。
new_list.append(number) # 将大于5的数添加到该新列表中。
return new_list # 将最后的新列表返回。
print(bigger_number(the_lst)) # 调用bigger_number函数,打印包含了所有大于5的数的列表。
# ----------------------------------分割线----------------------------------
'''为满足用户多样的需求'''
the_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def for_demand(l):
def get_even_number(i): # 定义一个判断是否为偶数的函数。
if i % 2 == 0:
return True
new_list = [] # 创建一个新的列表,用来存储原列表中的所有偶数。
for number in l: # 创建一个循环,遍历所有列表中的元素。
if get_even_number(number):
new_list.append(number) # 将偶数添加到该新列表中。
return new_list # 将最后的新列表返回。
print(for_demand(the_lst)) # 调用for_demand函数,打印包含了所有偶数的列表。
'''
但是并不满足客户任意需求,因为如果客户想要大于5的所有数时,
则需要在函数for_demand中添加新的函数,且要修改if get_even_number(number):这行代码。
如果为获取大于5的所有数的函数名为bigger_number(l),
则需要将if get_even_number(number):改为if bigger_number(number)
即:
'''
the_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def for_demand(l):
def get_even_number(i): # 定义一个判断是否为偶数的函数。
if i % 2 == 0:
return True
def bigger_number(i): # 定义一个判断是否为大于5的函数。
if i > 5:
return True
new_list = [] # 创建一个新的列表,用来存储原列表中的所有大于5的数。
for number in l: # 创建一个循环,遍历所有列表中的元素。
if bigger_number(number):
new_list.append(number) # 将大于5的数添加到该新列表中。
return new_list # 将最后的新列表返回。
print(for_demand(the_lst)) # 调用for_demand函数,打印包含了所有大于5的数的列表。
# ----------------------------------分割线----------------------------------
''' 为满足用户自由选择,使用高阶函数'''
the_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def get_even_number(i): # 定义一个判断是否为偶数的函数。
if i % 2 == 0:
return True
def bigger_number(i): # 定义一个判断是否为大于5的函数。
if i > 5:
return True
# 添加一个参数func,需要传递一个函数对象,即此函数对象就为我们想要的新规则,如求所有奇偶数的列表、求所有大于5的列表等等。
def for_demand(func,l):
new_list = [] # 创建一个新的列表,用来存储客户需要的数。
for number in l: # 创建一个循环,遍历所有列表中的元素。
if func(number):
new_list.append(number) # 将客户需要的数添加到该新列表中。
return new_list # 将最后的新列表返回。
print(for_demand(get_even_number,the_lst))
# 调用for_demand函数,打印包含了所有偶数的数的列表,get_even_number作为函数的实参,不能遗漏。
print(for_demand(bigger_number,the_lst))
# 调用for_demand函数,打印包含了所有大于5的数的列表,bigger_number作为函数的实参,不能遗漏。
2.匿名函数
- filter(function, iterable)是一个高阶函数,其作用是可以对一个列表进行过滤。
function:函数对象; iterable:可迭代对象(序列)。
# -----------------------------举课堂的一个案例-----------------------------
# filter() 高阶函数的使用
lst = [1,2,3,4,5,6,7,8,9,10]
def get_odd_number(i):# 求所有奇数
if i % 2 != 0:
return True
return False
# filter() 返回值为一个filter对象
print(filter(get_odd_number,lst)) # <filter object at 0x0000000002F720F0>
# -----------------------------举课堂的一个案例-----------------------------
# filter() 高阶函数的使用
lst = [1,2,3,4,5,6,7,8,9,10]
def get_odd_number(i):# 求所有奇数
if i % 2 != 0:
return True
return False
# filter() 返回值为一个filter对象
print(list(filter(get_odd_number,lst))) # 如果想得到我们想要的值,则在filter前加上list。
综上可见:我们目的是为了得到所有奇数,却使用filter()函数,大大浪费了计算机内存。接下来介绍匿名函数。
- 匿名函数 lambda(语法糖) 可以用创建一些简单的函数,是函数的另外一种创建方式。
'''
语法
lambda 参数列表 : 返回值
'''
# -----------------------------举课堂的一个案例-----------------------------
# 不使用filter()高阶函数,使用lambda匿名函数,来获取列表中的所有奇数。
'''lambda 第一种使用方式'''
get_add_number = lambda a,b : a + b
print(get_add_number(100,200))
'''注意'''
# 在不传递参数的情况下,传递的是lambda对象,所以要传递参数。
print(get_add_number)
# <function <lambda> at 0x00000000031E5400>
# --------------------------------分割线--------------------------------
'''lambda 第二种使用方式'''
print((lambda a,b : a + b)(100,200))
# 在不传递参数的情况下,传递的是lambda对象,所以要传递参数。
'''注意'''
print(lambda a,b : a + b)
# <function <lambda> at 0x00000000031E5400>
lambda的优点:
1.在程序中只会调用一次,调用之后从内存中消失。
2.使用简单、方便。
lambda的限制:
1.不能写复杂的语句,如for循环、遍历等等。
3 闭包
- 含义:将函数作为返回值返回的函数就是高阶函数
# -----------------------------举课堂的一个案例-----------------------------
def fn_1(): # fn_1 为高阶函数。
def fn_2(): # 函数内部创建一个函数fn_2。
print('Hallo Python')
return fn_2 # 返回一个函数对象。
print(fn_1()) # 打印fn_1的返回值fn_2函数对象。但不但会fn_2函数内代码。
# <function fn_1.<locals>.fn_2 at 0x0000000002FC5400>
# ---------------------------------分割线----------------------------------
'''如果想返回fn_2内的代码。'''
def fn_1(): # fn_1 为高阶函数。
def fn_2(): # 函数内部创建一个函数fn_2。
print('Hallo Python')
return fn_2 # 返回一个函数对象。
r = fn_1()
r() # 由于没有返回值直接r()
闭包作用:通过闭包可以创建一些只有当前函数能够访问的变量,可以将一些重要或不希望别人看见的函数隐藏在函数中。
# -----------------------------举课堂的一个案例-----------------------------
# 列表内所有数的平均数。
lst = [30,50,10,20,80]
# sum()求列表中元素之和。
print(sum(lst)/len(lst))
# 结果为 38
# ---------------------------------分割线----------------------------------
# 定义一个函数来求多个数的平均数。
lst = [] # 创建一个空列表
def average(n): # n 为添加到列表中的数
lst.append(n)
return sum(lst)/len(lst)
print(average(10), lst) # lst = [10] 10 / 1 = 10
print(average(10), lst) # lst = [10, 10] 20 / 2 = 10
lst = [] # 当有特殊情况,不小心添加了lst = [],会将前面已经添加了元素的列表lst,重新变成了空值。
# 重新开始计算。
print(average(10), lst) # lst = [10] 10 / 1 = 10
# 或者添加了 lst.append('python')
print(average(10), lst) # 就会报错!!!
为了解决以上问题,使用闭包原理。
# -----------------------------------课堂解决方案-----------------------------------
def make_fn():# 创建一个外函数
lst = [] # 将空列表存储在make_fn函数中,不受make_fn函数外的与句影响。
def average(n): # n 为添加到列表中的数 average 函数就是闭包。
lst.append(n)
return sum(lst)/len(lst)
return average
fn = make_fn()
print(fn(10)) # lst = [10] 10 / 1 = 10
print(fn(10)) # lst = [10, 10] 20 / 2 = 10
lst = [] # 不影响make_fn函数内的lst列表。
print(fn(10)) # lst = [10, 10, 10] 30 / 1 = 10
总结:形成闭包的条件
1 函数需要嵌套。
如make_fn 函数内还有一个 average 函数。
2 将内部函数作为返回值返回。
内部函数average 返回值为 sum(lst)/len(lst)。
3 内部函数必须要使用到外部函数的变量。
外部函数变量 lst = [ ] 的值在不停增加。
4 装饰器
# -----------------------------------课堂案例-----------------------------------
# 创建简单的几个函数
def add(number1, number2): # 创建两个数相加的函数。
return number1 + number2 # 求任意两个数的和。
def mul(number1, number2): # 创建两个数相乘的函数。
return number1 * number2 # 求任意两个数的积。
number_add = add(1, 2)
print(number_add) # 3
number_mul = add(2, 4)
print(number_mul) # 8
# -----------------------------------分割线-----------------------------------
# 案例修改语句...
'''
目前为止直接修改函数代码来满足需求,但会遇到问题:
如果函数太多,修改麻烦。
后期维护麻烦。
违反开闭原则(ocp) 要求对开发程序的扩展,但要求关闭对程序修改。
'''
def add(number1, number2): # 创建两个数相加的函数。
print('开始工作...')
result = number1 + number2 # 求任意两个数的和。
print('结束工作...')
return result
def mul(number1, number2): # 创建两个数相乘的函数。
return number1 * number2 # 求任意两个数的积。
number_add = add(1, 2)
print(number_add)
'''
开始工作...
结束工作...
3
'''
# -----------------------------------分割线-----------------------------------
# 再不修该函数的情况下,扩展函数
def add(number1, number2): # 创建两个数相加的函数。
return number1 + number2 # 求任意两个数的和。
def new_add(number1, number2): # 不违反ocp原则,再创建一个新的函数。
print('开始工作...')
result = add(number1, number2)
print('结束工作...')
return result
result = new_add(1,2)
print(result)
'''
开始工作...
结束工作...
3
'''
'''如果还要添加mul,则需要重新添加 new_mul函数,十分麻烦'''
# -----------------------------------分割线-----------------------------------
'''引入装饰器'''
def start_end():
# 用来对其他的函数进行扩展,扩展功能,添加两个打印语句。
# 创建一个函数
def new_function():
pass
# 返回新的函数
return new_function
result = start_end()
print(result) # <function start_end at 0x00000000031D6378>
# -----------------------------------分割线-----------------------------------
def other_function():
print('Hello World')
def start_end(old): # 参数old 用来扩展参数
def new_function():
print('Start.......')
old()
print('End.......')
return new_function
result = start_end(other_function)
result()
'''
Start.......
Hello World
End.......
'''
# -----------------------------------分割线-----------------------------------
# 再添加一个函数。
def add(number1, number2): # 创建两个数相加的函数。
return number1 + number2 # 求任意两个数的和
def start_end(old): # 参数old 用来扩展参数
def new_function(number1, number2):
print('Start.......')
result = old(number1, number2)
print('End.......')
return result
return new_function
result_1 = start_end(add)
result_2 = result_1(1,2)
print(result_2)
'''
Start.......
End.......
3
'''
'''发现依旧很麻烦,需要修改start_end函数内的代码'''
# -----------------------------------分割线-----------------------------------
def other_function():
print('Hello World')
def add(number1, number2): # 创建两个数相加的函数。
return number1 + number2 # 求任意两个数的和
def start_end(old): # 参数old 用来扩展参数
def new_function(*number1, **number2):
print('Start.......')
result = old(*number1, **number2)
print('End.......')
return result
return new_function
result = start_end(other_function)
result()
result_1 = start_end(add)
result_2 = result_1(1,2)
print(result_2)
类似start_end(old) 这一类函数我们称之为装饰器。
通过装饰器,可以在不修改原函数的情况下,对其他函数进行扩展。
在开发中,都是运用装饰器来对函数进行扩展的。
程序员千万不要去修改同事的代码
def start_end(old): # 参数old 用来扩展参数
def new_function(*number1, **number2):
print('Start.......')
result = old(*number1, **number2)
print('End.......')
return result
return new_function
@start_end # 使用@符号来扩展
def speak():
print('figting')
speak()
5 命名空间
- 使用 locals() 来获取当前作用域的命名空间,且返回一个 字典。
# -----------------------------------课堂案例-----------------------------------
a = 10
def f():
print('Hello Python')
scope = locals()
print(scope)
# 在locals()返回的字典内查询不存在的key-value。
a = 10
def f():
print('Hello Python')
scope = locals()
scope['c'] = 123 # 向命名空间内添加了一个key-value,等于在全局中创建一个变量
print(c)
print(scope)
# 在函数内使用locals()。
a = 10
def f():
print('Hello Python')
scope = locals()
scope['c'] = 123
print(scope)
f()
不要使用locals()在当前域中添加值。