作为面向对象语言, 函数是python中必须要掌握的一门知识
定义函数的目的就是为了方便使用, 同时也增加了代码的可读性
函数定义def
def test(x): #定义函数
print('test %s time'% x)
test(2) #使用函数,传入参数
#运行结果:
test 2 time
函数的参数
必选参数
调用函数时必需的参数,如果在调用时没有给必选参数赋值就会报错
def fn(x): #此时的x为必选函数
return x*x
fn()
# 运行结果:
TypeError: fn() missing 1 required positional argument: 'x'
默认参数
定义函数时指定初始值的参数,必须要在必选参数之后,即使在调用函数时没有传参,也可以运行
def fn(a=3): #此时的a为默认函数,初始值为3
return a*a
fn()
# Result:
9
不定长参数
位置参数
接收任意数目的参数,组成一个tuple
def fn(*args): #此时的args为位置函数
return args
关键字参数
接收任意数目的键值对,组成一个dict
def fn(**kwargs): #此时的kwargs为关键字函数
return kwargs
这里的args 和kwargs代表普通的tuple和dict变量
内置函数
查看对象信息
id()查看内存地址
>>> a=2
>>> id(a)
140732454724464
type()查看对象的类型
>>> type('string')
<class 'str'>
isinstance()是否为指定类型
>>> isinstance('str',str)
True
常见函数
len() 求长度
s='abcd'
print(len(s))
#运行结果:
4
min() 求最小值
li=[1,2,3,4,5]
print(min(li))
#运行结果:
1
max() 求最大值
li=[1,2,3,4,5]
print(max(li))
#运行结果:
5
reversed() 反向
将序列反过来,镜像
li=[6,3,2,5,4]
a=reversed(li)
print(list(a))
#运行结果:
[4, 5, 2, 3, 6]
sum() 求和
li=[6,3,2,5,4]
print(sum(li))
#运行结果:
20
常见的高阶函数
关键字 | 作用 |
---|---|
sorted | 对列表进行排序,返回一个新的排序后的列表 |
enumerate | 返回一个可以枚举的对象 |
eval(‘1+1’) | 执行字符串中的表达式来求值并返回计算结果 |
exec | 执行字符串中的语句 |
filter | 过滤器 |
map(iterable,function) | 对参数iterable中的每个元素都应用function函数,并将结果作为列表返回 |
zip | 将对象逐一的配对 |
sorted() 排序
可以对序列类型进行正序或反序,sorted中的reverse默认值是False
li=[6,3,2,5,4]
print(sorted(li)) #正序
#运行结果:
[2, 3, 4, 5, 6]
print(sorted(li,reverse=True)) #反序
#运行结果:
[6, 5, 4, 3, 2]
和 li.sort() 的区别,
li=[5,8,4,3,9]
li.sort()
print(li)
#运行结果: #彻底改变了原表的排序
[3, 4, 5, 8, 9]
li=[5,8,4,3,9]
print(sorted(li),li) #只打印排序后的表,不改变原表排序
#运行结果:
[3, 4, 5, 8, 9] [5, 8, 4, 3, 9]
sorted本身是一个高阶函数,他可以传入一个函数,这个函数会对要排序的所有的对象依次进行运算,原算出来的结果作为排序的依据
students = ['bob','nacry','jack','op','kim','lasuadn']
print(sorted(students,key=len)) #传入len函数根据函数的长度排序
#运行结果:
['op', 'bob', 'kim', 'jack', 'nacry', 'lasuadn']
enumerate() 枚举
传入列表,提取元素索引,将索引和值组成一个字典
li=['a','b','c']
a=enumerate(li)
print(list(a))
#运行结果:
[(0, 'a'), (1, 'b'), (2, 'c')]
执行字符串的内容
eval()
执行字符串中的表达式
print(eval('3+2'))
#运行结果:
5
evec()
将字符串中的内容作为代码执行
print(exec('print(123)'))
#运行结果:
123
None
filter() 过滤器
只显示函数中返回True的情况,过滤掉False,返回值为可迭代对象
def fn(x):
if x<3:
return True
else:
return False
li = [1,2,3,4,5]
a=filter(fn,li)
print(list(a))
#运行结果:
[1,2]
map() 映射
将序列内的值作为参数传入函数中,并返回执行结果(可迭代对象)
def fn(x):
return x*x*x
li = [1,2,3]
a=map(fn,li)
print(list(a))
#运行结果:
[1,2]
zip() 配对
将两个序列进行一一配对,输出一个有键值对的可迭代对象,多余的元素会被省略
li1=['a','b','c']
li2=[1,2,3,4]
li3=zip(li1,li2)
print(list(li3))
#运行结果:
[('a', 1), ('b', 2), ('c', 3)]
匿名函数lambda
匿名函数就是没有函数名的函数
lambda只适用于比较简单的表达式,如果单独使用lambda需要将表达式赋值到一个对象上,调用该对象
a=lambda x:x*x
print(a(3))
#运行结果:
9
lambda最适合用在filter、map这类函数上,匿名函数的合理利用能够让代码更加简洁
li=[1,2,3,4,5,6]
a=filter(lambda x:x<4,li) #使用在filter
print(list(a))
#运行结果:
[1,2,3]
li=[1,2,3,4]
a=map(lambda x:x*2,li) #使用在map
print(list(a))
#运行结果:
[2,4,6,8]
函数的作用域
函数的作用域具有以下四条原则:
1. 外部不能访问函数内部变量:
def fun1():
x = 1
return x
print(x)
#运行结果:
NameError: name 'x' is not defined
2. 函数内部能够访问函数外部变量:
x = 123
def fun2():
return x + 1
print(fun2())
#运行结果:
124
3. 函数里面不能修改函数外部变量:
x = 123
def fun3():
x = x + 1
return x
print(fun3())
#运行结果:
UnboundLocalError: local variable 'x' referenced before assignment
4. 函数里面和函数外部变量名可以相同:
此处可以看出,函数内部的局部变量x的内存地址与外部的全局变量x不同
x = 123
print(x, id(x))
def fun4():
x = 456
print(x, id(x))
x += 1
return x
print(fun4())
# 运行结果:
123 140726557930128
456 1889385718864
457
global(全局变量)
函数内部如果需要改变全局变量,就需要使用global修饰变量
x = 123
def fun1():
global x #声明x的作用域为全局变量
x += 1 #声明之后可以更改变量x的值
return x
print(fun1())
# 运行结果:
124
nonlocal(局部变量)
在函数嵌套函数的情况下,同样也有函数作用域的问题,但是python3中提供了方便,只需要使用nonlocal就可以在里层函数内部修改外部函数变量
def fun2():
x = 123
def fun3():
nonlocal x #声明x的作用域为局部变量
x += 1 #声明之后可以更改局部变量x的值
return x
return fun3() #这里用的是一个闭包
print(fun2())
# 运行结果:
124
全局变量与局部变量的关系,请参考:
[外链图片转存失败(img-IeBt5dyN-1564408713891)(C:\Users\zh99294875\AppData\Roaming\Typora\typora-user-images\1547908778872.png)]
高级特性
闭包
要理解闭包首先要知道什么是 嵌套函数
def fun1(): #嵌套函数
print('fun1()在被调用')
def fun2(): #在函数内部定义的函数称为嵌套函数
print('fun2()在被调用')
fun2()
fun1()
# 运行结果:
fun1()在被调用
fun2()在被调用
下面来看一下闭包,闭包是函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包
def fx(x):
x += 1
def fy(y):
return x*y
return fy
print(fx(5)) #这里的fx(5)的返回值是嵌套函数fy,由于fy没有传参因此返回结果是内存地址
# 运行结果:
<function fx.<locals>.fy at 0x0000022B59CC5268>
需要返回实际结果,就要使用以下方法:
print(fx(5)(5))
# 运行结果:
30
闭包是概念,不是某种函数类型,和递归的概念类似,就是种特殊的函数调用
闭包可以得到外层函数的局部变量,是函数内部和函数外部沟通的桥梁
递归
下面通过阶乘来演示一下递归的概念,递归中可以函数自身调用自身,但是使用时类似于条件循环一样,要有递归的终止条件
def jiecheng(x):
if x==1: #终止条件,当x为1时停止调用自身,返回1
return 1
return jiecheng(x-1)*x
print(jiecheng(5))
# 运行结果:
120
回调
自身是一个函数,只是被传入到另一个函数当中,供其调用。回调函数不一定会被调用,是否调用由被传入函数的内部逻辑决定
def a(fn):
fn()
def b():
print('b被调用了')
a(b) #b被传入函数a后,变成b(),也就是fn()==>b()
# 运行结果:
b被调用了