函数:组织好的、可以重复利用的、用户实现单一或者关联功能的代码段,函数能够提高应用的模块性和代码的重复利用率。
函数的定义规则
函数代码块以def关键词开头,后接函数标识符名称和圆括号()
任何传入参数和自变量必须放在圆括号中间
函数的第一行语句可以选择性的使用文档字符串----用于存放函数说明
函数内容以冒号起始,并且缩进
定义函数
语法:
def 函数名([参数列表]): #参数列表可选项函数体
例如:
def PName(): #使用def定义一个函数PName()
print('hello world')
PName() #调用函数
调用函数
python内置了很多函数,内置函数可以直接调用,调用一个函数需要知道函数的名称和函数的参数。
语法:
函数名([参数列表])
函数名其实就是指向一个函数对象的引用,完全可以把函数名赋值给一个变量,相当于给这个函数起了一个别名。
例如:
student = [1,2,3,4,5]
a = len #变量a指向len函数
num = a(student) #可以通过a调用len函数
print('student列表元素的个数为:',num)
结果为:
student列表元素的个数为: 5
注意:
1.遇到行数定义时,不会去执行内部代码,只有遇到函数调用时,才会去执行函数体内部代码
2.执行完内部代码后,又回到调用函数的地方,继续向下执行
3.如果没有调用函数的话,函数体内部代码是不会执行的
函数的参数
位置参数
:调用函数时根据函数定义的参数位置来传递参数
例如:定义一个参数,函数有3个参数name,age,gender
def UserInfo(name,age,denger):
print(f'你的名字为:{name},年龄为:{age},性别为:{denger}')
UserInfo('张三',18,'男') #需要放实参,个数和位置需要和形参一一对应,否则报错
结果为:
你的名字为:张三,年龄为:18,性别为:男
关键字参数
:函数调用时通过"键" = "值"形式加以指定,可以让函数更加清晰、容易使用。
例如:
def getInfo(name,address):
print('大家好我叫%s,我来自%s'%(name,address))
getInfo(name='张三',address='西藏') #给实参加上关键字,关键字对应形参
结果为:
大家好我叫张三,我来自西藏
参数的默认值
:在声明函数的时候给形参先赋值,携带默认值形参放在最右边
例如一:
def getInfo(name,address = '西藏')
print('大家好我叫%s,我来自%s'%(name,address))
getInfo('张三') #有默认值的形参,可以不用传递
结果为:
大家好我叫张三,我来自西藏
例如二:
def getInfo(name,address = '西藏')
print('大家好我叫%s,我来自%s'%(name,address))
getInfo('张三','新疆') #传递参数,会覆盖原来的默认值
结果为:
大家好我叫张三,我来自新疆
不定长参数
:也叫可变参数,用于不确定会传递多少参数的时候使用;
*args
是接收所有未命名的参数(关键字),返回的结果是元组类型;
**kwargs
是接收所有命名的实参(关键字),返回的结果是字典类型
例如:
def getInfo(name,address,*args,**kwargs):
print('大家好我叫%s,我来自%s'%(name,address))
print(args) #返回是元组类型
print(kwargs) #返回是字典类型
getInfo('张三','新疆','a','b','c',age = 18)
结果为:
大家好我叫张三,我来自新疆
('a','b','c')
{'age',18}
可变对象与不可变对象(传递的时候)
不可变类型
:如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在fun(a)内部修改a的值,只是修改另一个赋值的对象,不会影响a本身。
例如:
def sign(): #自定义函数
print('_'*30)
#值传递 不可变对象传递
def fun(args)
args = 'hello' #重新赋值
print(args) #输出hello
str = 'baby' #声明一个字符串变量,不可变数据类型
fun(str1) #将该字符串传递到函数中
sign()
print(str1) #还是baby,并没有被改变
结果为:
hello
------------------------------
baby
可变类型
:如列表、字典。如fun(la),则是将la真正的传递过去,修改后fun外部的la也会受到影响
例如:
def sign(): #自定义函数
print('_'*30)
#引用传递 可变对象传递
def fun(args):
args[0] = 'hello' #重新赋值
print(args) #输出hello
list1 = ['baby','come on'] #声明一个字符变量,可变数据类型
fun(list1) #将该字符传递到函数中
sign()
print(list1) #传递的对象本身,函数里面被修改了值,源对象也会修改
结果为:
['hello', 'come on']
------------------------------
['hello', 'come on']
函数的返回值
函数并非总是将结果直接输出,相反,函数的调用者需要函数提供一些通过函数处理过后的一个或者一组数据,只有调用者拥有了这个数据,才能够做一些其他的操作。那么这个时候,就需要函数返回给调用者数据,这个就被成为返回值,想要在函数中把结果返回给调用者,需要在函数中使用return
。
return
语句:用于退出函数,选择性的向调用者返回一个表达式。直接return的语句返回None。
def max(x,y):
if x > y:
return x #结束函数的运行,并且将结果返回给调用的地方
else:
return y
# print(y) #没有执行代码
#return后的代码不会执行
#调用函数 接收返回值
num = max(3,2) #声明一个变量num接收调用的函数后的返回值
print(num) #观察接收的返回值
结果为:
3
return返回多个值
def sum(x,y):
return x,y
num = sum(1,2) #用一个变量接收多个返回值时,会保存在一个元组中
print(num)
num1,num2 = sum(1,2)
print(num1)
print(num2)
结果为:
(1, 2)
1
2
yield 生成器
:把一个函数变成一个generator,使用生成器可以达到延迟操作的效果,所谓延迟操作就是指在需要的时候产生结果,而不是立即产生结果,节省资源消耗和声明一个序列不同的生成器,在不使用的时候几乎是不占内存。
例如:
def getNum(n):
i = 0
while i <= n:
yield i #将函数变成一个generator生成器对象
i += 1
# 调用函数
getNum(5)
a = getNum(5) #把生成器赋值给一个变量a
# 使用生成器,通过next()方法
print(next(a)) #输出yield返回的值,输出一次返回一个值
print(next(a))
结果为:
0
1
例如:
#for循环遍历一个生成器
a = (x for x in range(10000000)) #是一个生成器,不是元组推导式
print(a)
for i in a:
print(next(a))
send()
:把值传进当前的yield
例如:
def gen():
i = 0
while i <=5:
temp = yield i #不是一个赋值
#使用yield是一个生成器
print(temp) #因为yield之后返回结果到调用者的地方,暂停运行
i += 1
a = gen()
next(a)
print(a.send('我是a')) #可以将值发送到上一次yield的地方
结果为:
我是a
1
迭代器
迭代对象:
可以用for i in 遍历的对象可以叫做迭代对象:Iterable
如可迭代对象:list string dict
可以被next()函数调用的并不断返回下一个值的对象叫做迭代器:iterator
凡是可以用作与next()函数的对象都是iterator迭代器
例如:
list01 = [1,2,3,4,5] #是一个可迭代对象
#通过iter()将可迭代对象变成迭代器
a = iter(list01)
print(next(a))
print(next(a))
结果为:
1
2
变量的作用域
一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。
局部变量
:声明在函数内部的变量,局部变量的作用域只在于函数中,外部无法使用
例如:
def test01():
a = 10
print('-----修改前的a:%d'%(a))
print(id(a))
a = 20
print('-----修改后的a:%d'%(a))
print(id(a))
def test02():
a = 40
print('-----我是test02的a:%d'%(a))
print(id(a))
test01()
test02()
结果为:
-----修改前的a:10
140722366292672
-----修改后的a:20
140722366292992
-----我是test02的a:40
140722366293632
全局变量
:声明在函数外部的变量,大家共同使用;
a = 100
print('打印全局变量a:%d'%(a))
print(id(a))
def test1():
print('在test1函数内部使用全局变量a:%d'%(a))
print(id(a))
def test2():
print('在test2函数内部使用全局变量a:%d'%(a))
print(id(a))
#调用函数
test1()
test2()
结果为:
打印全局变量a:100
140722366295552
在test1函数内部使用全局变量a:100
140722366295552
在test2函数内部使用全局变量a:100
140722366295552
修改全局变量:global关键字
a = 100
print('打印全局变量a:%d'%(a))
print(id(a))
def test1():
global a
a = 200
print('在test1函数内部使用修改全局变量a:%d'%(a))
print(id(a))
def test2():
print('在test2函数内部使用全局变量a:%d'%(a))
print(id(a))
#调用函数
test1()
test2()
print('打印全局变量a:%d'%(a))
print(id(a))
结果为:
打印全局变量a:100
140722366295552
在test1函数内部使用修改全局变量a:200
140722366298752
在test2函数内部使用全局变量a:200
140722366298752
打印全局变量a:200
140722366298752
匿名函数
:定义函数的过程中,没有给定名称的函数,python中使用lambda表达式来创建匿名函数
lambda
创建匿名函数规则
lambda 参数列表:表达式
lambda只是一个表达式,函数体比def简单很多
lambda的主体是一个表达式,而不是一个代码块,所以不能写太多的逻辑进去
lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间的参数
lambda定义的函数的返回值就是表达式的返回值,不需要return语句块
lambda表达式的主要应用场景就是复制给变量、作为参数传入其他函数
例如:
1.没有参数的匿名函数
s = lambda : '哈哈哈'
print(s())
结果为:
哈哈哈
2.有参数的匿名函数
s = lambda x,y : x + y
print(s(3,3))
结果为:
6
3.矢量化的三元运算符
s = lambda x,y : x if x > 2 else y
print(s(3,5))
结果为:
3
需求:字典排序
dic = {'a':1,'c':2,'b':3}
dic = sorted(dic.items(),key=lambda x:x[1],reverse= True)
print({k:v for k,v in dic})
结果为:
{'b': 3, 'c': 2, 'a': 1}
需求:列表排序
list01 = [
{'name':'joe','age':18},
{'name':'susan','age':19},
{'name':'tom','age':17}
]
dic = sorted(list01,key = lambda x:x['age'],reverse= True) #reverse=True 是倒序,由大到小,reverse=False或者不填是正序,有小到大
print(dic)
结果为:
[{'name': 'susan', 'age': 19}, {'name': 'joe', 'age': 18}, {'name': 'tom', 'age': 17}]
递归函数
:递归就是子程序(或函数)直接调用自己或通过一系列调用语句简介调用自己,是一种描述问题和解决问题的基本方法。
例如:
def main(n):
print('进入第%d层梦境'%n)
if n == 3:
print('到达潜意识区,开始醒来')
else:
main(n+1)
print('从第%d层梦境醒来'%n)
main(1)
结果为:
进入第1层梦境
进入第2层梦境
进入第3层梦境
到达潜意识区,开始醒来
从第3层梦境醒来
从第2层梦境醒来
从第1层梦境醒来
计算阶乘
def jiecheng(n):
if n == 1:
return 1
else:
return n * jiecheng(n-1)
print(jiecheng(10))
结果为:
3628800
高阶函数
:将一个函数做为参数传递到另一个函数A中,那个这个函数A就是高阶函数
map接收一个函数及多个集合序列,会根据提供的函数对指定序列做映射,然后返回一个新的map
例如:
list01 = [1,3,5,7,9]
list02 = [2,4,6,8,10]
new_list = map(lambda x,y:x * y,list01,list02)
print(list(new_list)) #将map对象转换为list
结果为:
[2, 12, 30, 56, 90]
filter用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的filter对象
list02 = [2,4,6,8,10]
new_list = filter(lambda x:x > 4,list02)
print(list(new_list))
结果为:
[6, 8, 10]
reduce对于序列中的所有元素用func进行数据合并操作,可以给定一个初始值
from functools import reduce
list02 = [2,4,6,8,10]
new_list = reduce(lambda x,y:x+y,list02)
print(new_list)
结果为:
30