1.什么是函数?
函数就是具备某一功能的工具。
工具的使用:
实现准备好工具 =========》函数定义
遇到应用场景拿来就用 =======》函数的调用
2.为什么要有函数?
1、程序的组织结构不清晰,可读性差
2、如果要用到重复功能,只能拷贝功能的实现代码=》代码冗余
3、可扩展性差
3.如何用函数?
函数的使用原则:先定义后使用
定义函数:
def 函数名(参数1,参数2,参数3.....):
代码1
代码2
......
return 返回值
调用函数:
函数名(值1,值2,值3......)
定义一个函数和定义一个变量是类似的,申请内存空间把函数的代码保存起来,然后把内存地址绑定给函数名=》函数名=函数的内存地址
def sayhi():
print ("="*10)
print ("hellow")
print ("="*10)
调用函数就是函数名() =》函数的内存地址(),会触发函数体代码的运行
sayhi()
二、定义函数的三种方式
2.1 无参函数
def login:
inp_name = input("your name:").strip()
inp_pwd = input("your pwd:").strip()
if inp_name=="egon" and inp_pwd=="123":
print(""登陆成功!)
else:
print("登陆失败!")
2.2 有参函数
def sayhi(n,i):
print(n*i)
sayhi("=",3)
def incharge(x,y):
if x>y:
print(x)
else:
print(y)
incharge(3,4)
2.3 空函数
def func():
...或者pass#适合刚刚开始写代码,对于没有逻辑的代码用这个实现
三、函数的调用
return:函数内可以有多个return,但只要执行一次函数就立刻结束,并会把return后的值当作本次调用的结果返回。
函数可以有三种形式的返回值
1、return值:返回的就是该值的本身
2、return 值1,值2,值3:返回一个元组
3、没有return:默认返回None
def salary(x,y):
if x>y:
return(x)
else:
return(y)
salary_year = salary(2.1,1.8)*12
print(salary_year)#计算年薪需要返回值,所以用return
四:函数调用的三种格式
1.语句形式:单纯地调用一下函数就完了
def sayhi(n,i):
print(n*i)
sayhi("=",3)
2.表达式形式
def salary(x,y):
if x>y:
return(x)
else:
return(y)
salary_year = salary(2.1,1.8)*12
print(salary_year)
3. 把函数的调用当作值传送给另外一个函数
def salary(x,y):
if x>y:
return(x)
else:
return(y)
print(salary(11,22))
总结:函数的使用一定要分两个阶段去看:
1、定义阶段:只检测语法,不执行代码
2、调用阶段:执行函数体代码
如果发生的语法错误,定义阶段就会立马检测出来
如果发生的不是语法错误,而是逻辑错误,只能在调用阶段检测到
五、函数的参数分为两大类:
1、形参:在定义函数时,括号内定义的变量名,称之为形式参数,简称形参=》变量名
2、实参:在调用函数时,括号内传入的值,称之为实际参数,简称实参=》变量值
六、在python中参数的种类
1、位置参数:
(1)在函数定义阶段按照从左到右的顺序依次定义形参(变量名),称之为位置形参。
特点:必须被传值(少一个不行多一个也不行)
(2)在函数定义阶段按照从左到右的顺序依次定义实参(传入的变量值),称之为位置实参
特点:按照位置一一对应的传值
2、关键字实参:在函数调用阶段按照key = value的形式为指定的形参名传值,该形式称之为关键字实参
特点:在传值时可以完全打乱顺序,但是仍然能够指名道姓的为指定形参传值。
def func(name,age):
print(name,age)
func(age = 18,name ="egon")
注意:1.可以混用位置实参和关键字实参,但是位置实参必须放在关键字实参的前面
2.不能为同一个形参重复赋值
3、默认形参:在函数定义阶段就已经为某个形参赋值了,该形参称之为有默认值的形参,简称默认形参。
特点:定义阶段就已经被赋值意味着在函数调用阶段可以不用为其赋值。
注意:
1.默认形参应该跟在位置形参的后面
2.默认形参的值通常应该是不可变类型
3.默认形参的值只在函数定义阶段被赋值一次,函数定义之后的改变对默认形参没有影响
七、*与**在形参与实参中的应用
1、可变长参数
可变长指的是参数的个数不固定
站在实参的角度,实参是用来为形参赋值的,如果实参的个数不固定,那么必须要有对应的形参能够接收那些溢出的实参
1.1在形参名前面加*:*会把溢出的位置实参存成元组,然后赋值其后的形参名
def func(x,*y):
print(x)
print(y)
func(1,2,3,5)
1.2在形参名前面加**:**会把溢出的关键字实参存成字典,然后赋值其后的形参名
def func(x,**y):
print(x)
print(y)
func(1,a=1,b=2,c=3)
1.3在实参前加*:*会把其后的值打散成位置实参
def func(x,y,z):
print(x)
print(y)
print(z)
a = [1,2,3]
func(*a)
1.4在实参前加**:**会把其后的值打散关键字实参
def func(x,y,z):
print(x)
print(y)
print(z)
dic = {"x":1,"y":2,"z":3}
func(**dic)
1.5 在形参混用*和**
def index(x,y,z,a,b,c):
print(x,y,z,a,b,c)
def func(*d,**e):
index(*d,**e)
func(1,2,3,a=111,b=222,c=333)
命名关键字形参(**)
def func(x, y=222, *args, n=777,m, **kwargs): # m,n必须按照关键字实参的格式为其赋值
print(x) # 1
print(y) # 2
print(args) # (3,4,5)
print("m===>", m)
print("n===>", n)
print(kwargs)
# func(1,2,3,4,5,6666666)
# func(1,2,3,4,5,m=6666666)
func(1, 2, 3, 4, 5, n=88888,m=6666666, a=11, b=22, c=33)
八、函数对象指的是函数可以被当成变量去使用
def foo():# foo = 函数的内存地址
print('from foo')
1 可以被赋值
f = foo
print(fis foo)
f()
2 可以当作参数传给一个函数
def bar(func):
print(func)
func()
bar(foo)
3 可以当成一个函数的返回值
def bar(func):
return func
res=bar(foo)
print(res)
4 可以当成容器类型的元素
l = [foo]
print(l)
l[0]()
示例:
def login():
print('登录功能......')
def withdraw():
print('提现功能......')
def transfer():
print('转账功能......')
def recharge():
print('充值功能')
func_dic={
"1": [login,"登录"],
"2": [withdraw,"提现"],
"3": [transfer,"转账"],
"4": [recharge,"充值"]
}
while True:
print("0 退出")
for kin func_dic:
print("%s %s" %(k,func_dic[k][1]))
choice =input("请输入你的指令编号: ").strip()
if choice =="0":
break
if choicein func_dic:
func_dic[choice][0]()
else:
print('输入的指令不存在') #利用函数对象使代码更加简洁
九、函数的嵌套
1.函数的嵌套调用
def bar():
print('from bar')
def foo():
print('from foo')
bar()
foo()
案例:
def max2(x,y):
if x > y:
return x
else:
return y
def max4(a,b,c,d):
res1 = max2(a,b)
res2 = max2(res1,c)
res3 = max2(res2,d)
print(res3)
max4(1,2,3,4)#先定义一个比大小的函数,后面进行赋值操作时直接调用。
2 函数的嵌套定义
def f1():
print('from f1')
# f2 = 函数的内存地址
def f2():
print("from f2")
f1()
3.定义在函数内的函数特点是: 正常情况只能在函数体内调用
from math import pi
def circle(radius,mode=0):
def perimiter(radius):
return 2 * pi * radius
def area(radius):
return pi * (radius ** 2)
if mode == 0:
return perimiter(radius)
elif mode == 1:
return area(radius)
res1=circle(3,0)
res2=circle(3,1)
print(res1)
print(res2)
十、名称空间: 就是存放名字的地方
1 内置名称空间: 存放的是内置的名字,如print\input\len
生命周期: 解释器启动则产生,解释器关闭则销毁
2 全局名称空间: 存放的是顶级的名字
生命周期: python程序运行时则产生,python程序结束则销毁
3 局部名称空间:函数内的名字
生命周期:调用函数时则产生,函数调用结束则销毁
名字的查找优先级:
从当前位置往外查找,如果当前是在局部:局部名称空间->全局名称空间->内置名称空间
从当前位置往外查找,如果当前是在全局:全局名称空间->内置名称空间
实例:
x =10
def msg():
x =11
def esg():
x =12
print(x)
esg()
print(x)
msg()
print(x)
一个非常重要的结论:名称空间的嵌套关系是函数定义阶段(即扫描语法时)就固定死的,与函数的调用位置无关
佐证:
x =111
def foo():
print(x)
def bar(f):
x=222
f()
bar(foo)
l = ["aaa","bbb",[000,111,222]]
def msg():
l[2][0] =444
msg()
print(l)#中间的l是基于上面l的修改,所以输出的值为修改后的值。
全局范围/全局作用域:内置名称空间+全局名称空间
特点:全局存活,全局有效
局部范围/局部作用域:局部名称空间
特点:临时存活,局部有效
案例1:
x =10
def func():
global x
x=22
func()
print(x)
案例2:
x =10
def f1():
x=111
def f2():
x=222
f2()
print(x)
f1()
print(x)
案例3:nonlocal生命名字是来自于外层函数的(***)与案例2进行对比
x =10
def f1():
x=111
def f2():
nonlocal x
x=222
f2()
print(x)
f1()
print(x)