8.6.4 使用 as 给模块指定别名
代码语言:javascript复制你还可以给模块指定别名。通过给模块指定简短的别名(如给模块pizza指定别名p),让你 能够更轻松地调用模块中的函数。相比于pizza.make_pizza(),p.make_pizza()更为简洁:
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
代码语言:javascript复制上述import语句给模块pizza指定了别名p,但该模块中所有函数的名称都没变。调用函数 make_pizza()时,可编写代码p.make_pizza()而不是pizza.make_pizza(),这样不仅能使代码更简 洁,还可以让你不再关注模块名,而专注于描述性的函数名。这些函数名明确地指出了函数的功 能,对理解代码而言,它们比模块名更重要。 给模块指定别名的通用语法如下:
import module_name as mn
8.6.5 导入模块中的所有函数
代码语言:javascript复制使用星号(*)运算符可让Python导入模块中的所有函数
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
代码语言:javascript复制import语句中的星号让Python将模块pizza中的每个函数都复制到这个程序文件中。由于导入 了每个函数,可通过名称来调用每个函数,而无需使用句点表示法。然而,使用并非自己编写的 大型模块时,最好不要采用这种导入方法:如果模块中有函数的名称与你的项目中使用的名称相 同,可能导致意想不到的结果:Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。 最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。这能 让代码更清晰,更容易阅读和理解。这里之所以介绍这种导入方法,只是想让你在阅读别人编写 的代码时,如果遇到类似于下面的import语句,能够理解它们
from module_name import *
8.7 函数编写指南
代码语言:javascript复制编写函数时,需要牢记几个细节。应给函数指定描述性名称,且只在其中使用小写字母和下 划线。描述性名称可帮助你和别人明白代码想要做什么。给模块命名时也应遵循上述约定。 每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字 符串格式。文档良好的函数让其他程序员只需阅读文档字符串中的描述就能够使用它:他们完全 可以相信代码如描述的那样运行;只要知道函数的名称、需要的实参以及返回值的类型,就能在 自己的程序中使用它。 给形参指定默认值时,等号两边不要有空格:
def function_name(parameter_0, parameter_1='default value')
代码语言:javascript复制对于函数调用中的关键字实参,也应遵循这种约定:
function_name(value_0, parameter_1='value')
代码语言:javascript复制PEP 8(https://www.python.org/dev/peps/pep-0008/)建议代码行的长度不要超过79字符,这样 只要编辑器窗口适中,就能看到整行代码。如果形参很多,导致函数定义的长度超过了79字符, 可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一 层的函数体区分开来。 大多数编辑器都会自动对齐后续参数列表行,使其缩进程度与你给第一个参数列表行指定的 缩进程度相同:
def function_name(
parameter_0, parameter_1, parameter_2,
parameter_3, parameter_4, parameter_5):
function body...
如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一 个函数在什么地方结束,下一个函数从什么地方开始。 所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整 个程序。
8.8 小结
在本章中,你学习了:如何编写函数,以及如何传递实参,让函数能够访问完成其工作所需 的信息;如何使用位置实参和关键字实参,以及如何接受任意数量的实参;显示输出的函数和返 回值的函数;如何将函数同列表、字典、if语句和while循环结合起来使用。你还知道了如何将 函数存储在被称为模块的独立文件中,让程序文件更简单、更易于理解。最后,你学习了函数编 写指南,遵循这些指南可让程序始终结构良好,并对你和其他人来说易于阅读。 程序员的目标之一是,编写简单的代码来完成任务,而函数有助于你实现这样的目标。它们 让你编写好代码块并确定其能够正确运行后,就可置之不理。确定函数能够正确地完成其工作后, 你就可以接着投身于下一个编码任务。 函数让你编写代码一次后,想重用它们多少次就重用多少次。需要运行函数中的代码时,只 需编写一行函数调用代码,就可让函数完成其工作。需要修改函数的行为时,只需修改一个代码 块,而所做的修改将影响调用这个函数的每个地方。 使用函数让程序更容易阅读,而良好的函数名概述了程序各个部分的作用。相对于阅读一系 列的代码块,阅读一系列函数调用让你能够更快地明白程序的作用。 函数还让代码更容易测试和调试。如果程序使用一系列的函数来完成其任务,而其中的每个 函数都完成一项具体的工作,测试和维护起来将容易得多:你可编写分别调用每个函数的程序, 并测试每个函数是否在它可能遇到的各种情形下都能正确地运行。经过这样的测试后你就能信心 满满,深信你每次调用这些函数时,它们都将正确地运行。 在 第9章,你将学习编写类。类将函数和数据整洁地封装起来,让你能够灵活而高效地使用 它们。
第9章
类
9.1 创建和使用类
使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类Dog——它表示的不是特 定的小狗,而是任何小狗。对于大多数宠物狗,我们都知道些什么呢?它们都有名字和年龄;我 们还知道,大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息(名字和年龄)和 两种行为(蹲下和打滚),我们的Dog类将包含它们。这个类让Python知道如何创建表示小狗的对 象。编写这个类后,我们将使用它来创建表示特定小狗的实例。
9.1.1 创建 Dog 类
代码语言:javascript复制根据Dog类创建的每个实例都将存储名字和年龄。我们赋予了每条小狗蹲下(sit())和打滚 (roll_over())的能力: dog.py
1 class Dog():
2 """一次模拟小狗的简单尝试"""
3 def __init__(self, name, age):
"""初始化属性name和age"""
4 self.name = name
self.age = age
5 def sit(self):
"""模拟小狗被命令时蹲下"""
print(self.name.title() " is now sitting.")
def roll_over(self):
"""模拟小狗被命令时打滚"""
print(self.name.title() " rolled over!")
这里需要注意的地方很多,但你也不用担心,本章充斥着这样的结构,你有大把的机会熟悉 它。在1处,我们定义了一个名为Dog的类。根据约定,在Python中,首字母大写的名称指的是类。 这个类定义中的括号是空的,因为我们要从空白创建这个类。在2处,我们编写了一个文档字符 串,对这个类的功能作了描述。 1. 方法__init__() 类中的函数称为方法;你前面学到的有关函数的一切都适用于方法,就目前而言,唯一重要 的差别是调用方法的方式。3处的方法__init__()是一个特殊的方法,每当你根据Dog类创建新实 例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约 定,旨在避免Python默认方法与普通方法发生名称冲突。 我们将方法__init__()定义成了包含三个形参:self、name和age。在这个方法的定义中,形 参self必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self呢?因为 Python调用这个__init__()方法来创建Dog实例时,将自动传入实参self。每个与类相关联的方法 调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。 我们创建Dog实例时,Python将调用Dog类的方法__init__()。我们将通过实参向Dog()传递名字和 年龄;self会自动传递,因此我们不需要传递它。每当我们根据Dog类创建实例时,都只需给最 后两个形参(name和age)提供值。 4处定义的两个变量都有前缀self。以self为前缀的变量都可供类中的所有方法使用,我们 还可以通过类的任何实例来访问这些变量。self.name = name获取存储在形参name中的值,并将 其存储到变量name中,然后该变量被关联到当前创建的实例。self.age = age的作用与此类似。 像这样可通过实例访问的变量称为属性。 Dog类还定义了另外两个方法:sit()和roll_over()(见5)。由于这些方法不需要额外的信 息,如名字或年龄,因此它们只有一个形参self。我们后面将创建的实例能够访问这些方法,换 句话说,它们都会蹲下和打滚。当前,sit()和roll_over()所做的有限,它们只是打印一条消息, 指出小狗正蹲下或打滚。但可以扩展这些方法以模拟实际情况:如果这个类包含在一个计算机游 戏中,这些方法将包含创建小狗蹲下和打滚动画效果的代码。如果这个类是用于控制机器狗的, 这些方法将引导机器狗做出蹲下和打滚的动作。
2. 在Python 2.7中创建类
在Python 2.7中创建类时,需要做细微的修改——在括号内包含单词object:
代码语言:javascript复制class ClassName(object):
--snip--
代码语言:javascript复制这让Python 2.7类的行为更像Python 3类,从而简化了你的工作。 在Python 2.7中定义Dog类时,代码类似于下面这样:
class Dog(object):
--snip--
9.1.2 根据类创建实例
代码语言:javascript复制可将类视为有关如何创建实例的说明。Dog类是一系列说明,让Python知道如何创建表示特 定小狗的实例。 下面来创建一个表示特定小狗的实例:
class Dog():
--snip--
1 my_dog = Dog('willie', 6)
2 print("My dog's name is " my_dog.name.title() ".")
3 print("My dog is " str(my_dog.age) " years old.")
代码语言:javascript复制这里使用的是前一个示例中编写的Dog类。在1处,我们让Python创建一条名字为'willie'、 年龄为6的小狗。遇到这行代码时,Python使用实参'willie'和6调用Dog类中的方法__init__()。 方法__init__()创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name和age。方法 __init__()并未显式地包含return语句,但Python自动返回一个表示这条小狗的实例。我们将这 个实例存储在变量my_dog中。在这里,命名约定很有用:我们通常可以认为首字母大写的名称(如 Dog)指的是类,而小写的名称(如my_dog)指的是根据类创建的实例。 1. 访问属性 要访问实例的属性,可使用句点表示法。在2处,我们编写了如下代码来访问my_dog的属性name的值:
my_dog.name
代码语言:javascript复制句点表示法在Python中很常用,这种语法演示了Python如何获悉属性的值。在这里,Python 先找到实例my_dog,再查找与这个实例相关联的属性name。在Dog类中引用这个属性时,使用的 是self.name。在3处,我们使用同样的方法来获取属性age的值。在前面的第1条print语句中, my_dog.name.title()将my_dog的属性name的值'willie'改为首字母大写的;在第2条print语句中, str(my_dog.age)将my_dog的属性age的值6转换为字符串。 输出是有关my_dog的摘要:
My dog's name is Willie.
My dog is 6 years old.
代码语言:javascript复制2. 调用方法 根据Dog类创建实例后,就可以使用句点表示法来调用Dog类中定义的任何方法。下面来让小 狗蹲下和打滚:
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
代码语言:javascript复制要调用方法,可指定实例的名称(这里是my_dog)和要调用的方法,并用句点分隔它们。遇 到代码my_dog.sit()时,Python在类Dog中查找方法sit()并运行其代码。Python以同样的方式解读 代码my_dog.roll_over()。 Willie按我们的命令做了:
Willie is now sitting.
Willie rolled over!
代码语言:javascript复制这种语法很有用。如果给属性和方法指定了合适的描述性名称,如name、age、sit()和 roll_over(),即便是从未见过的代码块,我们也能够轻松地推断出它是做什么的。 3. 创建多个实例 可按需求根据类创建任意数量的实例。下面再创建一个名为your_dog的实例
class Dog():
--snip--
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
print("My dog's name is " my_dog.name.title() ".")
print("My dog is " str(my_dog.age) " years old.")
my_dog.sit()
print("nYour dog's name is " your_dog.name.title() ".")
print("Your dog is " str(your_dog.age) " years old.")
your_dog.sit()
代码语言:javascript复制在这个实例中,我们创建了两条小狗,它们分别名为Willie和Lucy。每条小狗都是一个独立 的实例,有自己的一组属性,能够执行相同的操作:
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.
Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.
就算我们给第二条小狗指定同样的名字和年龄,Python依然会根据Dog类创建另一个实例。 你可按需求根据一个类创建任意数量的实例,条件是将每个实例都存储在不同的变量中,或占用 列表或字典的不同位置。