翻译:《实用的Python编程》03_02_More_functions

尽管函数在早先时候介绍了,但有关函数在更深层次上是如何工作的细节却很少提供。本节旨在填补这些空白,并讨论函数调用约定,作用域规则等问题。

调用函数

考虑以下函数:

def read_prices(filename, debug): ...

可以使用位置参数调用该函数:

prices = read_prices('prices.csv', True)

或者,可以使用关键字参数调用该函数:

prices = read_prices(filename='prices.csv', debug=True) 默认参数

有时候,你希望参数是可选的,如果是这样,请在函数定义中分配一个默认值。

def read_prices(filename, debug=False): ...

如果分配了默认值,则参数在函数调用中是可选的。

d = read_prices('prices.csv') e = read_prices('prices.dat', True)

注意:带有默认值的参数(译注:即关键字参数)必须出现在参数列表的末尾(所有非可选参数都放在最前面)

首选关键字参数作为可选参数

比较以下两种不同的调用风格:

parse_data(data, False, True) # ????? parse_data(data, ignore_errors=True) parse_data(data, debug=True) parse_data(data, debug=True, ignore_errors=True)

在大部分情况下,关键字参数提高了代码的简洁性——特别是对于用作标志的参数,或者与可选特性相关的参数。

设计最佳实践

始终为函数参数指定简短但有意义的名称。

使用函数的人可能想要使用关键字调用风格。

d = read_prices('prices.csv', debug=True)

Python 开发工具将会在帮助功能或者帮助文档中显示这些名称。

返回值

return 语句返回一个值:

def square(x): return x * x

如果没有给出返回值或者 return 语句缺失,那么返回 None:

def bar(x): statements return a = bar(4) # a = None # OR def foo(x): statements # No `return` b = foo(4) # b = None 多个返回值

函数只能返回一个值。但是,通过将返回值放到元组中,函数可以返回多个值:

def divide(a,b): q = a // b # Quotient r = a % b # Remainder return q, r # Return a tuple

用例:

x, y = divide(37,5) # x = 7, y = 2 x = divide(37, 5) # x = (7, 2) 变量作用域

程序给变量赋值:

x = value # Global variable def foo(): y = value # Local variable

变量赋值发生在函数的内部和外部。定义在函数外部的变量是“全局的”。定义在函数内部的变量是“局部的”。

局部变量

在函数内部赋值的变量是私有的。

def read_portfolio(filename): portfolio = [] for line in open(filename): fields = line.split(',') s = (fields[0], int(fields[1]), float(fields[2])) portfolio.append(s) return portfolio

在此示例中,filename, portfolio, line, fields 和 s 是局部变量。在函数调用之后,这些变量将不会保留或者不可访问。

>>> stocks = read_portfolio('portfolio.csv') >>> fields Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'fields' is not defined >>>

局部变量也不能与其它地方的变量冲突。

全局变量

函数可以自由地访问定义在同一文件中的全局变量值。

name = 'Dave' def greeting(): print('Hello', name) # Using `name` global variable

但是,函数不能修改全局变量:

name = 'Dave' def spam(): name = 'Guido' spam() print(name) # prints 'Dave'

切记:函数中的所有赋值都是局部的

修改全局变量

如果必须修改全局变量,请像下面这样声明它:

name = 'Dave' def spam(): global name name = 'Guido' # Changes the global name above

全局声明必须在使用之前出现,并且相应的变量必须与该函数处在同一文件中。看上面这个函数,要知道这是一种糟糕的形式。事实上,如果可以的话,尽量避免使用 global 。如果需要一个函数来修改函数外部的某种状态,最好是使用类来代替(稍后详细介绍)。

参数传递

当调用一个函数的时候,参数变量的传递是引用传递。不拷贝值(参见2.7 节)。如果传递了可变数据类型(如列表,字典),它们可以被原地修改。

def foo(items): items.append(42) # Modifies the input object a = [1, 2, 3] foo(a) print(a) # [1, 2, 3, 42]

关键点:函数不接收输入参数的拷贝。

重新赋值与修改

确保了解修改值与给变量名重新赋值的细微差别。

def foo(items): items.append(42) # Modifies the input object a = [1, 2, 3] foo(a) print(a) # [1, 2, 3, 42] # VS def bar(items): items = [4,5,6] # Changes local `items` variable to point to a different object b = [1, 2, 3] bar(b) print(b) # [1, 2, 3]

提醒:变量赋值永远不会重写内存。名称只是被绑定到了新的值上面

练习

本组练习实现的内容可能是本课程最强大的和最难的。有很多步骤,并且过去练习中的许多概念被一次性整合在一起。虽然最后的题解只有大约 25 行的代码,但要花点时间,确保你理解每一个部分。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxpxj.html