3.18
上节课回顾
-
利用f
.seek()
实现 tail-f -
操作系统的文件是共享的,所有的应用程序都可以同时进行操作
同时对两个文件进行操作,存在问题,暂时碰不到这种问题,将来会有解决办法
-
文件修改的两种方式
- 读进内存,修改完用内存覆盖
- 创建一个临时文件,每次修改得到新的结果,放进新的文件中,最后删除原文件,将新的文件重命名成原文件
硬盘上没有删除一说,只有用新的覆盖旧的。删除只是把旧的内容标记为 free 状态,覆盖完了才是真的删除了
-
函数,为什么要用,怎么用
def 函数名(参数名1,参数名2): '''文档注释''' 代码块 return 值
-
先定义后使用
- 定义:申请内存空间将函数体代码存放起来,然后将内存地址绑定给函数名,只检测语法,不执行代码
- 调用:通过函数名找到函数的内存,加阔号除法函数体代码的运行
-
定义函数三种形式:有参,无参,空
-
调用的三种方式:语句形式,表达式形式,参数传入
-
return返回值:没有返回值,返回一个值,返回多个值
-
return 是函数结束的标志,一个函数内可以有多个return,但只要执行一个,整个函数就立刻结束,并且会将该return后的值当作结果返回
正课
参数
如何用
按照定义阶段跟调用阶段分为两大类,形参,实参
形参
变量,指向一个值
在函数定义阶段定义的参数称之为形式参数,简称形参
def func(x,y)
print(x,y)
实参
值,实际的数
在调用阶段传入的值称之为实际参数,简称实参,相当于变量值
形参与实参的关系
- 在调用阶段,实参(变量值)会赋值给形参(变量名)
- 这种绑定关系只能在函数体内使用
- 形参与实参的绑定在调用时生效,函数结束后解除绑定关系
实参是传入的值,但值可以是以下形式
-
func(1,2)
-
a = 1 b = 2 func(a,b)
-
func(int('1'),2) func(func(1,2),func(2,3),33)
只要结果是一个值,放什么进参数都行
位置参数
按照从左到右的顺序依次定义的参数,称之为位置参数
真正与位置有关的步骤是传参
-
位置形参
在函数定义阶段,按照从左到右顺序直接定义的变量名。必须被传值,多一个不行,少一个也不行
func(x,y)
-
位置实参
在函数调用阶段,按照从左到右的顺序依次传入的值,按照顺序与形参一一对应
func(1,2)
关键字参数
关键字形参:在函数调用阶段,按照key = value 的形式传入的值
指名道姓给某个形参传值,可以完全不参照顺序
def fun(x,y)
pass
fun(y=1,x=2)
混合使用
-
位置实参必须放在关键字实参前,否则报错
func(1,y=2)
-
不能为同一个形参重复传值
func(1,x=1,x=3) func(1,2,x=2,y=3) # 此时报错 keyword argument repeated
默认参数 形参
在定义函数的阶段,就已经被赋值的形参,称之为默认参数
-
在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
def func(x, y=3): print(x, y) func(x=1) # 此时 x = 1,y = 3 func(x=1,y=5) # 此时 x = 1,y = 5 func(1,5) # 此时 x = 1,y = 5
-
对于每次调用,都必须被传入新的值,则用位置参数或关键字参数,若大部分的使用情况下,某个参数是固定的,则可以把固定的参数设为默认参数
-
实参给形参赋值不指定关键字,而是直接按照位置进行赋值,从左到右,哪个位置对应着默认形参,哪个实参就给默认形参赋值,不过因为默认形参都在位置参数的最右边,所有不会有赋值错位的情况
位置形参与默认形参混用
-
位置形参必须在默认形参的左边
-
默认参数的值只在定义阶段被赋值一次,准确的说被赋予的是值的内存地址
m = 2 def func(x,y=m): # m的内存地址传给y,指向2 print(x,y) m = 333 func(1) # 输出1,2
m = [11111,] def func(x,y=m): # y指向m的内存地址,指向列表 print(x,y) m.append(333) func(1) # 输出1,[11111,333]
-
虽然默认值可以被指定为任意数据类型,但是一般使用不可变类型:使用可变则失去了默认参数使用的意义
函数的定义应该遵循一个原则,是能够预知它拿到的结果,只跟函数本身有关,不受外界代码影响
def func(x,y,z,l=None): if l is None: l = [] l.append(x) l.append(y) l.append(z) print(l) # 对于需求默认参数为可变类型,可以先默认参数为none,在函数体里面判断,如果没传入值就为可变,如果传入了值就相当于改变了默认参数 # 所有的none都是同一个none,python中自带的类似小整数池的概念
可变长度
可变长度指的是在调用函数时,传入的值(实参)的个数不固定,而实参是用来为形参赋值的,所以对应着,针对溢出的实参,必须有对应的形参来接收
可变长度的位置参数
* args:用来接收溢出的位置实参,溢出的实参会被 ***** 保存成元组的格式赋值给其后的形参名 args
def func(x,y,*z):
print(x,y,z)
func(1,2,3,4,5,6)
# 1 2 (3,4,5,6)
例子:对多个实参进行求和
def my_sum(*args):
res = 0
for item in args:
res += item
return res
res = my_sum(1,2,3,6,88,88)
print(res)
args
arguments的缩写
* 后面可以跟任意名字,但是约定俗成用 args
跟 * 搭配使用,一看到就知道其来自于 * 给他赋值的值
可变长度的关键字参数
** kwargs:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典格式,然后赋值给 ** 后面的任意名字
其中任意名字约定俗成是 kwargs**kwargs
def register(name,age,**kwargs):
print(name,age,kwargs)
register(name = 'deimos',age = '12',sex ='male',cool = 'true')
星 * 用在实参中 打散
def func(x,y,z)
print(x,y,z)
func(*[11,22,33]) #实参中带星 * 先将 * 后的值打散,每一个元素作为位置参数传入
# 11,22,33
复杂情况 * / **
- 先将实参打散成元素,再去到形参中赋值,其中溢出的部分被存成元组args
- 被 * 打散的对象只能是可迭代对象
- *args 必须在 **kwargs 之前:位置形参在左,关键字形参在右
- 用于以后为函数新增参数,传参十分方便
def index(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs):
index(*args,**args)
wrapper(1,z=2,y=3)
将函数的参数传递给其中嵌套的函数,在定义原函数和嵌套函数的时候都使用*args和**kwargs,可以将参数的格式转换为嵌套函数的格式
总结需要记忆的点
形参
-
形参中的顺序,从左到右:位置形参,默认形参
-
默认形参只在函数被定义时赋值一次,即与某个值绑定关系一次,若使用变量给默认形参定义,则赋值的时候会把变量值的内存地址交给默认形参。
因此在函数定义之后再改这个变量,如果他是不可变的,那么函数里的默认形参是不变的,因为默认形参已经绑定了不可变的变量值。若默认形参被赋值的是可变类型,因为形参指向可变类型的内存地址,所以定义函数之后,改变这个可变类型,形参也改变了。不过一般不会用默认形参被可变类型赋值,没有意义
-
def func(x,y,*z): print(x,y,z) func(1,2,3,4,5,6) # 1 2 (3,4,5,6)
在形参中 (定义函数中) 使用
*args
,是用作 把调用时多输入的位置参数存成元组 -
def register(name,age,**kwargs): print(name,age,kwargs) register(name = 'deimos',age = '12',sex ='male',cool = 'true')
在形参中 (定义函数中) 使用
**kwargs
,是用作 把调用函数时多输入的 关键字参数 存成 字典 -
因为形参中位置形参,默认形参等有左右顺序,所以args ,kwargs也有顺序
def func(x,y,*args,**kwargs):
实参
-
实参中的顺序,从左到右:位置实参,默认实参,关键字实参
-
实参对默认形参赋值不需要用关键字 = ,直接放一个值在那就好,形参和实参中默认参数的值都是在位置参数右边,不会赋值错位的
-
def func(x,y,z) print(x,y,z) func(*[11,22,33]) #实参中带星 * 先将 * 后的值打散,每一个元素作为位置参数传入 # 11,22,33
在实参中使用
*args
可以将列表或着其他的可迭代对象的元素分割成位置实参 -
在实参中使用
**kwargs
将一个字典转换成关键字实参