函数
函数的了解
1 什么是函数
函数就相当于具备某一功能的工具
函数的使用必须遵循一个原则:
先定义
后调用
具备某一功能的工具=====》函数
工具的使用:
事先准备好工具========》函数的定义
遇到应用场景拿来就用===》函数的调用
2 为何要用函数数
1、程序组织结构不清晰,可读性差
2、代码冗余==如果要用到重复的功能,只能拷贝功能的实现代码
3、可维护性、扩展性差
3 如何用函数
先定义:三种定义方式
后调用:三种调用方式
返回值:三种返回值的形式
定义函数:
def 函数名(参数1,参数2,参数3…):
“”“文档注释”""
代码1
代码2
代码3
return 返回值
调用函数:
函数名(值1,值2,值3)
函数的基本使用
1、定义函数:申请内存空间把函数体代码保存下来,然后把内存地址绑定给函数名-》函数名=内存地址
def sayhi():
print('*'*10)
print('hello')
print('*'*10)
print(sayhi)
2、调用函数:函数名()=》函数的调用地址
sayhi()
sayhi()
定义函数发生的事情
1、申请内存空间保存函数体代码
2、将上述内存地址绑定函数名
3、定义函数不会执行函数体代码,但是会检测函数体语法
调用函数发生的事情
1、通过函数名找到函数的内存地址
2、然后加括号就是在触发函数体代码的执行
定义函数的三种格式
1 无参函数
def sayhi():
print('='*20)
print('hello')
print('='*20)
sayhi()
# ====================
# hello
# ====================
# 登录功能
def login():
inp_name=input("your name: ").strip()
inp_pwd=input("your pwd: ").strip()
if inp_name == "egon" and inp_pwd == "123":
print('login successful')
else:
print('login error')
login()
2 有参函数
def max2(x,y):
# x=10
# y=20
if x > y:
print(x)
else:
print(y)
max2(10,20) # 20
max2(11,22) # 22
def sayhi(s,n):
# s = '-'
# n = 20
print(s*n)
print('hello')
print(s*n)
sayhi('-',20)
sayhi('*',10)
# --------------------
# hello
# --------------------
# **********
# hello
# **********
3 空函数
空函数主要用来对代码进行分类列出总的大概流程,先用空函数代替,然后将每部分代码写入。
def func():
pass
函数的返回值return
return:函数内可以有多个return,但只要执行一次函数就立刻结束,并会把return后的值当做本次调用的结果
1、return值:返回的就是该值本身
2、return值1,值2,值3:返回一个元组(包含所有值 值可以是任意类型)
3、 没有return: 默认返回None
函数体内没有return
return
return None
1 return值:返回的就是该值本身
def func():
print(1)
print(2)
print(3)
return 456
res = func() # 1\n 2\n 3\n
print(res) # 456
def func():
print(111)
return 1
print(222)
return 2
print(333)
return 3
res = func() # 111
print(res) # 1
2 return值1,值2,值3:返回一个元组(包含所有值 值可以是任意类型)
def func():
return 123,[1,2],{'k2':34},'hshs'
res = func()
print(res) # (123, [1, 2], {'k2': 34}, 'hshs')
3 没有return: 默认返回None # 可以用来干掉循环
def func():
return
res = func()
print(res) # None
def func():
return None
res = func()
print(res) # None
def func():
print('123')
res = func() # 123
print(res) # None
# 可以用来干掉循环 执行一次结束
def func():
while True:
while True:
return
res = func()
print(res) # None
def func():
for i in range(21):
print(i)
return
res = func() # 0
print(res) # None
函数调用的三种形式
1 语句的形式:只加括号调用函数,单纯的调用函数就完了
def func():
print('-'*20)
print('hello')
func()
def func(x,y):
print(x*y)
print('hello')
func('-',20)
def add(x,y): # 参数-》原材料
res1=x + y
print(res1)
return res1 # 返回值-》产品 # 没有返回值 返回的就是None
add(1,2) # 3
2 表达式形式
# 赋值表达式
def max2(x,y):
if x > y:
return x
else:
return y
res = max2(11,22)
print(res) # 22
# res = max2
# print(res) # <function max2 at 0x7fcc9f0d5790>
def add(x,y): # 参数-》原材料
res1=x + y
# print(res1)
return res1 # 返回值-》产品 # 没有返回值 返回的就是None
res = add(1,2)
print(res) # 3
# 数学表达式
def add(x,y): # 参数-》原材料
res1=x + y
# print(res1)
return res1 # 返回值-》产品 # 没有返回值 返回的就是None
res=add(1,2)*10
print(res) # 30
3 可以把函数的调用当作值传给另外一个函数
def max2(x,y):
if x > y:
return x
else:
return y
print(max2(11,22)) # 22
def add(x,y): # 参数-》原材料
res1=x + y
# print(res1)
return res1 # 返回值-》产品 # 没有返回值 返回的就是None
res=add(add(1,2),10)
print(res) # 13
总结
函数的使用一定要分两个阶段去看:
1、定义阶段:只检测语法,不执行代码
2、调用阶段:执行函数体代码
nbsp; def func():
nbsp; nbsp; print(‘addasd’ # 少个括号 语法错误
nbsp; 若发生的不是语法错误,而是逻辑错误,只能在调用阶段检测到
nbsp; def func(): # 逻辑错误
nbsp; nbsp; xxx
nbsp; func()
# 示范1:
def bar():
print('from bar')
def foo():
print('from foo')
bar()
foo()
示范2:
def foo():
print('from foo')
bar()
def bar():
print('from bar')
foo()
函数的参数
形参
在定义函数时,括号内定义的变量名,称之为形式参数,简称形参=》变量名
def func(x,y):
x=1
y=2
print(x)
print(y)
实参
在调用函数时,括号内传入的值,称之为实际参数,简称实参=》变量值
# 形式一:
func(1,2)
# 形式二:
a=1
b=2
func(a,b)
# 形式三:
func(int('1'),2)
func(func1(1,2,),func2(2,3),333)
形参与实参的关系:
1、在调用阶段,实参(变量值)会绑定给形参(变量名)
2、这种绑定关系只能在函数体内使用
3、实参与形参的绑定关系在函数调用时生效,函数调用结束后解除绑定关系
在python中参数的种类
1 位置参数
位置形参
在函数调用阶段按照从左到右的顺序依次定义实参(传入的变量值),称之为位置实参
特点:按照位置传值,一一对应
位置实参
在函数调用阶段按照从左到右的顺序依次定义实参(传入的变量值),称之为位置实参
特点:按照位置传值,一一对应
# 位置形参
def func(x,y):
print(x,y)
func(1,2)
func(1) # 少一个不行
func(1,2,3) # 多一个也不行
# 位置实参
func(1,2,3,4,5,6)
2 关键字实参
在函数调用阶段按照key=value的形式为指定的形参名传值,该形式称之为关键字实参
特点:指名道姓给某个形参传值,可以完全不参照顺序
def func(name,age):
print(name,age)
func(age=18,name='egon') # egon 18
3 混用位置实参与关键字实参
注意:
1 位置实参必须放在关键字实参的前面
2 不能为同一个形参重复赋值
# 1、位置实参必须放在关键字实参前
def func(x,y):
print(x,y)
# func(1,y=2)
# func(y=2,1) # 报错 原因:位置参数跟在关键字参数后面
# 2、不能能为同一个形参重复传值
# func(1,y=2,x=3) # 报错
# func(1,2,x=3,y=4) # 报错
def func(name, age, salary):
print(name)
print(age)
print(salary)
# func('egon',salary=3.1,age=18)
# func('egon',salary=3.1,18) # 错误 位置参数跟在关键字参数后面
# func('egon', 18, salary=3.1)
# func('egon',18,age=19,salary=3.3) # 报错 同一个形参重复传值
4 默认参数
在函数定义阶段就已经为某个形参赋值,该形参称之为有默认值的形参,简称默认形参
特点:定义阶段就已经被赋值,意味着在函数调用阶段可以不用为其赋值
def func(x,y=2):
print(x,y)
func(1)
func(1,33333)
默认形参注意事项
1 默认形参应该放在位置形参的后面
def func(y=2,x): # 错误
pass
2 默认形参的值是在函数定义阶段被赋值的,准确地说被赋予的是值的内存地址默认形参的值只在函数定义阶段被赋值一次,函数定义之后的改变对默认形参没有影响
# 示范1:
m=22
def func(x,y=m): # y=>22的内存地址
print(x,y)
# m=3333333333333333333 # 没用 会报错 找不到m
func(1) # 1 22
示范2:
m = [111111, ]
def func(x, y=m): # y=>列表[111111, ]的内存地址
print(x, y)
m.append(3333333) # 加入列表中 所以可以加入
func(1)
3 默认形参的值通常应该是不可变类型,虽然默认值可以被指定为任意数据类型,但是不推荐使用可变类型,函数最理想的状态:函数的调用只跟函数本身有关系,不受外界代码的影响
# 原来的想法是 egon 的爱好是:['play'] sa 的爱好是:['music'] lili 的爱好是:['read']
l=[]
def func(name,hobby,hobbies=l):
hobbies.append(hobby)
print('%s 的爱好是:%s'%(name,hobbies))
func('egon','play')
func('sa','music')
func('lili','read')
# egon 的爱好是:['play']
# sa 的爱好是:['play', 'music']
# lili 的爱好是:['play', 'music', 'read']
def func(name,hobby,hobbies=None):
if hobbies is None:
hobbies=[]
hobbies.append(hobby)
print('%s 的爱好是:%s'%(name,hobbies))
func('egon','play')
func('sa','music')
func('lili','read')
# egon 的爱好是:['play']
# sa 的爱好是:['music']
# lili 的爱好是:['read']
可变长参数*与**
可变长指的是参数的个数不固定
站在实参的角度,实参是用来为形参赋值的,如果实参的个数不固定,针对溢出的实参必须要有对应的形参能够接收溢出的实参
在形参中用*与**
nbsp; *形参名:用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式然后赋值紧跟其后的形参名
nbsp; *后跟的可以是任意名字,但是约定俗成应该是args
def func(x,*y): # y=(2,3,4)
print(x) # 1
print(y) # (2, 3, 4)
func(1,2,3,4)
func(1)
# func() # 报错 位置形参x必须被传值
# 示范:
def add(*nums):
res = 0
for num in nums:
res += num
return res
res=add(1, 2, 3)
print(res) # 6
**形参名:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典格式,然后赋值给紧跟其后的形参名
**后跟的可以是任意名字,但是约定俗成应该是kwargs
def func(x, **y): # y=(2,3,4)
print(x)
print(y)
func(1,a=111,b=222,c=333)
func(a=111, b=222, x=1, c=333)
# 1
# {'a': 111, 'b': 222, 'c': 333}
# 1
# {'a': 111, 'b': 222, 'c': 333}
在实参中用*与**
在实参前加*:*会把其后的值打散成位置实参
def func(x,y,z):
print(x,y,z)
func(*[11,22,33]) # func(11,22,33) 11 22 33
# func(*[11,22]) # 报错 func(11,22)
l=[11,22,33]
func(*l)
在实参前加**:**会把其后的值打散关键字实参
def func(x,y,z):
print(x,y,z)
func(*{'x':1,'y':2,'z':3}) # func('x','y','z')# x y z
func(**{'x':1,'y':2,'z':3}) # func(x=1,y=2,z=3) #1 2 3
# 错误
# func(**{'x':1,'y':2,}) # func(x=1,y=2)
# func(**{'x':1,'a':2,'z':3}) # func(x=1,a=2,z=3)
混用*与**:*args必须在**kwargs之前
kwargs):
print(args)
print(kwargs)
func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)
# (1, 2, 3, 4, 5, 6, 7, 8)
# {'x': 1, 'y': 2, 'z': 3}
命名关键字形参
命名关键字参数:在定义函数时,*后定义的参数,如下所示,称之为命名关键字参数
特点:命名关键字实参必须按照key=value的形式为其传值
def func(x,y=222,*args,m,**kwargs): # m必须按照关键字实参的格式为其赋值 在*与**之间被称为命名关键字形参
print(x)
print(y)
print(args)
print('m======》',m)
print(kwargs)
func(1,2,3,4,5,666,m=111)
组合使用(了解):形参混用的顺序:位置形参,默认形参,*args,命名关键字形参,**kwargs
def func(x,y=111,*args,z,**kwargs):
print(x)
print(y)
print(args)
print(z)
print(kwargs)
# 实参混用的顺序:
def func(x,y,z,a,b,c):
print(x)
print(y)
print(z)
print(a)
print(b)
print(c)
# func(111,y=222,*[333,444],**{'b':555,'c':666})
# # func(111,y=222,333,444,b=555,c=666)
# func(111,*[333,444],a=222,**{'b':555,'c':666})
# # func(111,333,444,a=222,b=555,c=666)
# func(111,*[333,444],**{'b':555,'c':666},a=222,)
# # func(111,3333,4444,b=555,c=666,a=222)
函数对象
函数对象指的是函数可以被当成变量去使用
def foo(): # foo = 函数的内存地址
print('from foo')
1 可以被赋值
def foo(): # foo = 函数的内存地址
print('from foo')
f = foo
print(f is foo)
f()
# True
# from foo
2 可以当做参数传给一个函数
def foo(): # foo = 函数的内存地址
print('from foo')
def bar(func):
print(func)
func()
bar(foo)
# <function foo at 0x7ffd8cd00700>
# from foo
3 可以当成一个函数的返回值
def foo(): # foo = 函数的内存地址
print('from foo')
def bar(func):
return func
res=bar(foo)
print(res)
res=bar(foo())
print(res)
# <function foo at 0x7faa92c00700>
# from foo
# None
4 可以当成容器类型的元素
def foo(): # foo = 函数的内存地址
print('from foo')
l = [foo]
print(l)
l[0]()
# [<function foo at 0x7f9e4bb00700>]
# from foo
5 应用(ATM登录取款模型)
def login():
print('登录功能......')
def withdraw():
print('提现功能......')
def transfer():
print('转账功能......')
def recharge():
print('充值功能......')
func_dic = {
'1':[login,'登录'],
'2':[withdraw,'提现'],
'3':[transfer,'转账'],
'4':[recharge,'充值'],
}
# func_dic[1][0]()
# 学了函数对象后的优化 代码更简介 用for
# 代码比较少 要加内容时加的地方比较少
while True:
print('0 退出')
# 用for 实现选项表 func_dic中添加后下面自动添加
# 0 退出
# 1 登录
# 2 提现
# 3 转账
# 4 充值
for k in func_dic:
print('%s %s'%(k,func_dic[k][1]))
choice = input('请输入你的命令指令:').strip()
# 用choice in func_dic 来判断是否存在 存在运行相关函数
if choice == '0':
break
if choice in func_dic:
func_dic[choice][0]()
else:
print('输入的指令不存在,重新输入:')
# 没学函数对象时 以往的atm功能 if esle来操作
# 代码比较多,要加内容时好多地方要修改
# while True:
# print('''
# 0 退出
# 1 登录
# 2 提现
# 3 转账
# 4 充值
# ''')
# choice = input('请输入你的命令指令').strip()
# if choice == '0':
# break
# elif choice == '1':
# login()
# elif choice == '2':
# withdraw()
# elif choice == '3':
# transfer()
# elif choice == '4':
# recharge()
函数嵌套
函数的嵌套调用:在调用一个函数的过程中又调用其他函数
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):
# 第一步:比较a,b得到res1
res1=max2(a,b)
# 第二步:比较res1,c得到res2
res2=max2(res1,c)
# 第三步:比较res2,d得到res3
res3=max2(res2,d)
return res3
res=max4(1,2,3,4)
print(res)
函数的嵌套定义:在函数内定义其他函数
def f1():
print('from f1')
# f2 = 函数的内存地址
def f2():
print("from f2")
f1()
# f2() # 报错 顶级没有f2函数
# from f1
定义在函数内的函数特点是: 正常情况只能在函数体内调用
# 应用
# 圆形
# 求圆形的求周长:2*pi*radius
def circle(radius,action=0):
from math import pi
def perimiter(radius):
return 2*pi*radius
# 求圆形的求面积:pi*(radius**2)
def area(radius):
return pi*(radius**2)
if action == 0:
# return 2*pi*radius
return perimiter(radius)
elif action == 1:
return area(radius)
res1=circle(10,action=0)
res2=circle(10,action=1)
print(res1)
print(res2)