函数
函数的语法结构
""" def 函数名(参数1,参数2) '''函数注释'' 函数代码体 return 返回值 """
1、def(必须的)
是定义函数的关键字
2、函数名(必须的)
是函数的名字,相当于变量名;函数的命名规范与风格遵循变量名
3、()括号
括号定义参数
4、参数1,参数2(可选的)
参数可以没有也可以有多个;表示在使用函数之前需要满足的一些条件
5、:冒号
括号后要加冒号,然后在下一行开始进行编写函数体的代码
6、函数注释(可选的)
类似于产品说明书;主要用于介绍函数功能、参数使用以及其他情况
7、函数代码体(必须的)
函数核心的代码逻辑
8、return返回值(可选)
使用函数之后返回给使用者的结果,可以有也可以没有
函数的定义与调用
一、需注意的点
1、函数必须先定义后调用(顺序不能乱)
2、函数在定义阶段只检测语法不执行代码
3、函数在调用阶段才会执行函数体代码
如何调用函数:函数名加括号,如果函数在定义阶段有参数,则在调用阶段也需要加上参数
二、函数在定义与调用阶段底层原理
1、在内存空间中申请一块空间储存函数代码体
2、将函数代码体所在的内存空间地址绑定给函数名
3、函数名加括号就可以调用函数代码体
函数的分类
1、内置函数
python解释器自带的函数,已经提前定义好的,直接就可以
2、自定义函数(程序员自己写的函数)
2.1、无参数函数
2.2、有参数函数
2.3、空函数
# 无参函数:在函数定义阶段括号内没有加参数 def my_func(): print('无参函数') # 有参函数:在函数定义阶段括号内加了参数 def my_func(a, b): print('有参函数') # 空函数,空函数本身没有含义,主要作用是可以提前规定好编写代码的思路 def my_func(): pass
空函数的实际应用案例
def register(): pass def login(): pass func_dic = {'1': register, '2': login} while True: print(""" 1.注册 2.登录 """) choice = input('please>>>:').strip() if choice in func_dic: func_name = func_dic.get(choice) func_name() else: print('功能编号不存在')
函数的返回值
# 如何获取函数的返回值 # res = len([1, 2, 3, 4, 5]) def my_func(): print('123') print('木头人') print('123') # return 123, 456, 789 return 123, 456, 789 # res = my_func() # 将函数my_func执行之后的反馈结果赋值给变量res # 1.函数体代码没有return关键字的时候 默认返回None # print(res) # None # 2.函数体代码如果只有一个return那么也返回None # print(res) # None # 3.函数体代码遇到return会立刻结束函数的运行 # 4.函数体代码有return 返回值就是return后面跟的数据(单个数据) # print(res) # 123 # 5.函数体代码有return 并且后面跟了多个数据 那么会自动组织成元组的形式返回 # print(res) # (123, 456, 789) """ 函数的返回值如果是容器类型 那么直接支持解压赋值 """
函数参数
一、函数参数的两大分类
1、形式参数:在函数定义阶段括号内所填的参数。简称“形参”
def func(a, b): pass # a和b就是函数func的形参
2、实际参数:在函数调用阶段括号内传入的参数。简称“实参”
def func(a, b): print(a, b) def func1(): return 111 def func2(): return 222 # 1.直接传入值 # func(1, 2) # 2.借助于变量名间接传入 # m = 111 # n = 222 # func(m, n) # 3.其他方法或者函数的返回值 # func(int('123'), int('111')) func(func1(), func2())
3、形参和实参的关系
1、我们可以将形参看成是变量名,实参看成是变量值
2、两者在函数调用阶段临时绑定,函数运行结束断开
3、形参是表现形式只有一种就是变量名;实参的表现形式有很多种(但是把握核心,就是数据值)
二、位置参数
1、位置参数:按照从左往右的顺序依次填入的参数
2、位置参数分类
2.1、位置形参:在函数定义阶段括号内按照从左往右的顺序依次填入的变量名
2.2、位置实参:在函数调用阶段括号内按照从左往右的顺序依次填入的数据值
3、关键字实参(可以打破位置顺序):在函数调用阶段通过形参名=数据值的形式指名道姓的传值
4、 特点:
4.1、位置形参与位置实参在函数调用阶段,按照位置一一对应绑定
4.2、位置参数在绑定的时候多一个不行少一个也不行
小技巧:格式越简单的越靠前,格式越复杂的越靠后
def my_max(a, b): # a,b 位置形参 print(a, b) if a > b: return a else: return b # res = my_max(111, 222) # 111,222 位置实参 # res = my_max(111) # 111,222 位置实参 # res = my_max(111,222,333) # 111,222 位置实参 # print(res)、 # res = my_max(b=123,a=222) # 指名道姓的传 # res = my_max(111,b=222) # 可以 # res = my_max(111,a=222) # 不可以 111会按照位置传给形参a 222会按照关键字参数也传给形参a 这种情况不允许出现 # res = my_max(b=222,111) # 不可以 位置参数必须要在关键字参数的前面 # res = my_max(a=222,111) # 不可以 位置参数必须要在关键字参数的前面
三、默认参数
1、默认参数就是默认形参
2、默认形参:函数在定义阶段就可以给形参赋值了
3、默认形参的特征:
1、该形参在函数调用阶段如果不给值,则使用默认的
2、该形参在函数调用阶段也可以继续给值,则使用你给的
4、位置形参与默认值形参在定义的时候,位置形参在默认值形参的前面
小技巧:格式越简单的越靠前,格式越复杂的越靠后
默认参数实际案例
def register(name, age, gender='male'): print('%s:%s:%s' % (name, age, gender)) register('jason', 18) register('tony', 28) register('kevin', 38) register('lili', 18, 'female') register('lili', 18, gender='female')
注意案例
# 1、默认形参如果绑定的是一个列表 那么指向的是固定的一个地址 def func(name, age, hobby=[]): hobby.append(age) print('%s:%s:%s' % (name, age, hobby)) func('jason', 18) # jason:18:[18] func('kevin', 28) # kevin:28:[18, 28] func('tony', 38) # tony:38:[18, 28, 38] func('jason', 18, []) # jason:18:[18] func('kevin', 28, []) # kevin:28:[28] func('tony', 38, []) # tony:38:[38] # 2、 m = 200 def func(a, b, c=m): print(a, b, c) m = 400 func(1, 2) # 200
四、可变长参数
1、函数无论传入多少位置参数都可以正常运行
def func(x, y, *a): print(x, y, a) func() # () func(1) # (1,) func(1, 2, 3, 4, 5, 6, 7) # (1, 2, 3, 4, 5, 6, 7) func(1, 2) # 1 2 () func(1, 2, 3, 4, 5, 6, 7, 8, 9) # 1 2 (3, 4, 5, 6, 7, 8, 9) func(1, 2) # 1 2 (3, 4, 5, 6, 7, 8, 9) """ *号在形参中的使用 用于接收多余的位置参数 并组织成元组的形式赋值给*号后面的变量名 """
2、函数无论传入多少关键字参数都可以正常运行
def index(x, y, **b): print(x, y, b) index() # {} index(a=1, b=2, c=3, d=4) # {'a': 1, 'b': 2, 'c': 3, 'd': 4} index(y=2, x=1) # 1 2 {} index(y=2, x=1, u=222, k=111, l=444) # 1 2 {'u': 222, 'k': 111, 'l': 444} """ **号在形参中的使用 用于接收多余的关键字参数 并组织成字典的形式赋值给**号后面的变量名 """
3、定义一个函数无论传入多少位置参数和关键字都可以正常运行
def index(*a,**b): print(a,b) index() # () {} index(1,2,3,4) # (1, 2, 3, 4) {} index(a=1,b=2,c=3) # () {'a': 1, 'b': 2, 'c': 3} index(1,2,3,4,a=1,b=2,c=3) # (1, 2, 3, 4) {'a': 1, 'b': 2, 'c': 3} """ 墨守成规 可变长形参 *与**后面的变量名其实是可以随便定义的 但是python中推荐使用 *args **kwargs def index(*args, **kwargs): pass """
4、*和**的实际应用
def index(a, b, c): print(a,b,c) new_list = [11,22,33] index(new_list) # 肯定不行 列表是一个整体 相当于一个实参 index(new_list[0],new_list[1],new_list[2]) # 可以 '''如果index形参是*args 列表里面有很多元素 如何实现按照位置一一传入''' def index1(*args): print(args) new_list1 = [11,22,33,44,55,66,77,88,99] index1(*new_list1) # index1(11,22,33,44,55,66,77,88,99) """ *号在实参中的使用 会将列表、元组内的元素打散成位置参数的形式一一传值 """ def index2(**kwargs): print(kwargs) new_dict = {'username': 'jason', 'pwd': 123} index2(**new_dict) # index2(username='jason',pwd=123) {'username': 'jason', 'pwd': 123} """ **号在实参中的使用 会将字典内的键值对打散成关键字参数传入 """
五、函数参数补充了解
def register(name, age, *, sex, height): pass register('jason',18,'male',183) register('lili',18,sex='male',height='1.8m') #正确使用 """ sex height在传入实参的时候必须以关键字参数的形式 ps:该类型的参数几乎不用 也几乎很少能碰到 """
函数对象(函数名)
"""函数名遇到括号就会调用!!!""" # 用法1:函数名可以当做变量名赋值 def index(): print('from index') a = index a() # 本质就是在调用index函数 # 用法2:函数名还可以当做函数的实参 def index(): print('from index') def func(a): print(a) a() print('from func') func(index) # 用法3:函数名还可以当做函数返回值 def index(): print('from index') def func(): print('from func') return index res = func() # 调用func并接受func的返回值 res() # 用法4:函数名可以当做容器类型(内部可以存放多个数据)的元素 def index(): print('from index') l = [111, 222, 333, index()] print(l)
案例演示
def register(): print('注册功能') def login(): print('登录功能') def shopping(): print('购物功能') def transfer(): print('转账功能') def withdraw(): print('提现功能') def check_order(): print('查看订单') func_dic = {'1':register, '2':login, '3':shopping, '4':transfer, '5':withdraw, '6':check_order } while True: print(""" 1.注册功能 2.登录功能 3.购物功能 4.转账功能 5.提现功能 6.查看订单 """) choice = input('请输入功能编号>>>:').strip() # 判断用户输入的编号在不在字典的k中 if choice in func_dic: # 根据键获取值(函数名) func_name = func_dic.get(choice) # 函数名加括号调用 func_name() else: print('功能编号不存在')
函数的嵌套调用
# 嵌套调用:函数内部调用其他函数 def index(): print('from index') def func(): index() print('from func') func() def my_max(a, b): if a > b: return a return b def many_max(x,y,z,m): res = my_max(x,y) res1 = my_max(res,z) res2 = my_max(res1,m) return res2 ret = many_max(1,2,3,4) print(ret)
函数的嵌套定义
函数体内部定义其他函数;将复杂的功能全部隐藏起来,只暴露一个简单的接口
def index(): name = 'tony' def func(): print('from func') index()
案例演示
def all_func(type): def register(): print('注册功能') def login(): print('登录功能') def transfer(): print('转账功能') def shopping(): print('购物功能') # 这里仅仅是延时嵌套定义的现象 暂不考虑优化 if type == '1': register() elif type == '2': login() elif type == '3': transfer() elif type == '4': shopping() else: print('不知道啥功能') all_func('3')
闭包函数
闭:定义在函数内部的函数
包:内部函数使用了外部函数名称空间中的名字
def outer(): x = 222 def index(): print('from index', x) return index
闭包函数其实是给函数传参的第二种方式
# 方式1:函数体代码需要用到数据 直接在括号内定义形参即可 def index(username): print(username) def my_max(a, b): if a > b: return a return b # 方式2:利用闭包函数 def outer(x,y): # x = 2 # y = 40 def my_max(): if x > y: return x return y return my_max res = outer(2,40) print(res()) print(res())
递归函数
1、定义
递归:函数在运行过程中,直接或者间接的调用了自身
2、小知识
官网表示:python默认的最大递归深度为1000次
3、递归分为递推和回溯
递推:一层层往下推导答案(每次递归之后复制度相较于上一次一定要有所下降)
回溯:依据最后的结论往后推导出最初需要的答案
注意:递归一定要有结束条件
4、演示
def func(): print('from func') index() def index(): print('from index') func() index()
5、案例演示
某公司四个员工坐在一起,问第四个人薪水,他说比第三个人多1000,问第三个人薪水,第他说比第二个人多1000,问第二个人薪水,他说比第一个人多1000,最后第一人说自己每月5000,请问第四个人的薪水是多少?
思路解析:
要知道第四个人的月薪,就必须知道第三个人的,第三个人的又取决于第二个人的,第二个人的又取决于第一个人的,而且每一个员工都比前一个多一千,数学表达式即:
salary(4)=salary(3)+1000 salary(3)=salary(2)+1000 salary(2)=salary(1)+1000 salary(1)=5000 总结为: salary(n)=salary(n-1)+1000 (n>1) salary(1)=5000 (n=1)
很明显这是一个递归的过程,可以将该过程分为两个阶段:回溯和递推。
在回溯阶段,要求第n个员工的薪水,需要回溯得到(n-1)个员工的薪水,以此类推,直到得到第一个员工的薪水,此时,salary(1)已知,因而不必再向前回溯了。然后进入递推阶段:从第一个员工的薪水可以推算出第二个员工的薪水(6000),从第二个员工的薪水可以推算出第三个员工的薪水(7000),以此类推,一直推算出第第四个员工的薪水(8000)为止,递归结束。需要注意的一点是,递归一定要有一个结束条件,这里n=1就是结束条件。
代码
def salary(n): if n==1: return 5000 return salary(n-1)+1000 s=salary(4) print(s) # 结果为8000
练习题
l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,]]]]]]]]]]]]]] # 打印出列表中每一个元素(列表除外) # 1.循环该列表 获取列表内每一个元素 # 2.判断该元素是否是数字 如果是数字 则直接打印 # 3.如果是列表 则循环该列表 获取列表内每一个元素 # 4.判断该元素是否是数字 如果是数字 则直接打印 # 5.如果是列表 则循环该列表 获取列表内每一个元素 # 6.判断该元素是否是数字 如果是数字 则直接打印 # 7.如果是列表 则循环该列表 获取列表内每一个元素 def get_num(l): for i in l: if type(i) is int: print(i) else: # 也是for循环 然后判断 get_num(i) get_num(l)
匿名函数
1、定义
没有名字的函数
2、格式
lambda 形参 :返回值
匿名函数一般不会单独使用,都是配合其他函数一起使用
3、案例
计算二次方
l = [1, 2, 3, 4, 5, 6, 7, 8, 9] def index(n): return n ** 2 print(list(map(lambda x:x**2, l)))
# 其中map()为映射