前戏
工作中代码量肯定很多,代码量随之增大,此时仍不加区分地把所有功能的实现代码放到一起,将会使得程序的组织结构不清晰,可读性变差,且程序中需要频繁使用同一功能时,只能重复编写该功能的实现代码,日积月累,程序将变得冗长,并且当某一功能需要修改时,又不得不找出所有定义及使用这段功能的地方修改,管理维护的难度极大,所以。。。所以。。。所以。。。怎么办呢?
我们完全可以从现实生活中找到简化程序设计的方案:比如上你家修空调或修水龙头的青年男人,他不会去徒手造一个螺丝刀或锤子去修的,肯定带了工具箱,那么函数就是我们代码里面的工具,可以拿来重复使用,即函数的调用。
定义函数
函数的使用必须遵循’先定义,后调用’的原则。函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,这和变量的定义是相似的。没有事先定义函数而直接调用,就相当于在引用一个不存在的’变量名’。
函数的语法结构
def 函数名(参数1,参数2):
'''函数注释'''
函数体代码
return 返回值
参数是函数的调用者向函数体传值的媒介,若函数体代码逻辑依赖外部传来的参数时则需要定义为参函数,
def register(name, age, gender='male'):
print(name, age, gender)
函数的分类
1.内置函数
解释器已经提前定义好的函数 程序员直接拿来使用即可
eg:len()
2.自定义函数
无参函数
函数在定义阶段括号内没有写参数
eg:
def my_func():
print(123)
调用无参函数不需要额外的条件 直接函数名加括号即可
3.有参函数
函数在定义阶段括号内写了参数
eg:
def my_index(a, b):
print(321)
调用有参函数需要额外的条件 括号内需要'给东西'
4. 空函数
函数体代码什么都没有
eg:
def my_outer():
pass
主要用于项目前期思路搭建 提示程序员后续需要做的操作
函数的返回值调用
1.如何理解返回值
调用函数之后可以返回给调用者的信息
2.如何获取返回值
变量名 = 函数调用
3.返回值具体操作
- 函数体代码如果没有return 默认返回None(什么都没有 布尔值为False)
- 函数体代码如果有return 后面上面都不写的话 返回的也是None
- 函数体代码如果有return 后面写什么就返回什么
- 函数体代码如果有return 并且有多个数据值逗号隔开 会自动组织成元组返回
- 函数体代码执行到return 就会立刻结束该函数(类似于break)
函数参数的概念
形式参数
函数在定义阶段括号内填写的参数称之为形式参数 简称为"形参"
实际参数
函数在调用阶段括号内填写的参数称之为实际参数 简称为"实参"
形参与实参的关系(重要)
形参类似于变量名 实参类似于数据值
函数在调用阶段形参和实参会临时绑定 函数运行结束会立刻断开绑定
def func(a): # a形参
print(a)
func(1) # 1实参
形参的命名尽量见名知意 提示调用者大致应该传什么类型的数据
位置参数
位置形参
函数定义阶段括号内从左往右依次填写的'变量名'
位置实参
函数调用阶段括号内从左往右依次填写的'数据值'(数据值、绑了值的变量名)
def func(a, b):print(a, b)
# func(1, 2) # 按照位置顺序一一传值
# func(1) # 少一个不行
# func(1, 2 ,3) # 多一个不行
关键字参数
关键字实参
函数调用阶段括号内通过指名道姓的方式传'数据值'(数据值、绑了值的变量名)
例子:
def func(a, b):print(a, b)
# func(a=1, b=2)
# func(b=1, a=2) # 指名道姓的传 可以不考虑位置顺序
# func(b=1, 2) # 位置参数一定要写在关键字参数的前面
# func(1, a=2) # 一个形参不能同时传两个实参
name = ‘lele'
age = 18
func(name, age)
默认参数
函数在定义阶段就已经给括号内形参赋值了
例子:
def register(name, age, gender='male'):print(name, age, gender)
register('1', 18)
register('2', 38)
register('3', 28)
register('4', 18, '0')
"""
无论是形参还是实参 都应该遵守
越短(简单)的越靠前 越长(复杂)的越靠后
"""
可变长参数
- 在形参中可以接收多余的位置实参 并组织成元组的形式赋值给符号后面的变量名(*)
- 在形参中可以接收多余的关键字实参 并组织成字典的形式赋值给符号后面的变量名(**)
- 在实参中可以将容器类型中所有的数据值for循环出来一个个传给函数(*)
- 在实参中可以将字典的kv键值对变成关键字参数传给函数(**)
*和**后面的变量名理论上怎么写都行 但是为了统一 建议使用(*args **kwargs)
例子:
def index(*args, **Kwargs):print(args)
print(Kwargs)
命名关键字参数
在定义了**kwargs参数后,函数调用者就可以传入任意的关键字参数key=value,如果函数体代码的执行需要依赖某个key,必须在函数内进行判断
def register(name,age,**kwargs):if 'sex' in kwargs:
#有sex参数
pass
if 'height' in kwargs:
#有height参数
pass
想要限定函数的调用者必须以key=value的形式传值,Python3提供了专门的语法:需要在定义形参时,用作为一个分隔符号,号之后的形参称为命名关键字参数。对于这类参数,在函数调用时,必须按照key=value的形式为其传值,且必须被传值
def register(name,age,*,sex,height): #sex,height为命名关键字参数... pass
...
>>> register('lili',18,sex='male',height='1.8m') #正确使用
>>> register('lili',18,'male','1.8m') # TypeError:未使用关键字的形式为sex和height传值
>>> register('lili',18,height='1.8m') # TypeError没有为命名关键字参数height传值。
名关键字参数也可以有默认值,从而简化调用
>>> def register(name,age,*,sex='male',height):... print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height))
...
>>> register('lili',18,height='1.8m')
Name:lili,Age:18,Sex:male,Height:1.8m
需要强调的是:sex不是默认参数,height也不是位置参数,因为二者均在后,所以都是命名关键字参数,形参sex=’male’属于命名关键字参数的默认值,因而即便是放到形参height之前也不会有问题。另外,如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了
>>> def register(name,age,*args,sex='male',height):... print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height))
...
>>> register('lili',18,1,2,3,height='1.8m') #sex与height仍为命名关键字参数
Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m