第一章我们学习了print()、input()、len()这样的python内建函数,其实我们也可以自己编写函数。这些函数就像一些有特定功能的小版块,我们可以在想要的时候随时调用他们。
def语句和参数
先看一个栗子
def hello(name):
print('Hello '+name)
hello('Doraemon')
hello('Nobita')
运行程序,输出如下结果:
Hello Doraemon
Hello Nobita
解释:在这个程序的hello()函数定义中,有一个名为name的变元。“变元”是一个变量,当函数被调用时,参数就存放在其中。需注意的是,==保存在变元中的值,在函数返回后就丢失了。==比如在hello(‘Nobita’)之后添加print(name),程序会报NameError,因为没有名为name的变量。在函数调用hello(‘Nobita’)之后,这个变量就被销毁了。
返回值和return语句
一般来说,函数调用求值的结果,成为函数的“返回值”。用def语句创建函数时,可以用return语句制定应该返回什么值。return语句包含以下部分:
- return关键字
- 函数应该返回的值或表达式
返回值可以作为参数传递给另一个函数调用。
None值
None是NoneType数据类型的唯一值。如果你希望变量中存储的东西不会与一个真正的值混淆,这个没有值的值就可能有用。
关键字参数和print()
“关键字参数”是由函数调用时加在它们前面的关键字来识别的。关键字参数通常用于可选变元。例如,print()函数有可选变元end和sep,分别指定在参数末尾打印什么,以及在参数之间打印什么来隔开他们。
print(,end=’’)
如果运行以下程序:
print('Hello')
print('Doraemon')
输出将会是:
Hello
Doraemon
这两个字符串出现在独立的两行中 ,因为print()函数自动在传入的字符串末尾添加了换行符。但是可以设置end关键字参数,将它变成另一个字符串。例如:
print('Hello',end='')
print('Doraemon')
输出就会像这样:
HelloDoraemon
'Hello’后面不再打印换行,而是打印了一个空字符串。
print(,sep=’’)
类似地,如果向print()传入多个字符串值,该函数就会自动用一个空格分隔他们。例如:
print('Nobita','Doraemon')
输出将会是:
Nobita Doraemon
你可以传入sep关键字参数,替换掉默认的分隔字符串。如:
print('Nobita','Doraemon',sep=',')
输出将会是:
Nobita,Doraemon
局部和全局作用域
在被调用函数内赋值的变元和变量,处于该函数的局部作用域。在所有函数之外赋值的变量,属于全局作用域。
一个函数被调用时,就创建了一个局部作用域。在这个函数赋值的所有变量,存在于该局部作用域内。该函数返回时,这个局部作用域就被销毁了,这些变量就丢失了。作用域很重要,理由如下:
- 全局作用域中的代码不能使用任何局部变量
def spam():
eggs = 520
spam()
print(eggs)
如果运行这个程序,python将报错,因为eggs为局部变量,在spam()函数返回时,局部作用域就销毁了,变量就丢失了,所以程序报错。
- 但是局部作用域可以访问全局变量
def spam():
print(eggs)
eggs = 42
spam()
print(eggs)
运行程序输出的结果为42
- 一个函数的局部作用域中的代码,不能使用其他局部作用域中的变量。
def spam():
eggs = 99
bacon()#eggs在bacon被调用时销毁
print(eggs)
def bacon():
ham = 101
eggs = 0
spam()
运行程序输出的结果为99。一个函数中的局部变量完全与其他函数中的局部变量分隔开来。
- 如果在不同的局部作用域中,你可以用相同的名字命名不同的变量。也就是说,可以有一个名为spam的局部变量,和一个名为spam的全局变量。
在python中让局部变量和全局变量同名是完全合法的,但是为避免麻烦,尽量避免。
global语句
如果需要在一个函数内修改全局变量,就是用global语句。
def spam():
global eggs
eggs = 'spam'
print(eggs)
eggs = 'global'
spam()
print(eggs)
运行程序输出的结果为spam。
有四条法则,来区分一个变量是处于局部作用域还是全局作用域:
1.如果变量在全局作用域中使用(即所有函数之外),他就总是局部变量。
2.如果在一个函数中,有针对变量的global语句,他就是全局变量。
3.否则,如果该变量用于函数中的赋值语句,他就是局部变量。
4.但是,如果该变量没有用在赋值语句中 ,他就是全局变量。
为方便理解,可以使用以下代码:
def spam():
global eggs
eggs = 'spam' #全局变量
def bacon():
eggs = 'bacon' #局部变量
def ham():
print(eggs) #全局变量
eggs = 42 #全局变量
spam()
print(eggs)
异常处理
错误可以由try和except语句来处理。那些可能出错的语句放在try子句中,如果错误发生,程序执行就转到接下来的except子句开始处。在运行那些代码后,执行照常继续。
def spam(divideBy):
try:
return 42 / divideBy
except ZeroDivisionError:
print('Error:Invalid arrgument.')
print(spam(2))
print(spam(12))
print(spam(0))
print(spam(1))
程序运行结果如下:
21.0
3.5
Error:Invalid arrgument.
None
42.0
看以下程序,它的做法不一样,将spam()调用放在语句块中:
def spam(divideBy):
return 42 / divideBy
try:
print(spam(2))
print(spam(12))
print(spam(0))
print(spam(1))
except ZeroDivisionError:
print('Error:Invalid arrgument.')
程序运行结果如下:
21.0
3.5
Error:Invalid arrgument.
print(spam(1))从未被执行是因为,==一旦执行跳到except子句的代码,就不会回到try子句,它会继续照常向下执行。