此系列文章的创作初衷是作为读书过程中的笔记,而非教程类文章。
第8章 函数
8.1 定义函数
- 定义函数的格式:
def 函数名(形参表):
函数体
如:
def greet():
print("Hello!")
def greetUser(name):
print("Hello, " + name.title() + "!")
- 在Python中,存在除#之外的注释。这样的注释称为文档字符串,用三引号括起。Python使用文档字符串生成有关函数的文档。
def greet():
"""显示简单的问候语"""
print("Hello!")
一个良好的代码编写习惯是,在每个函数头后都用文档字符串的形式说明此函数的功能,就像上面的代码一样。
8.2 传递实参
- Python必须将传递的实参与函数定义中的形参关联起来。
- 依据实参与形参的顺序关系关联实参与形参是最简单的方式,这种关联方式称为位置实参。
def printBookInfo(bookName, rate):
print("Book "+bookName+" has a rate of "+rate+".")
printBookInfo("Python Crash Course", 4)
- 关键字实参是传递给函数的名称-值对,这种方法在调用时显式地把型参与实参关联起来。
printBookInfo(rate = 4, bookName = "Python Crash Course")
- 定义函数时,可以为形参指定默认值。当函数未接受到对应的实参时,将使用形参的默认值。
def printBookInfo(bookName, rate = 4):
print("Book "+bookName+" has a rate of "+rate+".")
printBookInfo("Python Crash Course")
类似于C++,在形参表中必须先列出没有默认值的形参,再列出有默认值的形参。
- 可以混合使用位置形参、关键字实参和默认值。
8.4 传递列表
- 可以向函数传入列表,函数对此列表所做的所有修改都会永久影响此列表。
- 若要避免函数修改原始的列表,可用切片表示法传入列表的副本:
f(list[:])
8.5 传递任意数量的实参
- 在形参前加上一个星号,可以使函数能够接受任意数量的实参:
def f(*parameters):
# do something
这种定义方式会将所有传入的实参封装到一个名为parameters的元组中,即使只有一个参数时也是如此。注意,不可以增加、删除或是替换元组中的元素。
- 可以混合使用普通形参和元组形参,在声明时,需要将元组形参置于末尾。调用函数时,优先匹配位置实参和关键字实参,然后将剩余的实参收入元组中。
- 有些情况下,既不知道可能传入的实参的个数,也不知道可能传入的实参代表什么信息(换言之,不知道应该用什么作为形参名),这时候可以在形参前加上两个星号,这使得函数可以接受任意数量的关键字实参(换言之,函数可以接受任意数量的键-值对作为参数),如下例所示:
def buildProfile(first, last, **otherInfo):
profile = {}
profile["firstName"] = first
profile["lastName"] = last
for key, value in otherInfo.items():
profile[key] = value
print(profile)
buildProfile("Albert", "Einstein", field="Physics")
这种方式将所有传入的键-值对封装到字典中。
8.6 将函数存储在模块中
- 可以将函数存储在名为模块的独立文件中,再将模块导入不同的程序实现函数重用。通过将函数存储于独立的文件中,可以隐藏实现细节,将注意力集中在高层逻辑上,并且有利于提高代码的复用性。
- 在此篇笔记中,只讨论模块只包括函数的情形。
创建模块
- 模块即为扩展名为.py的文件,包含了要导入程序的代码。
导入模块
存在多种导入模块的方法:
import方式
- import方式导入一个模块,格式为:
import module_name
Python在执行此行代码时,将module_name.py中的所有函数复制到此文件中。在调用函数时,采取 模块.函数名 的方式加以调用,具体为:
module_name.function_name()
- 使用import方式导入函数,允许导入的模块中存在与本文件中函数同名的函数。由于使用了 模块.函数名 的方式加以调用,即使存在同名函数也不会造成混淆。
- 可以使用as为模块声明别名,例如:
import module_name as m
模块中的函数名并未改变,此时要调用module_name中的function_name函数,可以像下面这样编写:
m.function_name()
import-from方式
- import-from方式允许导入模块中某几个特定的函数:
from module_name import function_0, function_1, function_2
调用模块中的函数时,无需再指定模块名:
function_name()
注意:由于无法再使用模块名区分具体函数,当导入的模块与本文件中存在同名函数时,本文件中的函数将会覆盖模块中的函数(这是因为导入语句总是在一个源文件的开头部分,这也意味着模块中的函数定义将会位于本文件的函数定义之前),即便在形参表不同时也是如此。这也说明了Python不支持重载函数。
- 在import-from语句中,可以用as为函数指定别名:
from module_name import function_name as f
- 使用星号可以导入模块中的所有函数:
from module_name import *
在使用别人编写的库时,不建议采用此做法。这样做可能导致代码长度过长,更重要的是,可能导致函数之间发生覆盖。推荐的做法是只导入需要的函数,或者导入整个模块,然后用模块名指明需要调用的函数。