16.Python之函数
Python之函数
-
什么是函数
- 函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段。
-
为什么要用函数
- 函数能提高应用的模块性和代码的重复利用率。
-
如何定义函数
-
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号(),圆括号之间可以用于定义参数;
-
函数内容以冒号起始,并且缩进;
-
函数的第一行语句一般使用多行注释来阐述函数的作用。
-
return [表达式] 结束函数,选择性地返回一个值给调用方。返回值可以是单个值,也可以是被元组包裹的多个值,不带表达式的return相当于返回 None。
-
函数内尽量避免使用print();
def func(): ''' 描述一下这个函数是干什么的 :return: ''' pass
-
-
函数的调用
-
当定义一个函数后,函数内的所有代码都不会执行,只有调用函数时函数才会被执行
def func(): ''' 描述一下这个函数是干什么的 :return: ''' pass func() # 只有调用函数的时候,函数内的代码才会执行
-
-
函数的参数
-
函数的参数分为实参和形参,实参是调用函数时传入的参数,形参是定义函数时定义的参数
def func(a): # a就是形参 ''' 描述一下这个函数是干什么的 :return: ''' pass func('实参')
-
-
函数的实参分为3种:
-
位置实参:安照顺序传值,从左到右,与形参一一对应
def func(a, b): # a = 1,b = 2 ''' 描述一下这个函数是干什么的 :return: ''' pass func(1, 2) # 位置形参安照顺序传值,从左到右,与形参一一对应
-
关键字实参:按照关键字对形参进行传值
def func(a, b, c): # a = 1, b = 2, c = 3 ''' 描述一下这个函数是干什么的 :return: ''' pass func(c=3, a=1, b=2) # 按照关键字对形参进行传值
-
混合实参:位置实参与关键实参混合使用,关键字实参一定要放在位置实参之后
def func(a, b, c, d): # a = 1, b = 2, c = 3, d = 4 ''' 描述一下这个函数是干什么的 :return: ''' pass func(1, 2, d=4, c=3) # 当使用混合参数时,关键字实参一定要放在位置实参之后
-
-
函数的形参分为4种:
-
位置形参:按照位置从左到右接收实参传入的对象。
-
默认形参:将经常使用的参数,设置一个默认值,调用函数的时候,可以省略给默认形参传值。
def func(a, b, c=3): # c = 3 就是默认形参 ''' 描述一下这个函数是干什么的 :return: ''' pass func(1, 2) # 默认参数的陷阱 count = 1 def func(a,b=[]): b.append(a) return b ret1 = func(10) print(ret1) # [10] ret2 = func(20) print(ret2) # [10, 20] # 如果函数中的默认参数是一个可变数据类型,那么无论调用多少次这个函数,使用的都是同一个内存地址的数据。 count = 1 def func(a,b=[]): b.append(a) return b ret1 = func(10) ret2 = func(20) print(ret1) # [10, 20] print(ret2) # [10, 20]
-
仅限关键字形参
-
万能形参:可以接收任何形式的参数
def func(*args, **kwargs): ''' 描述一下这个函数是干什么的 :return: ''' pass func(1, '任意值', c=[2,3], d=4)
万能形参之所以可以接收任何形式的参数,奥秘在于变量args前面的 * 和变量kwargs前面的 ** ;
在定义函数时,args前面的 * 可以聚合传入的一切位置实参,将传入的所有位置实参生成一个元组;而kwargs前面的 ** 可以聚合传入的一切关键字实参,将传入的所有关键字实参生成一个字典。
def func(*args, **kwargs): ''' 描述一下这个函数是干什么的 :return: ''' print(args) # args = (1, '任意值') print(kwargs) kwargs = {'c': [2, 3], 'd': 4} func(1, '任意值', c=[2,3], d=4)
在调用函数时,使用 * 则会打散位置实参传入的一切可迭代对象,并生成一个元组;使用 ** 会将字典打散后聚合成一个字典。
def func(*args, **kwargs): ''' 描述一下这个函数是干什么的 :return: ''' print(args) # (1, '任', '意', '值', 2, 3, 4, 5) print(kwargs) # {'a': 6, 'b': 7} func(1, *'任意值', *[2,3], *(4,5), **{'a':6}, **{'b':7})
-
-
形参的顺序:位置参数,args, 默认参数,仅限关键字参数,*kwargs。
-
函数的名称
-
函数名指向的是函数的内存地址
def func(): print('函数变量名') print(func) # 输出结果: <function func at 0x000001797CDD93A0>
-
函数名本质上就是一个变量
def func1(): print('func1') def func2(): print('func2') func1 = func2 func1() # 输出结果:func2
-
函数名可以作为容器数据类型(元组、列表、字典等)的元素
def func1(): print('func1') def func2(): print('func2') def func3(): print('func3') l = [func1, func2, func3] for i in l: i() ''' 输出结果: func1 func2 func3 '''
-
函数名可以作为函数的参数
def func1(): print('func1') def func2(x): x() print('func2') func2(func1) ''' 输出结果: func1 func2 '''
-
函数名可以作为函数的返回值
def func1(): print('func1') def func2(x): print('func2') return x ret = func2(func1) ret() ''' 输出结果: func2 func1 '''
-
-
三元运算
-
如果一个函数中有且仅有一个 if……else 条件判断语句,那么这个函数可以简写成如下的三元运算:
a = 1 b = 2 if a > b: c = a else: c = b # 可以简写成: a = 1 b = 2 c = a if a > b else b # 写比较两个值大小的函数,输出较大的值 def func(a, b): if a > b: return a else: return b ret = func(1,2) print(ret) # 使用三元运算可以写成如下形式: def func(a, b): return a if a > b else b ret = func(1,2) print(ret)
-
-
lambda(匿名函数)
-
匿名函数就是一句话函数,使用lambda关键字创建匿名函数,函数冒号前面的是形参,冒号后面的表达式有且只能有一个。匿名函数自带return,而return的结果就是表达式的计算后的结果。
# 普通函数 def func(a, b): return a + b func(1,2) # 输出结果:3 # 匿名函数 func = lambda a, b: a + b print(func(1,2)) # 输出结果:3 # 匿名函数与三元表达式结合 func = lambda a, b: print(a) if a > b else print(b) func(1,2) # 输出结果:2
-
-
Python的内置函数
Python将一些常用的功能封装成了内置函数,需要直接调用,避免了重复造轮子的过程。
以下介绍一些常用的内置函数:
-
eval()
将字符串内的表达式拿出来运行一下,并拿到该表达式的运行结果。在网络传输、用户输入和SQL注入时绝对不要使用!有可能会遭到黑客攻击!s_1 = '1 + 2' s_2 = '{"a":1, "b":2}' print(eval(s_1)) # 3 print(eval(s_2)) # {'a': 1, 'b': 2}
-
exec()
与eval()
相似,但exec()
用于处理字符串中的代码流。msg = ''' for i in range(10): print(i) ''' exec(msg) # 会执行msg中的代码
-
min()
:返回给定参数的最小值,参数可以为序列。# 求出dic中最小的值 dic = {'a':1,'b':2,'c':3} result = min(dic,key=lambda value: dic[value]) print(result)
-
max()
:返回给定参数的最大值,参数可以为序列。 -
sorted()
:对所有可迭代的对象进行排序操作。# 求出sults_list中的人按照成绩从高到低进行排序 sults_list = [('a', 72), ('b', 83), ('c', 98), ('d', 92)] result = sorted(sults_list, key=lambda value: value[1], reverse=True) print(result) # [('c', 98), ('d', 92), ('b', 83), ('a', 72)]
-
filter()
:用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。# 筛选出列表l中大于5的数字 l = [2,4,5,7,3,9,6,8] # print([i for i in l if i > 3]) # 通过列表推导式也可以筛选出来 # filter()循环列表l,将l中的每个元素放到lambda函数中,var > 3 为True的留下。 result = filter(lambda var: var > 3, l) # 返回的是迭代器 print(list(result)) # [4, 5, 7, 9, 6, 8]
-
map()
:会根据提供的函数对指定序列做映射。# 计算列表中各个元素的平方 l = [2,4,5,7,3,9,6,8] result = map(lambda var: var ** 2, l) print(list(result)) # [4, 16, 25, 49, 9, 81, 36, 64]
-
abs()
:取绝对值 -
all()
:括号中传入可迭代的对象,在传入的可迭代对象当中的所有值都为Ture,返回的布尔值才为Ture;如果可迭代的对象为空,则返回Ture。 -
any()
:括号中传入可迭代的对象,在传入的可迭代对象中只要有一个值为Ture,返回的布尔值就为Ture;如果可迭代的对象为空,则返回False。 -
bin()
:将十进制转换成二进制。 -
oct()
:将十进制转换成八进制。 -
hex()
:将十进制转换成16进制。 -
bool()
:制造布尔值,其中0、None、空为False。 -
bytes()
:制造bytes类型res = ‘Hello’.encoding('utf-8') 等同于 res = bytes(‘Hello’,encoding='utf-8')
-
callable()
:判断一个对象是否可以调用 -
chr()
:把数字按照ascii码表转成字符。 -
ord()
:把字符按照ascii码表转换成数字。 -
dir()
:查看()内对象能够通过.调用哪些方法。 -
divmod(x,y)
:计算x除以y的商与余 -
enumerate()
:用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据序号,一般用在 for 循环当中。 -
globals()
:查看全局作用域中的名字与值的绑定关系。 -
locals()
:查看局部作用域中的名字与值的绑定关系。 -
hash()
:检测数据类型是可变还是不可变;可hash的类型相当于不可变的类型,不可hash的类型相当于可变类型。 -
help()
:查看函数的帮助信息。 -
id()
:用于获取对象的内存地址。 -
len()
:返回对象(字符、列表、元组等)长度或项目个数。 -
iter()
:相当于.iter() -
next()
: 相当于.next() -
open()
;用于打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写。 -
pow()
:pow(x,y,z) 表示x的y次方对z取余. -
range()
:可创建一个整数列表,一般用在 for 循环中。 -
reversed()
:返回一个反转的迭代器。 -
round()
: 四舍五入。 -
slice()
:实现切片对象,主要用在切片操作函数里的参数传递。 -
sum()
:进行求和计算. -
vars()
:如果不传值等同于locals(),传值后等同于object.dict -
zip()
:拉链函数,函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。可以使用 list() 转换来输出列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 ***** 号操作符,可以将元组解压为列表。s = 'ABCDEF' tu = ('a','b','c','d','e') l = [1,2,3,4] obj = zip(s,tu,l) print(obj) # <zip object at 0x00000241044AFD00> print(list(obj)) # [('A', 'a', 1), ('B', 'b', 2), ('C', 'c', 3), ('D', 'd', 4)]
面向对象里的重点内置函数:
classmethod()
staticmethod()
property()
delattr()
hasattr()
getattr()
setattr()
isinstance()
issubclass()
object()
super()
注意:凡是有默认形参
key=None
的内置函数,将key赋值后key=函数名称
,它会自动将可迭代对象的每一个元素按照顺序传入key的函数中 -
-
高阶函数
函数在Python中是第一类对象,第一类对象的特性有:
-
可以被引用
def bar(): print('form bar') f=bar
-
可以当做参数传入
def bar(): print('form bar') def wrapper(func): func() wrapper(bar)
-
可以当做函数的返回值
def bar(): print('form bar') def foo(func): return func f=foo(bar) print(f)
-
可以当作容器类型的元素
def get(): print('form get') def put(): print('form get') l=[get,put] l[0]() l[1]()
Python中函数为什么可以嵌套或者调用?因为在Python中一切皆对象!
-
-
开放封闭原则
- 对功能的拓展是开放的,对源码的修改是封闭的。
-
闭包函数
- 闭包函数是一种函数的嵌套,当内层函数引用或使用外层函数的非全局变量时就会产生闭包,被引用的外层非全局变量称之为自由变量,这个自由变量会与内层函数产生绑定关系,故而自由变量不会随着函数的执行完毕消失。闭包主要用于保证函数的安全。
-
装饰器
-
在不改变原函数代码、调用方式以及返回值的前提下,为其增加新功能,这就是装饰器。装饰器本质是闭包函数,装饰器遵循开放封闭原则。
def func_1(name): ''' 这是一个实现某个功能函数,内部拥有大量的代码,使用pass代替 :return: ''' pass time.sleep(1) # 模拟函数执行的时间 print(F'func_1执行完毕!参数为:{name}') return 1 def func_2(name_1,name_2): ''' 这是一个实现某个功能函数,内部拥有大量的代码,使用pass代替 :return: ''' pass time.sleep(2) # 模拟函数执行的时间 print(F'func_2执行完毕!,参数为:{name_1},{name_2}') return 2 # 将func_1和func_2加入计算运行时间的功能。要求:不改变原函数代码以及调用方式 import time # 导入时间模块 def omputation_time(var): # 定义一个新功能的函数 ''' 这是一个计算运行时间的函数 :param args: :return: ''' # args = func_1 # args = func_2 def inner(*args,**kwargs): # 为了不改变被装饰函数的调用方式,需要再定义一个内部函数 start_time = time.time() ret = var(*args,**kwargs) # 调用函数时,*会将传入的元组打散 end_time = time.time() print(f'函数执行用时:{end_time - start_time}') return ret # 将被装饰函数的返回值返回给omputation_time,确保被装饰函数的返回值不变 return inner # 返回inner()的函数名 @omputation_time # 语法糖会将下面func_1函数名作为参数传入到omputation_time(args)函数中 def func_1(name): ''' 这是一个实现某个功能函数,内部拥有大量的代码,使用pass代替 :return: ''' pass time.sleep(1) # 模拟函数执行的时间 print(F'func_1执行完毕!参数为:{name}') return 1 ret_1 = func_1('parameter') # 调用函数传入参数,并获取返回值 print(ret_1) ''' 执行结果: func_1执行完毕!参数为:parameter 函数执行用时:1.0006012916564941 1 ''' @omputation_time # 语法糖会将下面func_2函数名作为参数传入到omputation_time(args)函数中 def func_2(name_1,name_2): ''' 这是一个实现某个功能函数,内部拥有大量的代码,使用pass代替 :return: ''' pass time.sleep(2) # 模拟函数执行的时间 print(F'func_2执行完毕!,参数为:{name_1},{name_2}') return 2 func_2('parameter_1', 'parameter_2') # 调用函数传入参数,并获取返回值 ''' 执行结果: func_2执行完毕!,参数为:parameter_1,parameter_2 函数执行用时:2.0002026557922363 '''
-
装饰器的标准语法
def wapper(f): # f表示被装饰的函数名传入时的形参 def inner(*args, **kwargs): # 定义函数阶段*args, **kwargs会将被装饰函数的参数聚合 pass # 可以添加任意代码,完成调用函数之前的功能 ret = f(*args, **kwargs) # 调用函数阶段*args, **kwargs会将被装饰函数的参数打散 pass # 可以添加任意代码,完成调用函数之后的功能 return ret # 返回被装饰函数的执行后的返回值 return inner()
-