17.2 全局模块VS模块项
在库模块内容的选择上,有两种方式。一些模块被集成为了一个整体,一些则为互不相关项的集合。当将模块定义为一个整体时,通常会包含一些类或函数作为模块中面向公共的API。当将模块定义为解耦的项的集合时,每个类或函数都是独立的。
通常在导入和使用模块的方式上会有所区别,以下为3个不同的方式。
- 使用import some _ module命令。
some module.py模块文件将被执行并且结果对象被放在了名为some module的命名空间中。在使用模块中对象时,就需要使用限定名称,例如some module.this和some module.that。这种命名方式使得模块看起来是一个整体。
- 使用from some _ module import this 命令。
some _ module.py模块文件将被执行并且只有命名的对象被创建在了当前的本地命名空间中。通常,这是全局的命名空间。现在可以使用this或that而无需限定名称。这种方式使得模块看起来像是一个没有关联的对象集合。
- 使用from math import sqrt, sin , cos命令。
这种方式会为我们提供一些数学函数而无需限定名称。
- 使用from some _ module import *命令。
它的默认行为是对命令空间中的非私有名称进行导入。私有名称以起始。可以显式地限制模块中要导入的名称,通过提供_all列表来完成。它是一个字符串对象名称的列表;这些名称是由 import *语句阐述的。
可以使用all变量来对工具函数进行隐藏。它们是创建模块的一部分,但并不是要暴露给客户端API的一部分。
再次回顾21点游戏中一副牌的设计,在默认情况下,可以不必导入花色的实现细节。假设我们有一个cards.py模块,如以下代码所示。
all = ["Deck", "Shoe"]
class Suit:
etc.
suits = [ Suit("♣"), Suit("◇"), Suit("♥"), Suit("♠") ]
class Card:
etc.
def card( rank, suit ):
etc.
class Deck:
etc.
class Shoe( Deck ):
etc.
Suit和Card类的定义被保存在了all变量中。而实现的细节,card()函数和suits变量默认将不被导入。例如,当执行以下代码时。
from cards import *
这条语句将只在应用脚本中创建Deck和Shoe,与那些在all变量中显式指定的名称相一致。
当执行以下命令时,它会导入模块,但不会向全局命名空间中添加任何名称。
import cards
尽管没有导入到命名空间中,我们仍可以通过访问cards.card()方法来创建Card类。
以上每种技术都各有优劣。一个全局模块需要使用模块名称进行限定,这使得对象的源位置是明确的。从模块中导入项会缩短它们的名称,简化了编程的复杂度并增强了可读性。
