函数初识
什么是函数或者说为什么要用函数?
函数就是包裹一部分代码,去实现某一个功能,还可以重复使用这个功能。总结一下:
函数:功能:包裹一部分代码,实现某一个功能,达成一个目的
特点:可以反复调用,提高代码的复用性,提高开发效率,便于维护管理
函数的定义和使用
函数的基本格式:
函数的定义:
def 函数名():
code1
code2
函数的调用:
函数名():
# 定义函数
def func():
# code1
print("我是一个函数")
# 调用函数
func()
函数的定义:
def: 表示函数的关键字
函数名: 函数的名称, 根据函数名调用函数
函数体: 函数中进行一系列的逻辑计算
参数: 为函数执行完毕后, 可以给调用者返回数据
函数的命名规则
函数的命名规则:
字母数字下划线,首字符不能为数字
严格区分大小写,且不能使用关键字
函数命名有意义,且不能使用中文命
驼峰命名法:
(1) 大驼峰命名法:每个单词的首字符大写 (类:面向对象)
mycar => MyCar mydesk => MyDesk
(2) 小驼峰命名法:除了第一个单词的首字符小写之外,剩下每个单词首字符大写
mycar => myCar mydesk => myDesk
mycar => my_car mydesk => my_desk
symmetric_difference
# 函数的定义处
def cfb_99():
for i in range(1,10):
for j in range(1,i+1):
print("%d*%d=%2d " % (i,j,i*j) , end="")
print()
# 函数的调用处
for i in range(10):
cfb_99()
函数的参数
概念
函数的参数(参数:配合函数运算的值)
参数:
(1)形参:形式参数,在函数的定义处
(2)实参:实际参数,在函数的调用处
形参:普通形参(位置在调用处),默认形参,普通收集形参,命名关键字形参,关键字收集形参
实参:普通实参,关键字实参
遵循原则:
形参和实参要一一对应
普通形参
# 1.普通形参
# 函数的定义处
"""hang,lie是函数的普通形参"""
def s_star(hang,lie):
i = 0
while i < hang:
j = 0
while j < lie:
print("*",end="")
j+=1
print()
i+=1
# 函数的调用处
"""10,10 是函数的实际参数"""
s_star(10,10)
s_star(3,8)
默认形参
# 2.默认形参
def s_star(hang=10,lie=10):
i = 0
while i < hang:
j = 0
while j < lie:
print("*",end="")
j+=1
print()
i+=1
# 函数的调用处
"""
在函数调用时:
如果给予实参,那么直接使用实际参数
如果没有给予实参,那么使用参数默认自带的值
"""
s_star() # 10行10列小星星
s_star(3,8) # 3行8列小星星
s_star(4) # 4行10列小星星
普通形参+默认形参
# 3.普通形参 + 默认形参
# 函数的定义处
"""默认形参必须跟在普通形参的身后,顺序是一定的"""
def s_star(hang,lie=10):
i = 0
while i < hang:
j = 0
while j < lie:
print("*",end="")
j+=1
print()
i+=1
# 函数的调用处
s_star(3,3) # 3行3列
s_star(3) # 3行10列
s_star() # error
关键字实参
关键字实参是对具体的某个参数赋值,具体的顺序可以打乱
# 4.关键字实参
"""关键字实参是对具体的某个参数赋值,具体的顺序可以打乱"""
# 函数的定义处
def s_star(hang,a,b,c,d,lie=10):
i = 0
while i < hang:
j = 0
while j < lie:
print("*",end="")
j+=1
print()
i+=1
# 函数的调用处
s_star(hang=4,a=1,b=2,c=3,d=4,lie=5)
s_star(c=3,d=4,lie=5,hang=4,a=1,b=2) # 关键字实参参数顺序可以打乱
普通实参+关键字实参
关键字实参必须跟在普通实参的身后,顺序是一定的
# 5.普通实参 + 关键字实参
def s_star(hang,a,b,c,d,lie=10):
i = 0
while i < hang:
j = 0
while j < lie:
print("*",end="")
j+=1
print()
i+=1
# 函数的调用处
"""关键字实参必须跟在普通实参的身后,顺序是一定的"""
s_star(5,6,99,c=7,d=8,lie=9)
s_star(c=7,d=8,lie=9,5,6,99) # error 关键字实参必须跟在普通实参的后面
s_star(5,1,c=2,d=3,lie=10,b=5) # ok
s_star(5,1,c=2,d=3,lie=10,a=5) # error 重复给a赋值,错误
要注意区分默认形参和关键字实参
默认参数和关键字实参 在写法上一模一样
默认形参是在函数的定义处
关键字实参是在函数的调用处
普通收集参数 *args
"""
1.普通收集参数: 专门用来收集多余的没人要的普通实参
def func(*args):
code...
*args => arguments(参数)
在args这个参数的前面加上一个*表达普通收集参数,形成一个元组
"""
# 基本使用
def func(a,b,c,*args):
print(a,b,c) # 1 2 3
print(args) # (4,5,6,7,8)
func(1,2,3,4,5,6,7,8)
# 计算任意个数的累加和
def func(*args):
total = 0
for i in args:
total += i
print(total)
func(1,2,3,4,6,10,11,100)
关键字收集参数 **kwargs
"""
2.关键字收集参数 : 专门用来收集多余的没人要的关键字实参
def func(**kwargs):
code1...
**kwargs => keyword arguments
在kwargs参数的前面加上2个**表达关键字收集参数,形成一个字典
"""
# 基本使用
def func(a=1,b=2,c=3,**kwargs):
print(a,b,c)
print(kwargs) # {'f': 1, 'g': 2, 'j': 3}
func(f=1,g=2,j=3,a=15,b=16,c=17)
# 任意个数字符串的拼接
"""
班长:张三
班花:李四
班草:王麻子
吃瓜群众:小明,吴京,张涵予
"""
def func(**kwargs):
print(kwargs)
# 定义一个字典,存放每一位同学的身份
dic = {"monitor":"班长","class_flower":"班花","class_grass":"班草"}
strvar1 = ""
strvar2 = ""
# 遍历字典中的键值对
for k,v in kwargs.items():
print(k,v) # monitor 张三 class_flower 李四 class_grass 王麻子 ....
# 判断键是否在字典当中,如果在,获取对应的身份,拼装成字符串
if k in dic:
strvar1 += dic[k] + ":" + v + "\n" # 班长 + ":" + 张三 + '\n'
else:
strvar2 += v + ","
# 去掉右边多余的\n和,形成最后的效果
print(strvar1.strip())
print("吃瓜群众:"+ strvar2.rstrip(","))
func(monitor="张三",class_flower="李四",class_grass="王麻子",eatgua1="小明",eatgua2="吴京",eatgua3="张涵予")
命名关键字参数
# 3.命名关键字参数
"""
定义命名关键字参数的两种方式:
(1)def func(a,b,*,c) c是命名关键字
(2)def func(*args,c,**kwargs) c是命名关键字参数
在函数调用时,必须使用命名关键字参数来进行赋值
"""
# 定义方式一
def func(a,b,*,d,c):
print(a,b) # 1 2
print(d) # 3
print(c) # 10
func(1,2,d = 3,c=10)
# 定义方式二
def func(*args, c, **kwargs):
print(args) # (1, 2, 3, 4, 5, 6)
print(c) # 100
print(kwargs) # {'a': 1, 'b': 2, 'd': 6}
func(1, 2, 3, 4, 5, 6, a=1, b=2, d=6, c=100)
关于* 和 ** 的使用方法
* 和 ** 在函数的定义处,用来做收集操作,打包
* 和 ** 在函数的调用处,用来做打散操作,解包
# * 解包列表
def func(a,b,*,c,d):
print(a,b)
print(c,d)
lst = [1,2]
# *把列表里面的所有元素拿出来,当成参数一个一个赋值给func进行调用
func(*lst,c=3,d=4)
# ** 解包字典
def func(a,b,*,c,d):
print(a,b)
print(c,d)
dic = {"c":3,"d":4}
# **把字典里面的所有元素拿出来,拼装成键=值的参数形式,赋值给func进行调用
func(1,2,**dic,) # func( c=3, d=4 )
# *和**的组合
func(*lst,**dic)
strvar = "abc"
print(*strvar)
形参定义的顺序
当所有参数都在一起的时候,按照什么顺序定义呢?
参数定义的顺序:普通参数 -> 默认参数 -> 普通收集参数 -> 命名关键字参数 -> 关键字收集参数
收集到所有的实参: def func(*args,**kwargs)
函数的返回值
关键字:return
自定义函数的返回值,return可以把值返回到函数的调用处
1.return+六大标准数据类型,还有类和对象,函数
如果不定义return,默认返回的是None
2.在执行return之后,立刻终止函数,后面的代码不执行
函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回
# 1.return的返回类型
def func():
# return 1
# return 3.14
# return "abc"
# return []
# return ()
# return {"a":1}
pass
res=func()
# 如果不定义return,默认返回的是None
print(res)
# 2.在执行完return 之后,立刻终止函数,后面的代码不执行
def func():
print(1)
print(2)
return 3 # 立刻终止函数,后面的print(4)和print(5)不执行
print(4)
print(5)
res =func()
print(res)
def func():
for i in range(3):
if i==2:
return 1
print(i)
res = func()
print(res) # 0 1 1
# 3.模拟简单的计算器 + - * /
def func(sign,num1,num2):
if sign=="+":
res= num1+num2
elif sign=="-":
res =num1-num2
elif sign=="*":
res = num1*num2
elif sign=="/":
if num2 ==0:
return "除数不能为0,老弟"
res = num1/num2
else:
return "这个本计算器真算不了"
return res
res = func("+",3,5)
res = func("-",10,20)
res = func("*",10,20)
res = func("/",20,10)
res = func("/",20,0)
res = func("&",20,0)
print(res)
全局变量和局部变量
局部变量:在函数内部定义的变量(局部命名空间)
全局变量:在函数外部定义的或者使用global在函数内部定义(全局命名空间)
作用域:作用的范围
局部变量作用域:在函数的内部
全局变量作用域:横跨整个文件
生命周期:
内置变量>全局变量>局部变量
局部变量
# 局部变量
def func():
# 定义局部变量
a=5
# 获取局部变量
print(a)
# 修改局部变量
a=10
print(a)
func()
print(a) # error 不能在全局调用局部变量
全局变量
# 全局变量
# 定义全局变量
b=10
# 获取全局变量
print(b)
# 修改全局变量
b=20
def func():
# 可以在函数内部获取全局变量
print(b)
func()
使用global在函数内部创建全局变量
# 使用global在函数内部创建全局变量
def func():
global c
c=200
func()
print(c)
使用global在函数内部修改全局变量
# 使用global在函数内部修改全局变量
d=300
def func():
global d
d=400
func()
print(d)
可以使用global关键字在函数内部定义一个全局变量
也可以使用global关键字在函数内部修改一个全局变量
函数名的使用
函数名是一个特殊的变量,可以把函数当做变量对它赋值
def func():
print("我是func函数")
return 1
# 函数名是个特殊的变量,可以当做变量赋值
a="你好"
print(a)
a=func()
# a()
# 函数可以像变量一样销毁
del a
a()
函数名可以作为容器类型数据的参数
# 函数名可以作为容器类型数据的元素
def func1():
print("我是func1函数")
def func2():
print("我是func2函数")
def func3():
print("我是func3函数")
lst=[func1,func2,func3]
for i in lst:
print(i)
i() # func1() func2() func3()
函数名可以作为函数的参数
# 函数名可以作为函数的参数
def func3():
print("我是func3函数")
def func4(f):
f() # 我是func3函数
func4(func3)
函数名可以作为函数的返回值
# 函数名可以作为函数的返回值
def func(f):
return f
res = func(func2) # f---> func2 -----> res=func2()
res()
__ doc__ 或者help查看文档
# __doc__ 或者help查看文档
def func(a):
"""
功能:xxxx
参数:a
返回值:1
"""
print("xxxx")
return 1
help(func)
res = func.__doc__
print(res)
输出结果: 功能:xxxx
参数:a
返回值:1
函数的嵌套
例子
def outer():
def inner():
print("我是inner函数")
inner()
outer()
inner() # 调用外部函数时,内部函数不可以再函数外部调用!
概念
1.内部函数不能直接在函数外部调用
2.调用外部函数后,内部函数不能在函数外部调用
3.内部函数可以在函数内部调用
4.内部函数在函数内部调用时,有先后顺序,必须先定义再调用
函数嵌套案例
# 外层是outer,内层是inner,最里层是smaller,调用smaller里面的所有代码
def outer():
def inner():
def smaller():
print("我是smaller函数",id)
smaller()
inner()
outer()
nonlocal关键字
nonlocal 遵循LEGB就近找变量原则
1.找当前空间上一层的局部变量进行修改
2.如果找不到,会继续向上寻找
3.最后什么也没有,直接报错
LEGB原则
找寻变量的调用顺序采用LEGB原则,即就近原则
B- Builtin(Python):python内置模块的命名空间 (内建作用域)
G- Global(module):函数外部所在的命名空间(全局作用域)
E -Enclosing function locals:外部嵌套函数的作用域(嵌套作用域)
L -Local(function):当前函数内的作用域(局部作用域)
依据就近原则 从下向上 由里向外 依次寻找
nonlocal使用案例
找当前空间上一层的局部变量进行修改
# 找当前空间上一层的局部变量进行修改
def outer():
a=100
def inner():
nonlocal a
a=200
print(a) # 200
inner()
print(a) # 200
outer()
如果找不到,会继续向上寻找
# 如果找不到,会继续向上寻找
def outer():
a=100
def inner():
def smaller():
nonlocal a
a=400
print(a) # 400
smaller()
print(a) # 400
inner()
print(a) # 400
outer()
注意点:nonlocal只能修改局部变量
# 注意点:nonlocal只能修改局部变量
a=100
def outer():
def inner():
def smaller():
nonlocal a # nonlocal只能修改局部变量,而本程序中第一行的a是全局变量,nonlocal无法修改
a=400
print(a)
smaller()
print(a)
inner()
print(a)
outer()
不使用nonlocal修改局部变量—>只能适用于列表
# 不使用nonlocal修改局部变量
def func():
lst=[1,2,3,4]
def inner():
lst[-1]=10
inner()
print(lst)
func()
globals和locals
locals
locals 获取当前作用域中所有变量
locals 如果在全局,调用locals之后,获取的是打印之前的所有变量,返回字典,全局空间作用域
locals 如果在局部,调用locals之后,获取的是调用之前的所有变量,返回字典,局部空间作用域
# locals 在全局:获取打印之前的所有变量
def func():
ff = 123
a = 1
b = 2
res = locals()
c = 3
print(res) # 是一个大字典,里面有很多键值对,a:1 b:2 c:3均可以打印出来(截止到打印之前)
d = 4 # d:4 不会被打印
# locals 在局部
a1 = 10
def func():
a = 1
b = 2
res = locals()
c = 3
print(res) # a:1 b:2 会被打印出来 截止到调用local()之前的都会被打印出来
d = 4
a2 = 20
func()
a3 = 30
globals
globals 只获取全局空间中所有变量
globals 如果在全局,调用globals之后,获取的是打印之前的所有变量,返回字典,全局空间作用域
globals 如果在局部,调用globals之后,获取的是调用之前的所有变量,返回字典,全局空间作用域
# global 在全局
def func():
ff = 123
a = 1
b = 2
res = globals() # a:1 b:2 c:3 截止到打印之前
c = 3
print(res)
d = 4
# global 在局部
a1 = 10
def func():
a = 1
b = 2
res = globals()
c = 3
print(res)
d = 4
a2 = 20
func() # globals() a1:10 a2:20 截止到调用处
a3 = 30
globals 动态批量创建全局变量
# 用字符串定义全局变量
dic = globals() # 必须是global定义的字典,普通字典无效
print(dic) # 返回的是系统的字典
# 在全局的字典当中,通过添加键值对,自动创建全局变量
# 对应的键时变量名,对应的值是变量指向的值
dic["name"] = "致和"
print(name) # 致和
# 批量定义全局变量
def func():
dic = globals()
# 通过在全局系统字典当中,添加键值对,批量创建变量
for i in range(1,6):
# "a%d" % (1) => "a1" "a%d" % (2) => "a2"
dic["a%d" % (i)] = i # 1~5
func()