【python 让繁琐工作自动化】第3章 函数


Automate the Boring Stuff with Python: Practical Programming for Total Beginners (2nd Edition)
Written by Al Sweigart.
The second edition is available on 2019.10.29


函数的一个主要目的就是将需要多次执行的代码放在一起。
一般来说,我们总是希望避免复制代码,因为如果一旦决定要更新代码(比如说,发现了一个缺陷要修复),就必须记住要修改所有复制的代码。
随着编程经验的增加,常常会发现自己在消除重复(deduplicating)代码,即去除一些重复或复制的代码。消除重复能够使程序更短、更易读、更容易更新。

3.1 带参数的 def 语句

def hello(name):
	print('Hello ' + name)

hello('Alice')

3.2 返回值和 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'
		
# random.randint(1, 9)求值为 1到 9之间的随机整数(包括 1和 9)
fortune = getAnswer(random.randint(1, 9)) 
print(fortune)

3.3 None 值

在 Python 中有一个名为 None 的值,它表示没有值。NoneNoneType 数据类型的惟一值。
在后台,Python 在任何没有 return 语句的函数定义的末尾添加 return None
此外,如果使用没有值的 return 语句 (即仅返回关键字本身),则返回 None 值。

3.4 关键字参数和 print()

关键字参数 (keyword arguments) 由函数调用中加在它们前面的关键字来识别的。关键字参数通常用于可选参数。
例如,print() 函数有两个可选参数 endsep
end 指定应该在其参数末尾打印什么;
sep 指定参数之间打印什么来将它们隔开。

print('Hello', end='')
print('World')

print('cats', 'dogs', 'mice')
print('cats', 'dogs', 'mice', sep=',')

上面代码运行结果为:

HelloWorld
cats dogs mice
cats,dogs,mice

3.5 局部和全局作用域

一个变量要么是全局变量,要么是局部变量,不能既是局部的又是全局的。
如果不同的变量位于不同的作用域中,则可以对它们使用相同的名称。也就是说,可以有一个名为 spam 的局部变量和一个名为 spam 的全局变量。

def spam():
	eggs = 'spam local'
	print(eggs) # prints 'spam local'
def bacon():
	eggs = 'bacon local'
	print(eggs) # prints 'bacon local'
	spam()
	print(eggs) # prints 'bacon local'

eggs = 'global'
bacon()
print(eggs) # prints 'global'

上面代码运行结果如下:

bacon local
spam local
bacon local
global

3.6 global 语句

如果想要在函数中修改存储在全局变量中的值,则必须对该变量使用 global 语句。

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
print(eggs) # 打印 42
spam()
print(eggs) # 打印 ‘spam’

在一个函数中,如果试图在局部变量赋值之前就使用它,像下面的程序这样,Python 就会报错。

def spam():
	print(eggs) # ERROR!
	eggs = 'spam local'

eggs = 'global'
spam()

上面代码运行后报错信息为:

UnboundLocalError: local variable 'eggs' referenced before assignment

发生这个错误是因为,Python 看到 spam() 函数中有针对 eggs 的赋值语句,因此认为 eggs 变量是局部变量。但是因为 print(eggs) 的执行在eggs 赋值之前,局部变量 eggs 并不存在。

函数作为“黑盒”
通常,需要了解的关于函数的所有信息就是它的输入 (参数) 和输出值,不必总是为函数代码的实际工作方式而烦恼。当以这种高级方式思考函数时,通常会说将函数视为“黑盒”。
这个思想是现代编程的基础。不需要了解这些函数是如何工作的,就可以使用它们。

3.7 异常处理

def spam(divideBy):
    return 42 / divideBy

print(spam(12))
print(spam(0))
print(spam(1))

代码运行结果包含:

ZeroDivisionError: integer division or modulo by zero

错误可以由 tryexcept 语句来处理。
注意,在函数调用中的 try 语句块中,发生的所有错误都会被捕捉。

def spam(divideBy):
    try:
        return 42 / divideBy
    except ZeroDivisionError:
        print('Error: Invalid argument.')

print(spam(12))
print(spam(0))
print(spam(1))

上面代码的运行结果为:

3.5
Error: Invalid argument.
None
42.0
def spam(divideBy):
    return 42 / divideBy

try:
    print(spam(12))
    print(spam(0))
    print(spam(1))
except ZeroDivisionError:
    print('Error: Invalid argument.')

上面代码的运行结果为:

3.5
Error: Invalid argument.

print(spam(1)) 未被执行是因为,一旦执行跳到 except 子句的代码,就不会回到 try 子句。它会继续照常向下执行。

3.8 一个小程序:之字形(Zigzag)

# zigzag.py
import time, sys
indent = 0 # How many spaces to indent.
indentIncreasing = True # Whether the indentation is increasing or not.

try:
    while True: # The main program loop.
        print(' ' * indent, end='')
        print('********')
        time.sleep(0.1) # Pause for 1/10 of a second.

        if indentIncreasing:
            # Increase the number of spaces:
            indent = indent + 1
            if indent == 20:
                # Change direction:
                indentIncreasing = False

        else:
            # Decrease the number of spaces:
            indent = indent - 1
            if indent == 0:
                # Change direction:
                indentIncreasing = True
except KeyboardInterrupt:
    sys.exit()

该程序将创建来回的之字形图案,直到用户通过按Mu编辑器的“停止”按钮或按CTRL-C停止它为止。

3.9 习题

1.为什么在程序中加入函数会有好处?
解: 函数是将代码逻辑分组的主要方式。因为函数中的变量存在于它们自己的局部作用域内,所以一个函数中的代码不能直接影响其他函数中变量的值。这限制了哪些代码才能改变变量的值,对调试代码很有帮助。
函数是很好的工具,帮助你组织代码。可以认为他们是黑盒。它们以参数的形式接收输入,以返回值的形式产生输出。它们内部的代码不会影响其他函数中的变量。

3.10 实践项目

Collatz 序列

编写一个名为 collatz() 的函数,该函数有一个名为 number 的参数。如果 number 是偶数,那么 collatz() 应该打印 number // 2,并返回该值。如果 number 是奇数,那么 collatz() 应该打印并返回 3 * number + 1
然后编写一个程序,让用户输入一个整数,并一直对这个数字调用 collatz(),直到函数返回值1。(令人惊奇的是,这个序列实际上适用于任何整数,使用这个序列,迟早会得到 1!甚至数学家也不确定为什么。你的程序正在研究所谓的 Collatz 序列 (Collatz sequence),有时也被称为“最简单的不可能的数学问题”。
记住要使用 int() 函数将 input() 的返回值转换为整数,否则,它将是一个字符串值。
提示:如果 number % 2 == 0,则整数为偶数;如果 number % 2 == 1,则为奇数。
这个程序的输出可能是这样的:

Enter number:
3
10
5
16
8
4
2
1
def collatz(number):
	if number % 2 == 0:
		temp = number // 2
	else:
		temp = 3 * number + 1
	print(temp)
	return temp

print("Enter number:")
num = int(input()) # 在 Python2 中使用 num = input() 没出现错误
while num != 1:
	num = collatz(num)
输入验证

tryexcept 语句添加到前面的项目中,以检测用户是否输入了非整数字符串。通常,如果 int() 函数传递了一个非整数字符串,就会引发一个 ValueError 错误,如 int('puppy')。在 except 子句中,向用户打印一条消息,说明他们必须输入整数。

def collatz(number):
	if number % 2 == 0:
		temp = number // 2
	else:
		temp = 3 * number + 1
	print(temp)
	return temp
	
try:
	print("Enter number:")
	num = int(input())
	while num != 1:
		num = collatz(num)
except ValueError:	# Python2 出现 NameError。也可以直接使用 except:
	print("Please input an integer!")

【python 让繁琐工作自动化】目录
学习网站:https://automatetheboringstuff.com/2e/chapter3/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值