day10:函数基础知识
今日内容:
一、定义函数:
定义函数时发生的事情
调用函数时发生的事情
二、定义函数的三种方式和使用场景
三、调用函数的三种方式
四、函数参数
形参
实参
可变长系列 * **在形参和实参中的应用
五、函数的返回值
引入:函数就是装代码的容器
在程序中,具备某一功能的‘工具’指的就是函数,‘事先准备工具’的过程即函数的定义,‘拿来就用’即函数的调用。
什么是函数?
函数:具备某一功能的工具
事先准备工具的过程----》函数的定义
遇到场景拿来就用-------》函数的调用
原则:先定义,后调用
为何要用函数?
1、程序的组织结构不清晰,可读性差
2、代码冗余
3、可维护性,扩展性差
如何用函数?
先定义:定义的语法:3种定义方式
后调用:调用的语法:3种调用方式
返回值:3种返回值的形式
一、定义函数:相当于造了个工厂,函数名就是地址,参数是原材料,函数体是生产流水线,值是生产出的产品
1、语法:
def 函数名(参数1,参数2,...):
''''''文件描述''''''
函数体(代码1,代码2,代码3......)
return 值
- def: 定义函数的关键字;
- 函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;和变量名要求一样,最好定义为动词
- 括号:括号内定义参数,非必要,且无需指定参数的类型;
- 冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
- """文档描述""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
- 函数体:由语句和表达式组成;
- return 值:定义函数的返回值,非必要
追加:
变量名对应的和函数名一样,都是内存地址与名的绑定关系,打印时按原理都会显示内存地址
但是,python只会在运行变量名时会把变量的值给显示出来
例:
def login():
print(111)
print(222)
x = 10
print(x) --------》值 10
print(login)------》名login的内存地址<function login at 0x000002ABA4B37280>
定义函数时,发生的事情:
1、申请内存空间保存函数体代码
2、将上述内存地址绑定给函数名
3、定义函数时不执行函数体代码,只会检查函数体语法
调用函数时,发生的事情:
print(func)-------》函数的内存地址
1、通过函数名找到函数的内存地址
2、加()触发函数体代码的运行(python的语法)
重点!强调!查找名字的顺序/优先级:是以定义阶段为准,与调用位置无关
例:
def func():
print(111)
x
print(222)
=================定义阶段语法没有问题======================
func()----------》NameError: name 'x' is not defined
=============但是在调用阶段,逻辑问题产生报错================
同上:
x = 111
def func():
print(x)
x = 222
=================定义阶段语法没有问题======================
func()--------》UnboundLocalError: local variable 'x' referenced before assignment
=============但是在调用阶段,逻辑问题产生报错================
二、定义函数的3种定义方式和使用场景
方式一:无参函数,函数体不需要外部传进参数
def func():
print('头头大')
func()
def interactive():
name = input('username>>>>>:').strip()
age = input('userage>>>>>:').strip()
msg = '名字:{} 年龄:{}'.format(name, age)
print(msg)
interactive()
方式二:有参函数,函数体需要外部传进参数
def add(x,y):
res = x + y
print(res)
add(10,20)
add(1,2)
def add(x, y): -----------》参数----》原材料
res = x + y
return res ------------》返回值--》产品
res = add(20, 30)
print(res)
方式三:空函数,函数体代码为pass/...把所有功能都列举出来用pass充当函数体“占位符”
使用场景:
例如要编写一个ftp程序,我们可能想到的功能有用户认证,下载,上传,浏览,切换目录等功 能,可以先做出如下定义:
def auth_user():
"""user authentication function"""
pass
def download_file():
"""download file function"""
pass
def upload_file():
"""upload file function"""
pass
def ls():
"""list contents function"""
def cd():
"""change directory"""
pass
三、调用函数的3种方式
1、语句的形式:只加()调用函数,不做任何操作
len('hello')
2、表达式形式:
def add(x, y):
res = x + y
return res
赋值表达式:
res = add(1,2)
print(res)
数学表达式:
res = add(1,2)*10
print(res)
3、函数调用可以当做参数传给另一个函数
res = add(add(1,2),10)
print(res)
---------》就相当于把add的调用当做参数给了print
四、函数参数
总体分:
1、形参:在函数定义阶段括号内指定的参数(变量名)
2、实参:在函数调用阶段括号内传入的值(变量值)
形参和实参的关系:
在调用函数时,实参值会绑定给形参名,在调用完毕后解除绑定
细分:
形参系列:
1、位置形参:在定义函数时,按照从左到右的顺序依次定义的变量名
特点:每次调用,必须被赋值
def func(name,age):
print(name)
print(age)
2、默认形参:在定义函数时已经为某个形参赋值了
特点:调用函数时,可以不用为其赋值
def func(name,age=19):
print(name)
print(age)
func("jay")
func("jay",99)
注意:位置形参和默认形参可以混用
但是:a、位置实参必须前面
b、默认形参的值通常应该是不可变类型,但是实际情况又需要可变
def func(name,hobby,hobbies = None):
if hobbies is None:
hobbies = []
hobbies.append(hobby)
print('%s的爱好是%s' %(name,hobbies))
func('jay','music')
func('didi','computer')
func('toushao','drink',['many woman'])
c、默认形参的值是在函数定义阶段赋值的
m=111
def func(x,y,z=m):
print(x)
print(y)
print(z)
m=666
func(1,2)
------------------->1
2
111
实参系列:
1、位置实参:在调用函数时,按照从左到右的顺序依次传入的值
特点:按照位置为形参赋值,一 一对应
func('jay',19)
2、关键字实参:按照key=value的形式赋值
特点:可以打乱顺序,但是仍然能够给指定的形参赋值
func(age = 19,name = 'jay')
注意:位置实参和关键字实参可以混用
但是:a、位置实参必须在关键字实参前面
func('jay',age=19)------>成立
func(age=19,'jay')------>报错
b、不能为同一形参重复赋值
def foo(x,y,z):
pass
foo(1,y=2,3) ---------->报错
foo(1,y=2,z=3,x=4)----->报错
3、可变长系列:
可变长参数:*与**
在调用时,传入的实参个数不固定,对应必须有特殊模式的形参来接收溢出的实参
==================*与**在形参中是一种汇总行为=====================
1、*在形参中的应用:*会将溢出的位置实参合并成一个元组,然后赋值给紧跟其后的形参名
def func(x,*args): # y = (2,3,4,5)
print(x)
print(args)
func(1,2,3,4,5)
def num(*args):
res = 0
for i in args:
res += i
print(res)
num(1,9)
2、**在形参中的应用:**会将溢出的关键字实参合并成一个字典,然后赋值给紧跟其后的形参名
def func(x,**kwargs): # kwargs = {"a":2,"c":4,"b":3}
print(x)
print(kwargs)
func(1,a=2,b=3,c=4)
==================*与**在实参中是一种打散行为=====================
1、*在实参中的应用:*后可以跟可以被for循环遍历的任意类型,*会将紧跟其后的那个值打散成位置实参
def func(x,y,z):
print(x)
print(y)
print(z)
func([11,22,33])
func(*[11,22,33]) # func(11,22,33)
func(*"hello") # func("h","e","l","l","o")
func(*{"k1":111,"k2":2222}) # func("k1","k2")
2、**在实参中的应用:**后只能跟字典类型,*会字典打散成关键字实参
func(**{"k1":111,"k2":2222}) # func(k2=2222,k1=111)
func(**{"x":111,"y":2222,"z":333})
例:重在理解
def index(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs): # args=(1,2,3,4,5,6) kwargs={"a":1,"b":2,"c":3}
index(*args,**kwargs) # index(*(1,2,3,4,5,6),**{"a":1,"b":2,"c":3})
# index(1,2,3,4,5,6,a=1,b=2,c=3)
# wrapper(1,2,3,4,5,6,a=1,b=2,c=3)
wrapper(1,2,3,4,5,6,a=1,b=2,c=3)
(了解)命名关键字形参: 在*与**中间的形参
特点: 必须按照key=value的形式传值
def func(x,m=333,*args,y=222,z,**kwargs):
print(x)
print(args)
print(y)
print(z)
print(kwargs)
func(1,2,3,z=4,a=1,b=2,c=3)
func(1,2,3,4,5,6,7)
五、函数返回值
return:
函数结束的标志,即函数代码一旦运行到return会立刻终止函数的运行,并且会将return后的值当做本次运行的结果返回:
返回值有三种情况:
1、返回None:函数体内没有return
return
return None
2、返回一个值:return 值
3、返回多个值 值1,值2,值3:用逗号分隔开多个值,会被return返回成元组
def func():
return 10,'aaa',[1,2]
res = func()
print(res,type(res))--------》(10, 'aaa', [1, 2]) <class 'tuple'>

浙公网安备 33010602011771号