3-01 函数的定义和调用
函数的定义需要关键词 def
函数可以有返回值,也可以无返回值,是否有返回值根据函数中是否有关键词 return 决定
给出两个函数样例
输入一个数,扩大11倍
def cal(s):
s*=11
return s
a=eval(input())
b=cal(a)
print(b)
#定义了有返回值的函数
def cal(s):
s*=11
print(s)
a=eval(input())
cal(a)
#定义了无返回值的函数
3-02 实参和形参
当实参传递给形参后,如果在函数中修改形参,则不会影响到实参的值
当实参是列表等对象时,在函数中修改其中的元素,则会影响到列表其中的元素的值
3-03 默认参数和关键字参数
默认参数
默认实参与C语言相同,可以给参数一个默认值,如果不给形参传递实参,那么形参就会调用默认值
位置参数和关键字参数
位置参数指的是调用函数时按照参数位置对应关系传入参数,而关键字参数指的是传入参数时按照**“实参=形参“**这种形式传入参数
def cal(str1,str2):
print(str1,str2)
str11=input()
str22=input()
cal(str11,str22)
#用位置参数传入
def cal(str1,str2):
print(str1,str2)
str11=input()
str22=input()
cal(str2=str11,str1=str22)
#用关键字参数传入
位置参数和关键字参数可以混合使用但是位置参数必须写在关键字参数前面
3-04函数的不定长参数
定义方式
位置参数:
def 函数名([普通形参列表] *不定长参数名)
不定长的参数被封装成元组
def p(str1,*str):
print(str1,str)
p('lihua','liming','lilei','lishuai')
输出:lihua ('liming', 'lilei', 'lishuai')
关键字参数
def 函数名([普通形参列表] **不定长参数名)
关键字参数会被封装成字典
注意关键字参数的传入形式一定是 变量 = 常量 的形式
第一个位置不能放常量
def p(str1,**str):
print(str1,str)
p('lihua',name1='liming',name2='lilei',name3='lishuai')
输出:lihua {'name1': 'liming', 'name2': 'lilei', 'name3': 'lishuai'}
关键字参数的不定长参数定义只是比位置参数的多一个星号
注意区分两种使用方法,位置参数不能传关键字参数,关键字参数不能传位置参数
3-05 拆分参数列表
如果一个函数所需要的参数已经存储在了字典,列表,元组中,可以直接利用拆分参数列表的方法,把数据结构里的元素拆分出来作为函数的参数,列表和元组的元素作为位置参数,字典的元素作为关键字参数
实现方法:
def sumval(*l):
sum1=0
for i in l:
sum1+=i
print(sum1)
l1 = [1,2,3]
sumval(*l1) #传入时代上一个星号*
作为拆分后作为关键字参数使用同理,传入时带上两个星号即可
3-06 返回值
函数可以给出一个返回值,用于主函数的使用或者数值计算,与C/C++语言返回类型相同,不写返回值默认返回空;
3-07 模块与 import 语句
当一个程序较大时,可以分解成一个个带有不同功能的模块
import 是模块调用关键词,可以通过模块调用来使用其他模块里的功能
temp.py #实现求前 n 个数 的和
def sumval(n):
sum1=0
for i in range(n+1):
sum1+=i
return sum1
temp1.py
import temp
n = temp.sumval(10)
print(n)
值得注意的是 调用 temp 会执行 temp 里的所有语句
3-08 全局变量 _name_
为解决上边留下的那个问题,要引入全局变量 _name_
全局变量 _name_ 的作用是 获取当前模块的名称 ,如果 模块单独执行 , _name_ 的输出值 就是 _main_ ,如果模块被调用执行 , 那么 _name_ 的返回值就是被调用的模块名 , 我们可以根据这一特征来把调用时实现的功能与模块单独使用时的功能区分开
3-09 from ---- import
from import 可以简化 import 的使用 , 不再需要制定模块名,直接导入标识符
指定导入的标识符
temp.py #实现求前 n 个数 的和
def sumval(n):
sum1=0
for i in range(n+1):
sum1+=i
return sum1
temp1.py
from temp import sumval
n = sumval(10) #使用时更加方便
print(n)
2022.7.23 更新
引用的时候不要加后缀名,直接引用文件名即可,
一定要在相同路径下才可以引用!!!!!!
from ---- import *
当模块中的标识符较多时,可以使用 from ---- import * 一次导入所有的标识符
如果不想一次导入所有的标识符还想用这个语句 , 可以在模块开始列出一个 * 所对应的
_all_ 列表 , 表示 引用 星号时 可以引用到那些标识符
as 语句
当我们的模块名或者标识符比较复杂时,可以考虑用 as 给标识符或者模块改名
3-10 包
包类似于文件夹,可以把多个模块组合在一起,一方面方便管理,另一方面可以有效避免模块名冲突
当一个模块在一个包中,要想引用某个标识符,就要详细的表示出 这个模块 或 标识符在包中详细的位置
3-11 猴子补丁
猴子补丁用于不改变原有代码的情况下,改变其功能或增添新功能;
def sumval(n):
sum1=0
for i in range(n):
sum1+=i
return sum1
def sumval1(*l):
sum1=0
for i in l:
sum1+=i
return sum1
sumval = sumval1 #用新函数代替掉旧的函数
l=[1,2,3]
print(sumval1(*l))
3-12,3-13 局部变量和全局变量,global 关键字
局部变量的作用范围只是定义的部分
全局变量的作用范围是全局
当在函数中想要修改全局变量的值是 要使用 global 关键字指定变量为全局变量,否则只对局部生效
3-14 nonlocal 关键字
在函数嵌套中,内层变量与外层变量都是局部变量,当内层要使用外层变量时,global 关键字就无法解决,要使用 nonlocal 关键字;
3-15 递归函数
如果一个问题子问题与原问题解法相同,就采用递归函数
注意递归函数的层数,层数太多会引起堆栈溢出
3-15 高阶函数和lambda函数
高阶函数
把函数作为另一个函数的参数的使用方法
def ff(f,a,b):
return f(a)+f(b)
def g(a):
return a**3
def h(a):
return a**2
print(ff(g,2,3))
print(ff(h,2,3))
lambda函数
lambda函数是不用 def 定义的一种函数,可以实现简短的一些函数运算
lambda 参数列表 : 运算
可以赋给一个变量
f=lambda x:x**2
print(f(2))
也可以当参数传给一个形参
def ff(f,a,b):
return f(a)+f(b)
print(ff(lambda x:x**2,2,3))
3-16 闭包
如果内层函数使用了外层函数定义的局部变量,并且外层函数的返回值是内层函数的引用,就构成了一个闭包
闭包的主要作用是可以封存函数执行的上下文环境
def outer(x):
y=10
def inner(z):
nonlocal x,y
return x+y+z
return inner
f=outer(3)# x=3 y=10 z=?
g=outer(10)# x=10 y=10 z=?
# f 和 g 形成了两个不同的环境
print(f(3))
print(g(10))
3.17 装饰器
在闭包的基础上可以对其他函数进行装饰
2022.7.23 补充
- python 无法实现引用传递在函数中修改实参(数字,字符串,元组)的值,数字,字符串还有元组都是不可变对象,而列表和字典的内容可以修改(数字,字符串,元组是值传递,列表,字典是引用传递)
- 简单的装饰器实例
装饰器可以在不修改函数代码和客户端代码的前提下对函数增加功能,是函数的功能更加丰富
'''
如下函数可实现对超市用户两笔交易求和的功能,并用交易额分别为-10和20的数据进行测试
'''
def f1(a, b):
return a+b
#客户端函数调用代码
print(f1(-10, 20))
'''
上述函数虽然可对超市用户两笔交易求和的功能,但你存在如下问题需解决:
1.没有对单笔交易额数据进行检测,如交易额小于0时需提示用户错误并停止计算
2.超市规定如果两笔交易的总额低于100元,则在计算结果的同时要提示用户交易额不满足打折活动要求
要求不能修改f1函数且不增加客户端代码,并用交易额分别为-10和20的数据进行测试
'''
加入功能 1
'''
f1函数虽然可对超市用户两笔交易求和的功能,但你存在如下问题需解决:
1.没有对单笔交易额数据进行检测,如交易额小于0时需提示用户错误并停止计算
并用交易额分别为-10和20的数据进行测试
'''
def deco1(func):
def inner(*p):
for i in p:
if i <0:
print('数据额度错误,不能小于0!')
return
ret = func(*p)
return ret
return inner
@deco1
def f1(a, b):
return a+b
#客户端函数调用代码
print(f1(-10, 20))
同时加入两个功能
'''
上述函数虽然可对超市用户两笔交易求和的功能,但你存在如下问题需解决:
1.没有对单笔交易额数据进行检测,如交易额小于0时需提示用户错误并停止计算
2.超市规定如果两笔交易的总额低于100元,则在计算结果的同时要提示用户交易额不满足打折活动要求
并用交易额分别为-10和20的数据进行测试,不增加客户端代码
'''
def deco1(func):
def inner(*p):
for i in p:
if i <0:
print('数据额度错误,不能小于0!')
ret = func(*p)
return ret
return inner
def deco2(func):
def inner(*p):
ret = func(*p)
if ret < 100:
print('交易总额度低于参加折扣的额度要求!')
return ret
return inner
@deco1
@deco2
def f1(a, b):
return a+b
#客户端函数调用代码
print(f1(-10, 20))