Python之路(三)——函数
本节内容
- 函数基本语法及特性
- 参数
- 局部变量
- 返回值
- 嵌套函数
- 递归
- 匿名函数
- 高阶函数
- 高级函数
- 内置函数
一、函数基本语法和特性
定义
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性
- 减少重复代码
- 使程序变的可扩展,称作"解耦"
- 使程序变得易维护
基本语法
def cal(x,y):
'''
计算两个数的和
:param x: 第一个数,可以是整数或者浮点数
:param y: 第二个数,可以是整数或者浮点数
:return: x+y的值
'''
return x+y
print(cal(2,3)) # 5
二、参数

默认参数
def incre(x, step=1):
'''
返回一个数 + 10次step 的值
:param x: 一个数
:param step: 默认需要累加的基础值
:return:
'''
for i in range(10):
x += step
return x
print(incre(5)) # 15
print(incre(5,2)) # 25
非默认参数必须在默认参数之前,否: SyntaxError: non-default argument follows default argument
位置参数与关键字参数传递
users = []
def add_user(u_id,u_name,u_passwd='123'):
'''
新增用户,添加到users 列表中
:param u_id: 用户id
:param u_name: 用户名
:param u_passwd: 用户密码
:return: 多用户列表
'''
users.append({
"u_id": u_id,
"u_name": u_name,
"u_passwd": u_passwd,
})
return users
#调用程序代码
if __name__ == '__main__':
add_user(1,'alex1') # 按照位置传递参数 u_id = 1,u_name='alex1',默认参数u_passwd='123'
add_user(2,u_name='alex2',u_passwd='abc')# 按照位置和关键字参数类型混合传递
print(users)
# [{'u_id': 1, 'u_name': 'alex1', 'u_passwd': '123'}, {'u_id': 2, 'u_name': 'alex2', 'u_passwd': 'abc'}]
注意:
- 函数定义中'varname=var'形式为默认参数,区别于位置参数
- 位置参数必须在关键字参数之前
非固定参数传递
有时参数的数量,传递形式(位置,关键字)不可知。
非固定位置参数用*args表示,非固定关键字参数用**kwargs表示。其中:*,**强制要求,args,kwargs 是约定俗称的参数名
*:打包所有位置参数,组成一个元祖,赋值给args;**:打包所有关键字参数,组成一个字典,赋值给kwargs
def stu_register(id, *args, **kwargs):
'''
注册一个学生,打印学生信息
:param id: 学生id
:param args: 学生其他信息,采用元祖形式保存
:param kwargs: 学生其他信息,采用字典形式保存
:return:
'''
# print(id, *arg, **kwargs)
print(id, args, kwargs)#Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}
stu_register("Alex", '男', 22, province="ShanDong", major="计算机")
#传参步骤
# 1.位置参数匹配 id = "Alex"
# 2.'男', 22没有固定位置参数匹配,打包成一个元组统一传输给可变位置参数args,至此所有位置参数匹配完毕
# 3.province="ShanDong"关键字参数传递,无:打包成字典,统一传递给可变关键字参数kwargs
解包与不解包
非固定长度参数传递中,存在传递的参数本身为元祖或者字典的情况。
解包:对传递的元祖或者字典处理,分割成单个参数进行传递
非解包:不对传递的元祖或者字典处理,作为一个整体进行传递
def stu_register(id, *args, **kwargs):
'''
注册一个学生,打印学生信息
:param id: 学生id
:param args: 学生其他信息,采用元祖形式保存
:param kwargs: 学生其他信息,采用字典形式保存
:return:
'''
# print(id, *arg, **kwargs)
print(id, args, kwargs)
stu_register("Alex", '男', 22, province="ShanDong", major="计算机")
#Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}
#传参步骤
# 1.位置参数匹配 id = "Alex"
# 2.'男', 22没有固定位置参数匹配,打包成一个元组统一传输给可变位置参数args,至此所有位置参数匹配完毕
# 3.province="ShanDong"关键字参数传递,无:打包成字典,统一传递给可变关键字参数kwargs
#如果,参数本身已经是元祖或者字典形式, 如果需要传递前解包,元祖解包 * ,字典解包 **
tuple_stu_info = ('男', 22, ) #一般都会在最后一个元祖加',' 区分函数调用
dic_stu_info = {'province': "ShanDong", 'major':"计算机"}
stu_register("Alex", *tuple_stu_info, **dic_stu_info)
#同上:Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}
#元组不解包,字典解包
stu_register("Alex", tuple_stu_info, **dic_stu_info)
# Alex (('男', 22),) {'province': 'ShanDong', 'major': '计算机'}
#字典不解包,元组解包
stu_register("Alex", *tuple_stu_info, dic_stu_info)
# Alex ('男', 22, {'province': 'ShanDong', 'major': '计算机'}) {}
#都不解包
stu_register("Alex", tuple_stu_info, dic_stu_info)
# Alex (('男', 22), {'province': 'ShanDong', 'major': '计算机'}) {}
三、局部变量
定义在函数内部的变量称 局部变量,变量定义时没有格式缩进的变量称 全局变量。其中:参数是函数的局部变量
变量作用域
变量可以被使用的范围,即变量的有效范围
- L(Local) 局部作用域
- E(Enclosing) 嵌套函数外的函数中
- G(Global)全局作用域
- B(Built-in)内建作用域
查找顺序: 按照 L –> E –> G –>B依次寻找
name = "刚娘"
def weihou():
name = "沉着"
weihou_name ="燥起来"
print(name,weihou_name)
def weiweihou():
global name #只改全局,不改局部
name = "冷静"
nonlocal weihou_name
weihou_name = "李云龙"
# nolocal name #报错: global ,nolocal 起指示作用,变量名还是唯一的
weiweihou()
print(name,weihou_name)
print(name)
weihou()
print(name)
#
# 刚娘
# 沉着 燥起来
# 沉着 李云龙
# 冷静
四、返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
五、嵌套函数
函数定义中有另外一个函数的定义
六、递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身,这个函数就是递归函数。
# 汉诺塔的移动可以用递归函数非常简单地实现。
#
# 请编写move(n, a, b, c)函数,它接收参数n,表示3个柱子A、B、C中第1个柱子A的盘子数量,然后打印出把所有盘子从A借助B移动到C的方法,例如:
def move(n, a, b, c):
if n == 1:
print(a,'--->',c)
return
move(n-1,a,c,b)
move(1,a,b,c)
move(n-1,b,a,c)
# 期待输出:
# A --> C
# A --> B
# C --> B
# A --> C
# B --> A
# B --> C
# A --> C
move(3, 'A', 'B', 'C')
尾递归
递归函数逻辑表达清晰,但太耗内存(不断保存上一次栈的状态)。变相提出了尾递归,即在返回的时候计算出下次函数被调用的值替代表达式。
#递归
def jiecheng(n):
if n == 1:
return 1
else:
return n * jiecheng(n-1) #返回值有同名函数表达式
#尾递归
def jiecheng2(n,product=1):
if n == 1:
return product
else:
return jiecheng2(n-1,n*product) #无函数表达式,理论上可以单独调用。但python没有优化
print(jiecheng2(10000)) # RecursionError: maximum recursion depth exceeded in comparison
七、匿名函数
匿名函数就是不需要显式定义的函数,用于临时使用的简易逻辑函数
#求一个数的平方 cal = lambda x:x**2 print(cal(5)) # 25
八、高阶函数
函数的参数or返回值是一个函数,这种函数就称之为高阶函数。常用于装饰器
#高阶函数
def cal(f, x, y):
return f(x, y)
def add(x, y):
return x + y
def div(x, y):
return divmod(x, y)
print(cal(add, 2, 3)) # 5
print(cal(div, 5, 3)) # (1, 2)
九、高级函数
函数递归、高阶函数、高级函数是函数式编程的主要特色,原则:不要重复造轮子。 本小节主要介绍 filter、map、functools.reduce以及for 推导式
1.找到长度不唯一的单词,并首字母大写,用,连接成字符串输出
employees = ['neal','s','stu','j','rich','bob','aiden','j','ethan','liam']
l = ','.join(map(lambda i:i.capitalize(),filter(lambda i:len(i)>1,employees)))
print(l) # Neal,Stu,Rich,Bob,Aiden,Ethan,Liam
#1.2
print(','.join(i.capitalize() for i in employees if len(i)>1)) #更加方便
#2. [‘adam’, ‘LISA’, ‘barT’]转换首字母大写,其他小写
l = ['adam', 'LISA', 'barT']
l = list(map(lambda i:i.capitalize(),l))
print(l)
#2.1
print([i.capitalize() for i in l])
#3.[1,3,5,6,7,10,2,5] 求乘积
l = [1,3,5,6,7,10,2,5]
import functools
print(functools.reduce(lambda x,y:x*y,l))
#4.求5000..10000 之间的回数
print([i for i in range(5000,10000) if str(i)== str(i)[::-1]])
#5. 1. 100 整除2 不能整除4的数,做平方
print(list(map(lambda i:i**2,filter(lambda x:x%2==0 and x%4 !=0,[i for i in range(100)]))))
#5.2 for 列表形式。简单元素处理可以取代 map ,filter(if)
print([i**2 for i in range(100)if i%2==0 and i%4!=0])
#取最长单词
s = ('dfsa','dsafdsaffdf','sad','adfdsaf')
functools.reduce(lambda a,b:a if len(a)>len(b) else b,s)
十、内置函数
Python解释器的内置函数(无论什么地方,什么时间都可以使用)

浙公网安备 33010602011771号