函数的一个主要目的就是将需要多次执行的代码放在一起。如果没有函数定
义,你可能每次都需要复制粘贴这些代码,程序看起来可能会像这样:
print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')
一般来说,我们总是希望避免复制代码,因为如果一旦决定要更新代码(比如
说,发现了一个缺陷要修复),就必须记住要修改所有复制的代码。
随着你获得更多的编程经验,常常会发现自己在为代码“消除重复”,即去除
一些重复或复制的代码。消除重复能够使程序更短、更易读、更容易更新。
1.def语句和参数
如果调用print()或len()函数,会传入一些值,放在括号之间,这里我们称为参数.也可以自己定义接收参数的函数
def hello(name):
print("hello " + name)
hello('Alice')
hello('Bob')
print(name)
执行结果:
hello Alice
hello Bob
关于变元有一件特殊的事情值得注意:保存在变元中的值,在函数返回后就丢 失了。例如前面的程序,如果你在 hello('Bob')之后添加 print(name),程序会报 NameError,因为没有名为 name 的变量。在函数调用 hello('Bob')返回后,这个变量 被销毁了,所以 print(name)会引用一个不存在的变量 name。
2.返回值和return语句
调用len()函数,传入参数'Hello',函数调用的求值为5.这是传入字符串的长度.一般来说函数调用的求值结果,称为函数的"返回值".
用def语句创建函数的时候,可以用return语句指定返回值.return语句包含以下几部分: return 关键字 函数应该返回的值或表达式 如果return语句使用了表达式,返回的结果就是表达式的求值
import 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 'Reply hazy try again'
elif answerNumber == 5:
return 'Ask again later'
elif answerNumber == 6:
return 'Concentrate and ask again'
elif answerNumber == 7:
return 'My reply is no'
elif answerNumber == 8:
return 'Outlook not so good'
elif answerNumber == 9:
return 'Very doubtful'
num = random.randint(1, 9)
fount = getAnswer(num)
print(fount)
// def randint(self, a, b):
// """Return random integer in range [a, b], including both end points.
// 返回范围为[a,b]的随机整数,包括两个端点。
// """
还可以缩写为一行
print(getAnswer(random.randint(1,9)))
表达式是值和操作符的组合.函数可以用在表达式中,因为函数的求值是他的返回值
3.None值
在 Python 中有一个值称为 None,它表示没有值。None 是 NoneType 数据类型
的唯一值(其他编程语言可能称这个值为 null、nil 或 undefined)。就像布尔值 True
和 False 一样,None 必须大写首字母 N。
如果你希望变量中存储的东西不会与一个真正的值混淆,这个没有值的值就可
能有用。有一个使用 None 的地方就是 print()的返回值。print()函数在屏幕上显示文
本,但它不需要返回任何值,这和 len()或 input()不同。但既然所有函数调用都需要
求值为一个返回值,那么 print()就返回 None。要看到这个效果,请在交互式环境中
输入以下代码。
spam = print('hello')
print(None == spam)
打印结果:
hello
True
对于所有没有 return 语句的函数定义,Python 都会在末尾加上 return
None。这类似于 while 或 for 循环隐式地以 continue 语句结尾。而且,如果使用不
带值的 return 语句(也就是只有 return 关键字本身),那么就返回 None。
4.关键字参数和print()
大多数的参数,在函数的调用位置来识别比如 random.randint(1,10)与random.randint(10,1)并不一样,第一个参数是范围的下界,第二个参数是范围的上界.random.randint(10,1)执行会报错.
但是关键字参数,是有函数调用数,加在他前面的关键字来识别的
print('hello', end=' ')
print('world')
print('cat','dog','bird','fish')
print('cat','dog','bird','fish' ,sep='|')
打印结果:
hello world
cat dog bird fish
cat|dog|bird|fish
5.局部和全局作用域
在函数内赋值的变量和变元都,处于'局部作用域',属于局部变量.在函数外赋值的变量,处于全局作用域,属于全局变量. 一个变量肯定是其中一种,不可能既是属于全局作用域又是属于局部作用域.
作用域可以看成是变量的容器,作用域销毁,保存在该作用域的变量也随之丢弃.只有一个全局作用域,在程序开始时创建.
一个函数调用,就创建了一个局部作用域.函数返回,该作用域销毁,该作用域的变量也销毁.
- 全局作用域中的代码不能使用任何局部变量;
- 但是,局部作用域可以访问全局变量;
- 一个函数的局部作用域中的代码,不能使用其他局部作用域中的变量。
- 如果在不同的作用域中,你可以用相同的名字命名不同的变量。也就是说,可以有一个名为 spam 的局部变量,和一个名为 spam 的全局变量。
局部作用域不能使用其他局部作用域内的变量
局部作用域不能使用其他局部作用域内的变量
def spam():
egg = 99
becon()
print(egg)
def becon():
egg = 0
ham = 101
spam()
打印结果
99
在程序开始运行时,spam()函数被调用,创建了一个局部作用域。局部变量eggs被赋值为 99。然后 bacon()函数被调用,创建了第二个局部作用域。多个局部作用域能同时存在。在这个新的局部作用域中,局部变量 ham 被赋值为 101。局部变量 eggs(与 spam()的局部作用域中的那个变量不同)也被创建,并赋值为 0。 当 bacon()返回时,这次调用的局部作用域被销毁。程序执行在 spam()函数中继续,打印出 eggs 的值。因为 spam()调用的局部作用域仍然存在,eggs 变量被赋值为 99。这就是程序的打印输出。要点在于,一个函数中的局部变量完全与其他函数中的局部变量分隔开来。
5.1名称相同的局部变量和全局变量
def spam():
eggs = 'spam local'
print(eggs)
def bacon():
eggs = 'bacon local'
print(eggs)
spam()
print(eggs)
eggs = 'global'
bacon()
print(eggs)
打印结果:
bacon local
spam local
bacon local
global
在这个程序中,实际上有 3 个不同的变量,但令人迷惑的是,它们都名为 eggs。
这些变量是: 名为 eggs 的变量,存在于 spam()被调用时的局部作用域; 名为 eggs 的变量,存在于 bacon()被调用时的局部作用域; 名为 eggs 的变量,存在于全局作用域。
因为这 3 个独立的变量都有相同的名字,追踪某一个时刻使用的是哪个变量,
可能比较麻烦。这就是应该避免在不同作用域内使用相同变量名的原因。
5.2 global语句
如果需要在函数内,修改变量的作用域为全局变量就可以用global语句
def spam():
global eggs
eggs = 'global'
spam()
有 4 条法则,来区分一个变量是处于局部作用域还是全局作用域:
1.如果变量在全局作用域中使用(即在所有函数之外),它就总是全局变量。
2.如果在一个函数中,有针对该变量的 global 语句,它就是全局变量。
3.否则,如果该变量用于函数中的赋值语句,它就是局部变量。
4.但是,如果该变量没有用在赋值语句中,它就是全局变量。
为了更好地理解这些法则,这里有一个例子程序。在文件编辑器中输入以下代
码:
def spam():
global eggs
eggs = 'spam' # this is the global
def bacon():
eggs = 'bacon' # this is a local
def ham():
print(eggs) # this is the global
eggs = 42 # this is the global
spam()
print(eggs)
在 spam()函数中,eggs 是全局 eggs 变量,因为在函数的开始处,有针对 eggs变量的 global 语句。在 bacon()中,eggs 是局部变量,因为在该函数中有针对它的赋值语句。在 ham()中,eggs 是全局变量,因为在这个函数中,既没有赋值语句,也没有针对它的 global 语句。如果运行输出将是:
spam
在一个函数中,如果试图在局部变量赋值之前就使用它,像下面的程序这样,Python就会报错。
def spam():
print(eggs) #报错
eggs = '123'
5.3异常处理
错误可以由 try 和 except 语句来处理。那些可能出错的语句被放在 try 子句中。如果错误发生,程序执行就转到接下来的 except 子句开始处。
def spam(divd):
try:
print(42 / divd)
except ZeroDivisionError:
print('Error invalid argument')
spam(1)
spam(3)
spam(0)
spam(4)
打印结果:
42.0
14.0
Error invalid argument
10.5