Python学习--函数
函数
[!NOTE]
以下内容部分摘录自
《Python编程快速上手——让繁琐的工作自动化(第二版)》
,并加入了一些自己的理解,仅用于个人交流与学习,如涉及侵权请联系站长删除!
1. 函数定义与调用
语法:使用
def
关键字定义函数。参数:函数可以接收
参数(变元)
,参数
在函数内部作为局部变量使用。示例:
1
2
3
4
5def hello(name):
print('Hello, ' + name)
hello('GSY') # 输出:Hello, GSY
hello('CYX') # 输出:Hello, CYX
解释:像
print()
或者len()
函数括号中经常带有一些值,他们称之为函数的参数
,也可以自己定义接收到参数的函数。- 如同上述例子一样:
hello函数
中有一个名叫name
的变元,当函数被调用时,参数
就存放在其中(保存在变元中的值,在函数返回后就消失了,例如:在hello('CYX')
之后再print(name)
那么程序就会报错。)
- 如同上述例子一样:
示例:
1
2
3def sayHello(abc):
print('Hello, ' + abc)
sayHello('AI')解释:
def sayHello(abc)
就是定义了一个这样的函数,而sayHello('AI')
行则是调用了这样的函数,这样的函数调用也将字符串里的AI
传递给该函数,传递给函数的值称为参数
,这里的abc
就是接受参数AI
的局部变量,也叫做变元。
2. 参数与返回值
返回值:使用
return
语句指定函数的返回值。若无return
,默认返回None
。示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import random
def getAnswer(answerNumber):
if answerNumber == 1:
return 'It is certain'
elif answerNumber == 2:
return 'It is decidedly so'
elif answerNumber == 3:
return 'Yes'
elif answerNumber == 4:
return 'Replay hazy try again'
elif answerNumber == 5:
return 'Ask again later'
elif answerNumber == 6:
return 'Concentrate and ask again'
elif answerNumber == 7:
return 'My replay is no'
elif answerNumber == 8:
return 'Outlook not so good'
elif answerNumber == 9:
return 'Very doubtful'
r = random.randint(1, 9)
fortune = getAnswer(r)
print(fortune) # 随机输出结果
- 解释:这是一个随机返回一句话的例子,我们首先定义了一个函数
getAnswer()
,之后又生成了一个随机变元r
它通过random
函数在1-9之间随机一个数字,之后再通过对应我们定义函数中对应的部分来返回相应的句子,一般来说函数调用求值的结果称为函数的返回值
,用def语句
创建函数时可以用return语句
指定应该返回什么值,return语句
包含 :- 1.
return
关键字 - 2.函数应该返回的值或者表达式(如果return语句中是有了表达式那么返回值就是求值的结果)
- 1.
3. 关键字参数与 None 值
None 值:无显式返回值的函数默认返回
None
。例如:print()
函数,它直接在屏幕上显示文本,但不需要返回任何值,既然所有的函数调用都需要一个返回值,那么它的返回值就是None,而对于所有没有return语句
的函数和不带值的return语句
他们的返回值都默认是None
关键字参数:通过参数名指定值,常用于可选参数。
示例:
1
2
3
4print('Hello', end=' ') # 输出:Hello World(不换行)
print('World')
print('cats', 'dogs', 'mice', sep=',') # 输出:cats,dogs,mice
- 解释:上面所展示的就是
print()
函数的两个可选的变元end
和sep
:sep
:指定参数间的分隔符,即:在参数之间输入什么来将他们分隔开(默认空格)。end
:指定末尾字符,即:指定在参数末尾输出什么(默认换行)。
4. 调用栈
调用栈:Python 通过栈结构管理函数调用,每次调用函数时创建帧对象,返回时销毁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def Alice():
print('Alice starts')
Bob()
Carol()
print('Alice returns')
def Bob():
print('Bob starts')
Carol()
print('Bob returns')
def Carol():
print('Carol starts')
print('Carol returns')
Alice()解释:调用栈是Python记住每个函数调用后在那里返回执行的方式,调用栈不是存储在程序的变量中而是由python在后台处理它,程序调用一个函数时python在调用栈的顶部创建一个
帧对象
,帧对象
保存了再出函数调用的行号,使得python可以记住返回的位置,如果进行了另一个函数的调用python会将另一个帧对象
放在调用栈中,且在前一个帧对象之上,当函数调用返回时,python从栈顶部删除一个对象并将执行栈转移至保存在其中的行号。注意 :帧对象始终是从栈顶部添加和删除的。
执行流程:
Alice()
调用Bob()
和Carol()
。Bob()
调用Carol()
。- 函数返回时按栈顺序退出。
代码输出:
1
2
3
4
5
6
7
8Alice starts
Bob starts
Carol starts
Carol returns
Bob returns
Carol starts
Carol returns
Alice returns
5. 作用域
全局作用域:函数外定义的变量,处于全局作用域中的变量称为全局变量。
局部作用域:函数内定义的变量,函数返回后销毁,处于局部作用域中的变量被称为局部变量。
规则:
全局作用域不能访问局部变量
1
2
3
4
5def spam():
eggs = 31337
spam()
print(eggs)
# 注意:这是错误的代码!!!- 解释:发生错误是因为
eggs
变量只属于spam()
调用所创建的局部作用域,在程序执行从spam
返回后,该局部作用域就被销毁了。
- 解释:发生错误是因为
不同函数的局部作用域相互独立
1
2
3
4
5
6
7
8
9
10def spam():
eggs = 99
bacon()
print(eggs)
def bacon():
ham = 101
eggs = 0
spam()
# 这串代码的输出结果为99- 解释:这串代码第一个局部作用域来自于
spam函数
的调用,其中eggs
的值为99,然后bacon函数
被调用,创建了第二个局部作用域,在新的作用域中ham
被赋值为101,eggs
赋值为0,当bacon函数
返回时,这次调用的局部作用域被销毁,程序执行在spam函数
中继续输出eggs
的值,所以eggs
值为99被输出。
- 解释:这串代码第一个局部作用域来自于
局部作用域可读取全局变量
1
2
3
4
5def spam():
print(eggs)
eggs = 42
spam()
print(eggs)代码输出:
1
242
42- 解释:首先我们调用的
spam()
中的print(eggs)
处于函数spam()
的局部作用域中,却可以输出我们在全局作用域中定义的eggs
的值,这说明局部作用域可读取全局变量。
- 解释:首先我们调用的
同名变量在不同作用域互不影响
6. global 语句
作用:在函数内修改全局变量。
示例:
1
2
3
4
5
6
7
8
9eggs = 'abc'
def spam():
global eggs
eggs = 'spam' # 修改全局变量
spam()
print(eggs)
# 代码输出为:spam
解释:用
global语句
来告诉python我们要在此函数内修改的eggs
是一个全局变量,不要用这个名字创建一个局部变量。因为eggs
在spam()
函数的顶部被声明为global
所以当eggs
被赋值为spam
时赋值发生在全局作用域的eggs上
没有创建局部eggs
变量。法则(判断全局变量或局部变量):
1.如果变量在全局作用域中使用(在所有函数之外),它就是全局变量。
2.如果在一个函数中有针对该变量的
global语句
,它就是全局变量。3.如果该变量用于函数中的赋值语句,它就是局部变量。
4.如果该变量没有用在赋值语句中,它就是全局变量。
7. 异常处理
语法:使用
try
和except
捕获异常。示例:
1
2
3
4
5
6
7def spam(divideBy):
return 42 / divideBy
print(spam(2))
print(spam(12))
print(spam(0))
print(spam(1))注意:如果运行以上代码会遇到异常,因为有一个除数为0,遇到这种情况可以使用
try
和except
语句来进行异常处理处理。例如:1
2
3
4
5
6
7
8
9
10def spam(divideBy):
try:
return 42 / divideBy
except ZeroDivisionError:
print('Error: Invalid argument.')
print(spam(2))
print(spam(12))
print(spam(0)) # 输出:Error: Invalid argument. 后返回 None
print(spam(1))
- 解释:我们使用
try
和except
语句来检测代码中可能会报错的细节,但一旦跳到except
子句的代码,就不会回到try
的子句,而会继续向下执行。