函数的基本使用
1、什么是函数
ps:函数就是盛放代码的容器
具备某一功能的工具 ---> 函数
事先准备工具的过程 ---> 函数的定义
遇到应用场景拿来就用 ---> 函数的调用
所以函数的使用原则:
先定义 后调用
2、为何要用函数
解决下述问题:
1、代码组织结构不清晰,可读性差
2、可扩展性差
3、如何用函数
定义的语法
def 函数名(参数1,参数2,...):
"""文档描述"""
函数体
return 返回值
1、def:定义函数的关键字
2、函数名:函数名指的是函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能
3、括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型
4、冒号:括号后面要加冒号,然后在下一行开始缩进编写函数体的代码
5、''''文档描述''':描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性
6、函数体:由语句和表达式组成
7、return 返回值:定义函数的返回值,return是可有可无的,不一定要加在最后一行
调用的语法
一、定义函数
定义函数发生的事情
1、申请内存空间把函数体代码放进去
2、将函数内存地址绑定给函数名
强调:定义函数只检测语法,不执行代码
def login(): # login = 函数的内存地址
print(111)
print(222)
print(333)
print(login)
>>>:
<function login at 0x000002193ECEC1F0>
二、调用函数
调用函数发生的事情
1、先通过函数名定位到函数内存地址
2、函数内存地址() ---> 触发函数体代码的运行
强调:调用函数才会执行函数体代码
login()
# >>>:
# 111
# 222
# 333
三、定义函数的三种形式
无参
def func():
print('hello world')
有参
def max2(x,y):
if x > y:
print(x)
else:
print(y)
max2(10,20) # 20
空
def login():
pass # pass代表什么都不做
# ...
四、调用函数的三种方式
语句
表达式
res = len('hello') * 10
print(res) # 50
可以当做一个参数传给另一个参数
函数的参数
形参
在函数定义阶段括号内指定的参数,称之为形式参数,简称形参
位置形参
在定义函数时,按照从左到右的顺序依次定义的变量名,称之为位置形参
特点:每次调用,必须被赋值
def func(x,y):
print(x)
print(y)
func(1,2)
默认形参
在定义函数时,就已经为某个形参赋值了,称之为默认形参
特点:调用函数时,可以不用为其赋值
def func(name,age=18):
print(name)
print(age)
func('egon')
>>>:
egon
18
注意
注意:可以混用位置形参与默认形参,但是:
1、位置形参必须在前面
2、默认形参的值,通常应该是不可变类型
3、默认形参的值是在函数定义阶段赋值的
实参
在函数调用阶段括号内传入的值,称之为实际参数,简称实参
位置实参
在调用函数时,按照从左到右的顺序依次传入的值,称之为位置实参
特点:按照位置为形参赋值,一一对应
func(1,2) # 1 2
func(2,1) # 2 1
关键字实参
在调用函数时,按照key=value的形式传值,称之为关键字实参
特点:可以大乱顺序,但是仍然能够指名道姓的为指定的形参赋值
def func(name,age):
print(name)
print(age)
func(age=18,name='egon')
>>>:
egon
18
注意
可以混用位置实参与关键字实参,但是:
1、位置实参必须在关键字实参的前面
2、不能为同一形参重复赋值
形参与实参的关系
在调用函数时,实参值会绑定给形参名,在函数调用完毕之后解除绑定
# 形参
def func(x,y):
# x = 111
# y = 222
print(x,y)
# 实参
m = 111
n = 222
func(111,222)
可变长系列
详情参见:https://www.cnblogs.com/ZhZhang12138/p/14200978.html#hanshudefanhuizhi
可变长参数指的是在调用函数时,传入的实参个数不固定,对应着必须有特殊形式的形参来接收移除实参
实参无非两种形式
溢出的位置实参 ---> *
溢出的位置关键字实参 ---> **
函数的返回值
return详解
1、函数可以有多个return,但只要执行一次return,整个函数就立即结束,并且将return后的值当做本次调用的结果返回
2、return后返回值有三种情况
(1)return 值:返回的就是这一个值
(2)return 值1,值2,值3:返回的是一个元组
(3)函数内可以没有return、或者return None、或者return:默认返回None
函数对象
在python中,函数时第一类对象,函数是第一等公民
本质:函数可以当变量使用
函数对象指的是函数可以被当做’数据’来处理,具体可以分为四个方面的使用,如下
def func(): # func = 函数的内存地址
print('from func')
# # 1、可以赋值
f = func
print(f)
f()
# 2、可以当做参数传给另外一个函数
def foo(x):
print(x)
foo(func) # <function func at 0x000001FF3854C1F0>
# 3、可以当做函数的返回值
def foo(x):
return x
res = foo(func)
print(res) # <function func at 0x000001F48080C1F0>
# 4、可以当做容器类型的元素
l = [func,]
print(l) # [<function func at 0x000001F132A5C1F0>]
l[0]() # from func
函数的嵌套
函数的嵌套调用
def ma2(x,y):
if x > y:
return x
else:
return y
def max4(a,b,c,d):
res1 = ma2(a,b)
res2 = ma2(res1,c)
res3 = ma2(res2,d)
return res3
print(max4(11,99,33,12)) # 99
函数的嵌套定义
def f1():
x = 10
def f2():
print(x)
print(x)
print(f2)
f1()
>>>:
10
<function f1.<locals>.f2 at 0x00000255051DA0D0>
名称空间与作用域
名称空间与作用域的关系是在函数定义阶段(扫描语法时)就确立的,与什么时候调用以及调用位置无关
namespace名称空间:存放名字的地方
内置名称空间:存放内置的名字
生命周期:python解释器启动则产生,关闭则销毁
全局名称空间:存放的是顶级的名字
生命周期:运行python文件时则产生,python文件运行完毕则销毁
局部名称空间:存放的是函数内的名字
生命周期:调用函数则产生,函数调用完毕则销毁
核心:名字的访问优先级:
基于当前所在的位置向外查找
函数内 ---> 外层函数 ---> ... ---> 全局 ---> 内置
LEGB
L:内置
E:外层函数
G:全局
B:内置
作用域
全局作用域:内置名称空间+全局名称空间
特点:全局存活,全局有效
局部作用域:局部名称空间
特点:临时存活,局部有效
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字
# 案例一:
l = []
def func():
l.append(111)
# l = [11,22,33] # 定义了一个新列表,与全局无关
func()
print(l) # [111]
# 案例二:
x = 111
def func():
global x
x = 222
func()
print(x) # 222
对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)
def f1():
x = 2
def f2():
nonlocal x # 声明变量名是来自于外层函数的,不是全局
x = 3
f2() # 调用f2(),修改f1作用域中名字x的值
print(x) #在f1作用域查看x
f1()