文章目录
一.函数的介绍
函数就是一堆组织好的,可以重复使用的,用来实现单一或者相关联功能的代码段。
函数的优点是能提高应用的模块性和代码的重复利用率,其缺点是沉余、可读性很差、维护性很差。
二.函数的基本使用
1.函数的定义
定义函数的格式如下:
def 函数名(参数):
函数要执行的操作
定义函数的规则:
1.函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
2.任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
3.函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
4.函数内容以冒号起始,并且缩进。
5.return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
2.函数的调用
定义好一个函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它,而调用函数很简单的,直接通过函数名() 即可完成调用。
def ex1():
print('我被调用了')
ex1() # 我被调用了
当一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用。
def ex1():
print('ex1被调用了')
ex2()
print('ex1被调用了啦')
def ex2():
print('ex2被调用了')
ex1()
运行结果:
ex1被调用了
ex2被调用了
ex1被调用了啦
如果当一个函数里面又调用了另外一个函数,先把另一个函数都执行完之后,再回到上次函数执行的位置。
3.注意事项
1.定义好函数后,函数体里的代码并不会执行,如果想要执行函数体里的内容,需要手动的调用函数。
2.每次调用函数时,函数都会从头开始执行,当这个函数中的代码执行完毕后,意味着调用结束了。
3.如果函数中执行到了return也会结束函数。
三.函数的参数
函数声明时,括号里的参数我们称之为形式参数,简称形参。
形参的值是不确定的,只是用来占位的。
函数调用时传入的参数,才是真正参与运算的数据,我们称之为实参。
在调用函数时可使用的正式参数类型有以下几种:必需参数、关键字参数、缺省参数、不定长参数。
1.必需参数
必需参数需要以正确的顺序传入函数,调用时的数量必须和声明时的一样。
def ex1(a, b):
return a + b
print(ex1(1, 2)) # 3
2.关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
def student(name, age):
print('姓名:', name)
print('年龄:', age)
student(age=18, name='zhangsan')
运行结果:
姓名: zhangsan
年龄: 18
3.缺省参数(默认参数)
调用函数时,如果没有传递参数,则会使用默认参数。
def student(name, age=18):
print('姓名:', name)
print('年龄:', age)
student(name='zhangsan')
运行结果:
姓名: zhangsan
年龄: 18
注意:带有默认值的参数一定要位于参数列表的最后面。
4.不定长参数
如果需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数。
def student(a, b, *args, **kwargs):
print('a={},b={},args={},kwargs={}'.format(a, b, args, kwargs))
student(1, 2, 'hello', 'world', name='zhangsan', age=18)
运行结果:
a=1,b=2,args=(‘hello’, ‘world’),kwargs={‘name’: ‘zhangsan’, ‘age’: 18}
注意:变量*args会存放所有未命名的变量参数,args为元组。
变量**kwargs会存放命名参数,即形如key=value的参数, kwargs为字典。
5.注意事项
如果很多个值都是不定长参数,那么这种情况下,可以将缺省参数放到 args的后面, 但如果有**kwargs的话,kwargs必须是最后的。
四.函数的返回值
返回值就是函数执行的结果,并不是所有的函数都必须要有返回值
使用返回值的前提需求就是函数调用者想要在函数外使用计算结果
1.带有返回值的函数
想要在函数中把结果返回给调用者,需要在函数中使用return。
def add(a, b):
c = a + b # 变量c在外部是不可见的,只能在函数内部使用
return c # return 表示一个函数的执行结果
print(add(1, 2)) # 3
2.保存函数的返回值
一个函数返回了一个数据,如果想用这个数据,就需要保存。
def add(a, b):
return a + b
result = add(1, 2)
print(result ** 2) #9
如果一个函数没有返回值,它的返回就是None
3.函数的多个返回值
1.多个return语句
一般情况下,一个函数可以有多个return语句,但只会执行一个return语句。
因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数
def a():
print('hello')
return 1
print('world')
return 2
a() #hello
特殊情况(finally语句)下,一个函数可能会执行多个return语句。
def demo1(a, b):
try:
x = a + b
return x
finally:
print('我还能运行')
print(demo1(1,2))
运行结果:
我还能运行
3
def demo1(a, b):
try:
x = a + b
return x
finally:
print('我还能运行')
return 'hello' # 如果函数里有finally,finally里的返回值会覆盖之前的返回值
print(demo1(1,2))
运行结果:
我还能运行
hello
2.一个函数返回多个数据的方式
def clac(a, b):
add = a + b
jian = a - b
return add, jian
result = clac(2, 1)
print(result) # (3, 1)
1.return后面可以是元组,列表、字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据。
2.如果return后面有多个数据,那么默认是元组。
3.对返回的数据直接拆包
def student():
name = 'zhangsan'
age = 18
score = 99
return name, age, score
# result=student() 默认是元组
# print(result) ('zhangsan', 18, 99)
student_name,student_age,student_score=student() # 直接把元组拆分为三个变量来使用,更加方便
print(student_name) # zhangsan
print(student_age) # 18
print(student_score) # 99
1.拆包时要注意,需要拆的数据的个数要与变量的个数相同,否则程序会异常。
2.除了对元组拆包之外,还可以对列表、字典等拆包
五.函数的注释查看
想要对函数的注释进行了解,可以使用help查看文档说明
def add(a: int, b: int):# 注意,形参上标注的类型只是提高代码的可读性,并不会限制实参的类型
"""
这个函数用来将两个数字相加
:param a: 第一个数字
:param b: 第二个数字
:return: 两个数字相加的结果
"""
return a + b
help(add) # 使用help查看add函数的文档说明
x = add(1, 2) # 函数可以正常调用
print(x) # 3
运行结果:
Help on function add in module main:
add(a: int, b: int)
这个函数用来将两个数字相加
:param a: 第一个数字
:param b: 第二个数字
:return: 两个数字相加的结果
3
六.函数的高级
1.全局变量和局部变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。
#定义全局变量
x = 1
def test1():
print(x) # 虽然没有定义变量x,但是依然可以获取其数据
def test2():
print(x) # 虽然没有定义变量x,但是依然可以获取其数据
# 调用函数
test1() # 1
test2() # 1
1.在函数外边定义的变量叫做全局变量
2.全局变量能够在所有的函数中进行访问
在函数内部定义并使用的变量,这样的变量叫做局部变量。
def test1():
x = 'hello' #x为局部变量,只能在函数内部使用
print('x = {}'.format(x)) # x = hello
#print(x) #会报错
1.局部变量的作用:为了临时保存数据需要在函数中定义变量来进行存储。
2.其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的。
3.因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量。
4.当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了。
全局变量和局部变量名字相同问题:
如果局部变量的名和全局变量同名,会在函数内部又定义一个新的局部变量,而不是修改全局变量。
x = 1
def test1():
x = 2
print('函数内部x = {}'.format(x))
test1()
print('函数外部x = {}'.format(x))
运行结果:
函数内部x = 2
函数外部x = 1
修改全局变量:
使用global对变量进行声明,可以通过函数修改全局变量的值。
x = 1
def test1():
global x
x = 2
print('函数内部x = {}'.format(x))
test1()
print('函数外部x = {}'.format(x))
运行结果:
函数内部x = 2
函数外部x = 2
1.如果在函数中出现global 全局变量的名字,那么这个函数中即使出现和全局变量名相同的变量名 = 数据,也理解为对全局变量进行修改,而不是定义局部变量
2.如果在一个函数中需要对多个全局变量进行修改,那么可以一次性全部声明,也可以分开声明
2.1 可以使用一次global对多个全局变量进行声明
global x, y
2.2 可以用多次global分开声明
global x
global y
查看所有的全局变量和局部变量:
Python提供了两个内置函数globals()和locals()可以用来查看所有的全局变量和局部变量。
x = 1
def test1(): a= 2
print('locals = {}'.format(locals()))
test1()
print('globals = {}'.format(globals()))
2.可变数据类型和不可变数据类型
所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变,否则是不可变。
可变类型(修改数据,内存地址不会发生变化)有: 列表、字典、集合
def demo(nums):
print('修改前nums的内存地址0x%X' % id(nums))
nums[0] = 10
print('修改后nums的内存地址0x%X' % id(nums))
y = [3, 5, 6, 8, 2]
print('调用前y的内存地址0x%X' % id(y))
demo(y)
print('调用后y的内存地址0x%X' % id(y))
print(y)
运行结果:
调用前y的内存地址0x1E65A0A5208
修改前nums的内存地址0x1E65A0A5208
修改后nums的内存地址0x1E65A0A5208
调用后y的内存地址0x1E65A0A5208
[10, 5, 6, 8, 2]
不可变类型(修改数据,内存地址必定发生变化)有: 数字、字符串、元组
def test(a):
print('修改前a的内存地址0x%X' % id(a))
a = 100
print('修改后a的内存地址0x%X' % id(a))
x = 1
print('调用前x的内存地址0x%X' % id(x))
test(x)
print('调用后x的内存地址0x%X' % id(x))
print(x)
运行结果:
调用前x的内存地址0x7FFFE8507110
修改前a的内存地址0x7FFFE8507110
修改后a的内存地址0x7FFFE8507D70
调用后x的内存地址0x7FFFE8507110
1