一、函数
1、函数的定义
- 如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
2、函数的语法及调用
定义语法:
# def 是定义函数的关键词
def 函数名():
函数体中要执行的代码
调用函数:
# 函数定义完成后,在需要的地方直接通过函数名()即可进行调用
def fun():
print("hello world!!!")
# 以下代码即为函数的调用
fun()
注意:函数一定要先定义再调用
3、函数的文档说明
文档说明格式:
"""
函数的文档说明
"""
def 函数名():
"此处是编写函数文档说明的地方,需要紧贴着函数定义写,不能写在函数执行代码之后,否则文档将会失效"
print("hello world!!!")
help(函数名)
"""
控制台输出结果:
Help on function 函数名 in module __main__:
函数名()
此处是编写函数文档说明的地方需要紧贴着函数定义写,不能写在函数执行代码之后,否则文档将会失效
"""
4、函数的四种使用形式
"""
函数的四种使用形式
"""
# 1.没有参数,没有返回值
def printInfo():
print("用户信息")
printInfo()
# 2.有参数,没有返回值
def printInfo2(name, age):
print("用户姓名是:%s" % name)
printInfo2("岳飞", None)
# 3.没有参数,有返回值
def printInfo3():
a = 10
if a > 5:
return # return : 如果return后面没有任何内容,则返回None。如果没有return,则也表示返回None
# None同False、0一样可以用在if判断中,表示条件不成立
return 12
print(printInfo3()) # None
if printInfo3():
print("111")
else: # 222
print("222")
# 4.有参数,有返回值
def calc(x, y):
if x.isdigit() & y.isdigit():
return int(x) + int(y)
else:
return "输入的数据不正确"
print(calc(input("请输入第一个数字:"),input("请输入第二个数字:")))
5、函数的参数
(1)、位置参数形式
def printInfo2(name, age):
print("用户姓名是:%s,年龄是%s" % (name, age))
# 1.位置参数形式:即对应的位置上传递对应的参数
printInfo2("岳飞", None)
(2)、关键字参数形式
def printInfo2(name, age):
print("用户姓名是:%s,年龄是%s" % (name, age))
# 2.如果调用函数是不确定参数的位置,可以使用关键字参数形式,写法如下:
printInfo2(age=18, name="秦桧")
printInfo2("崇祯", age=18)
(3)、默认参数形式
# 3.默认参数:在定义函数时,就给参数设置默认值
def fun(name, age=18):
print("name=%s,age=%d"%(name,age))
fun("袁世凯") # name=袁世凯,age=18 如果调用函数时,没有给参数,则使用默认值
fun("蒋介石",20) # name=蒋介石,age=20 如果给了参数,就会覆盖默认值
注意:默认参数不能使用可变数据类型,例如:字典、列表等
(4)、可变参数
"""
可变参数
"""
# 1. *args : 收集所有的位置参数,合并为元组
def function(*args): # args 就是可变参数
print(type(args)) # <class 'tuple'>
print(args) # ('袁世凯', '徐世昌', '段祺瑞', '曹汝霖')
for i in args:
print(i, end="\t")
function()
function("袁世凯") # 袁世凯
function("袁世凯","徐世昌","段祺瑞","曹汝霖") # 袁世凯 徐世昌 段祺瑞 曹汝霖
function("袁世凯",18) # 袁世凯 18
# 2. **args : 收集所有的关键字参数,合并为一个字典
def function2(**args):
print(type(args)) # <class 'dict'>
print(args) # {'name': '袁世凯', 'age': 18, 'gender': '男', 'address': '北京'}
for key,value in args.items():
print(key,value,end="\t")
# 调用函数时,实参必须是关键字参数
function2()
function2(name="袁世凯", age=18, gender="男", address="北京") # name 袁世凯 age 18 gender 男 address 北京
(5)、命名关键字参数
"""
命名关键字参数:强制控制命名关键字的个数
"""
# * 代表修饰符,即 * 之后的所有参数都必须使用关键字参数进行传值,* 之前的没有要求
def function(name, age, *, gender, address):
print(name, age, gender, address)
function("康有为", 20, gender="男", address="北京胡同") # gender和address必须使用关键字参数
(6)、参数的混合使用
"""
多种参数的混合使用
"""
# 如果参数没有通过关键字参数传值,默认遵循位置参数的顺序
# 如果有 **kwargs,默认放到最后接收
def function(a, b=20, c="hehe", *args, **kwargs):
print(a)
print(b)
print(c)
print(args)
print(kwargs)
# 调用函数
function("梁启超", 22, "北京", 100, 200, 300, 400, 500, action="戊戌变法", time="19世纪末")
"""
打印结果:
梁启超
22
北京
(100, 200, 300, 400, 500)
{'action': '戊戌变法', 'time': '19世纪末'}
"""
6、函数的返回值
"""
函数的返回值
"""
# 1. return 一个值
def calc(num1, num2, num3):
"""
:param num1: 左运算数
:param num2: 运算符
:param num3: 右运算数
:return: 返回值
"""
# pass pass代表程序走到这一行时不执行任何操作
if num2 == "+":
return num1 + num3
elif num2 == "-":
return num1 - num3
elif num2 == "*":
return num1 * num3
elif num2 == "/":
return num1 / num3
else:
print("输入的运算符有问题")
# 查看函数的帮助文档
help(calc)
# 调用函数
print(calc(10, "+", 30)) # 40
# 2. return 返回多个值
def caclMore(num1, num2):
return num1 ** 2, num2 ** 3 # 返回多个值时,默认将返回值打包,即打成一个元组返回
print(caclMore(10, 5)) # (100, 125)
value1, value2 = caclMore(10, 6) # 此操作是拆包
7、局部变量和全局变量
(1)、局部变量
- 局部变量,就是在函数内部定义的变量
- 其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的
- 因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储
- 当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了
- 在函数外边定义的变量叫做全局变量
- 全局变量能够在所有的函数中进行访问
- 当函数内出现局部变量和全局变量相同名字时,函数内部中的
变量名 = 数据
此时理解为定义了一个局部变量,而不是修改全局变量的值 - 如果在函数中出现
global 全局变量的名字
那么这个函数中即使出现和全局变量名相同的变量名 = 数据
也理解为对全局变量进行修改,而不是定义局部变量 - 如果在一个函数中需要对多个全局变量进行修改,那么可以使用
(3)、局部变量和全局变量的使用 -- global关键字
# 在此处声明的变量叫做全局变量
num1 = 1000
num2 = 2000
def test01():
num1 = 100 # 此处定义的变量叫做局部变量
# 在函数体内修改全部变量,作用范围只能是函数内,出了函数,全局变量值不变
num1 = 100
print(num1) # 100
# 如果想在函数内修改全局变量,同时想在函数外也保持修改后的值,需要用到global关键字
# 注意:使用global关键字修改全局变量,必须先在函数体内声明,再使用
global num2 # 声明要修改的全局变量
num2 = 2001 # 此时修改完成之后,在函数外全局变量的值也已经修改
test01()
print(num1) # 1000
print(num2) # 2001
"""
总结:什么时候需要加上global关键字
1.如果只是使用全局变量的值,有没有global关键字都一样
2.如果要在函数体内修改局部变量的值,就必须使用global关键字,并且需要先声明,再去修改
3.如果全局变量是可变数据类型(列表、字典)的值,则不管在函数体内需不需要修改全局变量,都不用加gbal关键字
"""
8、命名空间
(1)、命名空间(作用域):为了防止多个变量名冲突,而引入的一种对变量名作用范围分组的机制。
Python里的命名空间:
- 局部命名空间:函数内的命名空间就是局部的
- 全局命名空间:模块内的命名空间就是全局的
- 内置命名空间:内置函数、异常处理等都是内置命名空间
(2)、命名空间的访问:
locals():包含所有局部变量的命名空间,格式是字典类型
globals():包含所有全局变量的命名空间,格式也是字典类型、
(3)、命名空间的查找顺序: LEGB 规则: "由内而外" (Python2.2 之前不支持函数嵌套,所有只有LGB)
L - Local :局部命名空间
E - Enclosing Function :嵌套函数的命名空间
G - Global : 全局命名空间
B - Built-in : 内置命名空间
(4)、命名空间的生命周期:某个命名空间里的变量的存活时间
- 局部命名空间:从函数调用时开始、到函数结束后(return、正常执行结束、抛出异常),是该命名空间下的变量存活时间,函数结束后变量被回收(要么引用计数减1)
- 全局命名空间:从模块加载(代码执行)开始、到程序执行结束后,是全局命名空间的存活时间
- 内置命名空间:从Python解释器启动开始、到程序执行结束,是内置命名空间的存活时间。
9、引用
(1)、引用
lis1 = [10, 20, 30]
lis2 = lis1
# lis1 和 lis2 操作的是同一个列表对象,id 相同,值相同,同时操作也同步
# lis1 引用 lis2的数据,不管做任何修改,都会影响所有的引用。
lis1.append(10)
# lis2 也会被修改。
(2)、 浅拷贝: list.copy() dict.copy()
import copy
copy.copy
# 浅拷贝会创建新的列表对象,id 不一样,但是里面子对象不拷贝,还是是同一个
lis1 = [1,2,3,4]
lis3 = lis1.copy()
# copy() 的当时里面的数据是一样,但是之后 lit1 做任何操作都不会影响lis3
# 列表对象相同,但是子对象不同
str = "gesdg"
str.split("") # 字符串是不可变类型,会生成新字符串
list.append(10) #列表是可变类型,不会生成新字符串
(3)、深拷贝
import copy
lis1 = [1,23,4]
lis4 = copy.deepcopy(lis1)
# 深拷贝会创建一个和 lis1 没有任何关系的列表
# 不仅id不同,连子对象的id也不同了,操作也不会同步。
总结:不管是引用,还是浅拷贝,还是深拷贝,在使用小整数对象池的时候,小整数id还是一样的。
10、匿名函数(lambda表达式)
"""
lambda表达式:(匿名函数)
1. lambda表达式是单一的一种表达式语句,没有语句块。
2. lambda表达式是为了编写简单的函数而设计的,不能编写复杂的函数。def 定义的函数可以处理复杂的逻辑
3. lambda默认会有返回值,但是不是通过return返回的,而是在 : 号后面的就代表返回值
4. lambda表达式可以没有参数,也可以有多个参数(支持可变参数、默认参数等)
5. lambda表达式的 :后面不能写输出语句,但是可以写表达式、if判断等
"""
# 定义一个普通结构的函数
def test01():
return 100
"""
以上函数使用lambda表达式改造如下:
1. 使用 lambda 关键字,表示后面的是一个lambda表达式
2. : 前面放置的是函数的入参,如果没有参数可以不写,但是要留出空位置。
3. : 后面放置的是函数的返回值,如果没有可以不写
"""
lambda : 100 # lambda表达式的写法
# 调用lambda表达式,如果只是执行一次,就可以直接吧lambda放到输出体中
print((lambda : 100)()) # 100
# 或者如下方式调用:该方式是如果多次使用lambda表达式,就可以将lambda表达式赋值给对象,然后多次调用对象
f =lambda : 100
print(f()) # 100
"""
带参数带返回值的lambda表达式
"""
# 定义一个普通的带参数带返回值的函数
def test02(a, b):
return a + b
print(test02(10, 12))
# 创建lambda表达式对象
f = lambda a, b: a + b
print(f(8,3)) # 11
# 直接调用lambda表达式
print((lambda a, b: a * b)(2, 5)) # 10
"""
多种情况返回值的lambda表达式
"""
# 定义普通函数
def test03(a, b):
if a < b:
return a + b
else:
return a - b
# 以上函数体的判断方式不够pythonic(python化),可以用如下方式写(类似于java中的三元表达式)
def test04(a, b):
# 解释:如果 if a < b 成立,则表达式的结果是 a + b,否则表达式的结果是 a - b
return a + b if a < b else a - b
print(test03(1, 3)) # 4
print(test04(1, 3)) # 4
# 使用lambda表达式改造上述 test04 的函数如下
f = lambda a, b: a + b if a < b else a -b
print(f(5,3)) # 2
print((lambda a, b: a + b if a < b else a -b)(20,15)) # 5
# lambda表达式的默认参数
f = lambda a, b, c=20: a + b +c
print(f(10,20,100)) # 130
# lambda表达式接收可变参数
f = lambda *args: args
print(f(10,20,30,40,50)) # (10, 20, 30, 40, 50)
f = lambda *args, a=10,b=20: list(args)+[a,b]
print(f(1,2,3,4,5,6)) # [1, 2, 3, 4, 5, 6, 10, 20]
# 字典类型的可变参数
f = lambda **kwargs: kwargs
print(f(name="嬴政", age=18, gender="男")) # {'name': '嬴政', 'age': 18, 'gender': '男'}
f = lambda **kwargs: {value: key for key, value in kwargs.items()}
print(f(name="嬴政", age=18, gender="男")) # {'嬴政': 'name', 18: 'age', '男': 'gender'}
# lambda表达式作为函数的参数传递
def test00(a, b, f):
return f(a, b)
print(test00(10, 20, lambda x, y: x + y)) # 30