函数小结
函数小结
目录
-
初识函数
- 函数的本质
- 函数的语法结构
- 函数的定义与调用
- 函数的分类
- 函数的返回值
-
函数的参数
- 参数的简介
- 位置参数
- 关键字参数
- 默认值参数
- 可变长参数
- 命名关键字参数
-
名称空间
-
名称空间的分类
-
名称的查找顺序
-
global 和 nonlocal关键字
-
函数名的多种使用方式
-
-
闭包函数
- 闭包函数的简介
- 闭包函数的实际应用
-
装饰器
-
装饰器的简介
-
装饰器的原则
-
装饰器推到前需了解的小知识
-
装饰器的固定模板
-
多层装饰器
-
有参装饰器
-
-
递归函数
-
递归函数的概念
-
直接和间接调用递归函数实例
-
-
算法
- 二分法
-
三元表达式
- 三元表达式的使用
- 三元表达式的语法结构
- 三元表达式的实例
-
各种生成式
- 列表生成式
- 字典生成式
- 集合生成式
-
匿名函数
- 匿名函数简介
- 匿名函数的语法结构
- 匿名函数与内置函数的结合
-
内置函数
- map( )映射
- filter()
- reduce()
- zip()
初始函数
-
函数的本质
函数的本质就是将程序段提前定义好,封装成函数,然后才能调用
-
函数的语法结构
def 函数名 ( 形参) # def 定义函数的关键字
# 函数名---指向函数的内存地址 # 括号内定义的是参数,可有可无,且无需指定参数类型
""" 文档描述 """ # 为了描述函数的功能,介绍函数的相关信息
函数体 # 函数体 由语句和表达式组成,就是相关代码
return 值 # 定义函数的返回值
- 函数的定义与调用
-
函数必须先定义在调用
-
定义函数使用def 关键字 ,调用函数使用函数名加括号(可能参加额外的参数)
-
函数在定义阶段只检测函数体代码语法,不执行函数体代码
- 函数的分类
-
内置函数
内置函数就是解释器提前定义好的函数,可以直接调用
-
自定义函数
(1)空函数
空函数就是函数体代码用pass代替,暂且没有任何功能
主要用于项目的搭建,提醒其功能
(2)无参函数
函数定义阶段括号内没有填写参数
-
有参函数
函数定义阶段括号内填写了参数
在调用的时候,必须函数名加括号且给于数据值
-
函数的返回值
函数的返回值就是调用函数后产生的结果,获取的方式是固定的返回值的五种返回方式:
- 函数体代码没有return关键字:默认返回None
- 函数体代码有return 后面没有返回值,默认返回None
- return 后有什么就返回什么(如果是数据值则直接返回 如果是变量则需要找到对应的数据值返回)
- 若后面有多个数据值,这默认自动组成元组返回
- 函数体代码遇到return关键字会立刻结束函数体代码的运行
函数的参数
-
函数的简介
函数的参数分为形参和实参两大类形参:在定义函数时,所需定义的值。本质就是变量名,用来接收外部传来的值。
实参:在调用函数时,所需输入的值。本质就是数据值(可以是常量,变量,表达式或三者的结合)
在函数调用阶段形参会临时与实参进行绑定 函数运行结束立刻解除
-
位置参数
位置参数就是按照从左到右的顺序定义的,形参和实参的位置是一一对应的
-
关键字参数
关键字参数是在定义阶段,可以不安顺序执行,但与位置参数联用时,关键字参数需要在其后面
-
默认值参数
默认值参数就是在函数定义阶段,( ) 中以 ... = ... 的形式填写的形参
-
可变长参数
可变长形参与实参可以随意传值
'*'和'**'在可变长参数的作用
'*'在形参中接收多余的位置参数组合成元组的形式赋值给 其后面的变量名
在实参中,获取的是可迭代对象的值
'**'在形参中,接收到多余的关键字组合成字典的形式,交付给后面的变量名
在实参中,获取的是可迭代对象的V值
-
命名关键字参数
在定义了**kwargs参数后,函数调用者就可以传入任意的关键字参数key=value,如果函数体代码的执行需要依赖某个key,必须在函数内进行判断
名称空间
名称空间就是用来存放变量名和数据值之间绑定关系的地方
-
名称空间的分类
| 名称空间分类 | 各个名称空间作用 | 作用域 | 存活周期 |
| ------------ | ------------------------------------------------------------ | ---------------------------------- | ---------------------------------------- |
| 内置名称空间 | python解释器运行就会立刻创建的空间,写代码过程中可以直接使用的名字都在该空间中 | 在程序任意位置都可以使用(全局有效) | 解释器运行(创建),解释器关闭(销毁) |
| 全局名称空间 | py文件运行代码过程中产生的名字都会存入该空间 | 在程序任意位置都可以使用(全局有效) | py文件运行(创建) , py文件结束(销毁) |
| 局部名称空间 | 函数体代码运行过程中产生的名字都会存入该空间 | 在各自的局部空间可以使用(局部有效) | 函数体代码运行(创建) 函数体代码结束(销毁 | -
名称空间的查找顺序
查找名字前需要事先确定一下在哪个内存空间在全局名称空间时,先找全局的,再是内置
在局部名称空间时,先找局部,再全局,最后是内置
各自局部名称空间默认的情况下,不能彼此共享名字
-
global 和 nonlocal 关键字
当需要再局部空间中更改全局名称空间的名字时,需要用global 关键字如果是可变类型 则无需关键字声明
在嵌套函数中,若想将内部的局部名称空间更改外层局部名称空间中的不可变类型时需要用nonlocal关键字
-
函数名的多种使用方式
- 函数名可用来多次赋值
def func(): print('from func') name = func name() name1 = name name1()2.函数名可当做函数的实参
def func(): print('from func') def index(a): print(a) a() index(123) name = 'jason' index(name) index(func)- 函数名可当作函数的返回值
def func(): print('from func') def index(): return func res = index() print(res) res()4.函数名可当作容器类型中的数据值
def func(): print('from func') l1 = [1,2,3,4,func] print(l1) l1[-1]()
闭包函数
-
闭包函数的简介
-
闭包函数就是定义在函数内部的函数
-
内部函数用了外部函数的名称空间中的名称
在嵌套函数中,内层函数用了外层函数的变量名 就是闭包函数
-
-
闭包函数的实际应用
将函数体所需要的参数定义成闭包函数的形式
def foun1(x):
def foun():
print(x)
return foun
a = foun1(1/2/3)
a() # 1 2 3
装饰器
-
装饰器的简介
不改变被装饰对象原来的'调用方式' 和'内部代码' 的情况下给被装饰的对象添加新的功能 -
装饰器的原则
能添加功能,但不能修改代码 -
推导装饰器前所需小知识
import time
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
time.time()
'''让程序原地等待'''
time.sleep()
- 装饰器的固定模板
from functools import wrps
def outer(func_name):
@wrps(func_name) # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
def inner(*args, **kwargs):
print('执行被装饰对象前的操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象后的操作')
return res
return inner
@outer # home = outer(真正的函数名home)
def home():
pass
home()
- 多层装饰器
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1 # index = outter1(wrapper2)
@outter2 # wrapper2 = outter2(wrapper3)
@outter3 # wrapper3 = outter3(index函数名)
def index():
print('from index')
"""
语法糖的功能
会自动将下面紧挨着的函数名当成参数传递给@符号后面的函数名(加括号调用)
涉及到多个语法糖装饰一个函数名
从下往上执行 ,最后一个语法糖才会做重命名操作
"""
- 有参装饰器
def login_auth(func_name):
def inner(*args, **kwargs):
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if username == 'jason' and password == '123':
res = func_name(*args, **kwargs)
return res
else:
print('用户权限不够 无法调用函数')
return inner
"""
需求:在装饰器内部可以切换多种数据来源
列表
字典
文件
"""
def outer(condition,type_user):
def login_auth(func_name): # 这里不能再填写其他形参
def inner(*args, **kwargs): # 这里不能再填写非被装饰对象所需的参数
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 应该根据用户的需求执行不同的代码
if type_user =='jason':print('VIP')
if condition == '列表':
print('使用列表作为数据来源 比对用户数据')
elif condition == '字典':
print('使用字典作为数据来源 比对用户数据')
elif condition == '文件':
print('使用文件作为数据来源 比对用户数据')
else:
print('去你妹的 我目前只有上面几种方式')
return inner
return login_auth
@outer('文件','jason')
def index():
print('from index')
index()
"""
我们以后遇到的最复杂的装饰器就是上面的 不会比上面更复杂
目的仅仅是为了给装饰器代码传递更多额外的数据
"""
递归函数
-
递归函数的概念
函数直接或间接调用了函数本身就被称为是递归函数 -
直接或间接调用递归函数
1.直接调用函数
def index():
print('from index')
index()
index()
2.间接调用函数
def index():
print('from index')
func()
def func():
print('from func')
index()
func()
"""
python中允许函数最大递归调用的次数
官方给出的限制是1000 用代码去验证可能会有些许偏差(997 998...)
"""
递推:一层层往下寻找答案
回溯:根据已知条件推导最终结果
算法
- 二分法
l1 = [11, 23, 32, 45, 65, 78, 90, 123, 432, 467, 567, 687, 765, 876, 999, 1131, 1232]
def get_num(l1, target_num):
# 添加递归函数的结束条件
if len(l1) == 0:
print('不好意思 找不到')
return
# 1.先获取数据集中间那个数
middle_index = len(l1) // 2
middle_value = l1[middle_index]
# 2.判断中间的数据值与目标数据值孰大孰小
if target_num > middle_value:
# 3.说明要查找的数在数据集右半边 如何截取右半边
right_l1 = l1[middle_index + 1:]
# 3.1.获取右半边中间那个数
# 3.2.与目标数据值对比
# 3.3.根据大小切割数据集
# 经过分析得知 应该使用递归函数
print(right_l1)
get_num(right_l1, target_num)
elif target_num < middle_value:
# 4.说明要查找的数在数据集左半边 如何截取左半边
left_l1 = l1[:middle_index]
# 4.1.获取左半边中间那个数
# 4.2.与目标数据值对比
# 4.3.根据大小切割数据集
# 经过分析得知 应该使用递归函数
print(left_l1)
get_num(left_l1, target_num)
else:
print('找到了', target_num)
# get_num(l1, 999)
get_num(l1, 1000)
二分法的缺陷
- 数据集必须是有序的
- 查找的数如果在开头或者结尾,是用二分法的效率会更低。
三元表达式
-
三元表达式的使用
只有再二选一的情况下才能用到三元表达式。可以嵌套使用,但不推荐 -
三元表达式的语法结构
值1 if 条件 else 值2如果If 后面的条件成立 , 则执行 if 前面的值
如果 if 后面的条件不成立, 则使用else后面的值
各种生成式
- 列表生成式
new_list = []
for name in name_list:
new_name = name + '_NB'
new_list.append(nwe_name)
print(new_list)
列表生成式不但支持for循环,还支持if判断
执行if判断的时候,先执行for循环,然后将一个个的数据值交给if判断,最后的结果返回for循环前面处理
列表生成式中只能出现for和if
- 字典生成式
new_dict = {i: 'jason' for i in range(10) if i == 6}
print(new_dict) # {6: 'jason'}
先执行for循环,然后将一个个数据交给if 条件进行判断,最后的结果返回给for的前面进行处理
- 集合生成式
new_set = {i for i in range(10) if i == 6}
print(new_set)
先执行for循环,然后将一个个数据交给if 条件进行判断,最后的结果返回给for的前面进行处理
匿名函数
-
什么是匿名函数
匿名函数就是没有函数名的函数 -
匿名函数的语法结构
lambda 形参 : 返回值(lambda x: x + 1)(123) 直接调用 res = lambda x: x + 1 命名调用 print(res(123)) 匿名函数通常都需要配合其他函数一起使用 用于减少代码
内置函数
-
max( ) / min( ) 与匿名函数相结合
- 如果有多个数据在列表中, 需要求出其中的最大值,用max()直接可求出
- 当用max()获取字典中V值最大值,需要匿名函数来参与调用完成
dic = {
'jason': 100,
'aj': 123,
'Bason': 9999999,
'zero': 888
}
def index(k):
return dic.get(k)
# res = max(dic, key=lambda k: dic.get(k))
res = max(dic, key=index)
print(res) # Bason
当用max()直接获取最大值时,由于其底层相当于for循环。在字典参与for循环时,只有K键才参与,其比较的只是K键进行比对,若想用V值比较时,需用函数或匿名函数来进行调用。
- map( ) 映射
映射:把一个数据通过处理变成另外一个数据,并且数据之间一一对应
l1 = [11, 22, 33, 44, 55, 66]
需求:将列表中所有的数据值自增20
方式1:for循环
方式2:列表生成式
方式3:map函数
res = map(lambda x: x + 20, l1)
print(res) # <map object at 0x000001954B581100>
print(list(res))
"""将l1的数据交给匿名函数X,得到返回值X+20.通过映射返回给res """
def index(a):
return a + 20
res = map(index, l1)
print(list(res))
- filter()
通常用于过滤的功能,需要加入过滤的条件,过滤的对象是所包含的元素之一。
l1 = ['jason', 'kevin', 'oscar', 'tony']
需求:移除数据值里面的jason
方式1:for循环
方式2:列表生成式
方式3:filter()
res = filter(lambda a: a != 'jason', l1)
"""将l1的数据交给匿名函数a,若a不等于'jason'那么通过filter函数,过滤jason """
print(res) # <filter object at 0x00000195F21E6C70>
print(list(res)) # ['kevin', 'oscar', 'tony']
def index(a):
return a != 'jason'
res = filter(index, l1)
print(list(res))
- reduce()
reduce 原理:
当用reduce传值的时候,内部有一个机制,第一次取值的时候分别取两个数值,分别给X,Y
接下来就只传一个值。在最后还可以加一个值
l2 = [1, 2, 3]
需求:求列表中所有数据值的和
方式1:for循环
方式2:sum()
res = sum(l2) # 直接求和
print(res)
方式3:reduce() 将很多单体 变成一个整体
# 不能直接用,导不出reduce,在 from functools import reduce 中
res = reduce(lambda x, y: x + y, l2)
print(res)
- zip()
zip函数可以拼接多个数据值
相当于基于for循环 ,依此去取每一个里面的数据值,然后zip函数自动做拼接操作。若元素不一致,按最少元素的个数来拼接。
zip()
n1 = [1, 2, 3]
n2 = ['jason', 'kevin', 'oscar']
res = zip(n1, n2)
print(res) # <zip object at 0x000002A9E38C7F40>
print(list(res))
n1 = [1, 2, 3, 4]
n2 = [5, 6, 7, 8]
n3 = 'jack'
res = zip(n1, n2, n3)
print(list(res))
n1 = [1, 2, 3, 4, 5, 6, 7]
n2 = [5, 6, 7, 8]
n3 = 'jason'
res = zip(n1, n2, n3)
print(list(res))

浙公网安备 33010602011771号