要使用模块和库,需要先导入。
**Python之禅**
```
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```
导入系统是相当复杂的,不过你可能已经了解了一些基本知识。这里会介绍一些关于这一子系统的内部机理。
`sys`模块包含许多关于Python导入系统的信息。首先,当前可导入的模块列表可以通过`sys.moudle`变量获取。它是一个字典,其中键(key)是模块名字,对应的值(value)是模块对象。
```
>>> sys.modules['os']
<module 'os' from '/usr/lib/python2.7/os.pyc'>
```
许多模块是内置的,这些内置的模块在`sys.builtin_module_names`中列出。内置的模块可以根据传入Python构建系统的编译选项的不同而变化。
导入模块时,Python会依赖一个路径列表。这个列表存储在`sys.path`变量中,并且告诉Python去哪里搜索要加载的模块。可以在代码中修改这个列表,根据需要添加或删除路径,也可以通过编写Python代码直接修改环境变量`PYTHONPATH`。下面的方法几乎是相等的[①](#anchor21)。
```
>>> import sys
>>> sys.path.append('/foo/bar')
$ PYTHONPATH=/foo/bar python
>>> import sys
>>> '/foo/bar' in sys.path
True
```
在`sys.path`中的顺序很重要,因为需要遍历这个列表来寻找请求的模块。
也可以通过自定义的导入器(importer)对导入机制进行扩展。Hy[②](#anchor22)正是利用这种技术告诉Python如何导入其他非标准的`.py`或者`.pyc`文件的。
顾名思义,导入钩子机制是由PEP 302(<http://www.python.org/dev/peps/pep-0302/>)定义的[③](#anchor23)。它允许扩展标准的导入机制,并对其进行预处理,也可以通过追加一个工厂类到`sys.path_hooks`来添加自定义的模块查找器(finder)。
模块查找器对象必须有一个返回加载器对象的`find_module(fullname, path=None)`方法,这个加载器对象必须包含一个负责从源文件中加载模块的`load_module(fullname)`方法。
为了进一步说明,下面给出了Hy利用自定义的导入器导入`.hy`而不是`.py`结尾的源文件的方法,见示例2.1。
**示例2.1 Hy模块导入器**
```
class MetaImporter(object):
def find_on_path(self, fullname):
fls = ["%s/__init__.hy", "%s.hy"]
dirpath = "/".join(fullname.split("."))
for pth in sys.path:
pth = os.path.abspath(pth)
for fp in fls:
composed_path = fp % ("%s/%s" % (pth, dirpath))
if os.path.exists(composed_path):
return composed_path
def find_module(self, fullname, path=None):
path = self.find_on_path(fullname)
if path:
return MetaLoader(path)
sys.meta_path.append(MetaImporter())
```
一旦路径被确定是有效的且指向了一个模块,就会返回一个`MetaLoader`对象。
**Hy模块加载器**
```
class MetaLoader(object):
def __init__(self, path):
self.path = path
def is_package(self, fullname):
dirpath = "/".join(fullname.split("."))
for pth in sys.path:
pth = os.path.abspath(pth)
composed_path = "%s/%s/__init__.hy" % (pth, dirpath)
if os.path.exists(composed_path):
return True
return False
def load_module(self, fullname):
if fullname in sys.modules:
return sys.modules[fullname]
if not self.path:
return
sys.modules[fullname] = None
mod = import_file_to_module(fullname, self.path) ❶
ispkg = self.is_package(fullname)
mod.__file__ = self.path
mod.__loader__ = self
mod.__name__ = fullname
if ispkg:
mod.__path__ = []
mod.__package__ = fullname
else:
mod.__package__ = fullname.rpartition('.')[0]
sys.modules[fullname] = mod
return mod
```
❶ `import_file_to_module`读取一个Hy源文件,将其编译成Python代码,并返回一个Python模块对象。
`uprefix`模块(<https://pypi.python.org/pypi/uprefix>)是这个功能起作用的另一个好的例子。Python 3.0到3.2并没有像Python 2中用来表示Unicode字符串的`u`前缀[④](#anchor24),这个模块通过在编译前删除字符串的前缀`u`来确保在2.x和3.x之间的兼容性。
- - - - - -
[①](#ac21) 说“几乎”是因为路径并不会被放在列表的同一级上,尽管根据你的使用情况它可能并不重要。
[②](#ac22) Hy是Python上的Lisp实现,会在11.2节介绍。
[③](#ac23) 自Python 2.3版本实现的新导入钩子机制。
[④](#ac24) 它在Python 3.3中又被加了回来。
- 内容提要
- 中文版序
- 前言
- 第1章 项目开始
- 1.1 Python版本
- 1.2 项目布局
- 1.3 版本编号
- 1.4 编码风格与自动检查
- 1.5 Joshua Harlow访谈
- 第2章 模块和库
- 2.1 导入系统
- 2.2 标准库
- 2.3 外部库
- 2.4 框架
- 2.5 Doug Hellmann访谈
- 第3章 管理API变化
- Christophe de Vienne访谈
- 第4章 时区陷阱
- 第5章 文档
- 5.1 Sphinx和reST入门
- 5.2 Sphinx模块
- 5.3 扩展Sphinx
- 第6章 分发
- 6.1 简史
- 6.2 使用pbr打包
- 6.3 Wheel格式
- 6.4 包的安装
- 6.5 和世界分享你的成果
- 6.6 Nick Coghlan访谈
- 6.7 入口点
- 6.7.1 可视化的入口点
- 6.7.2 使用控制台脚本
- 6.7.3 使用插件和驱动程序
- 第7章 虚拟环境
- 第8章 单元测试
- 8.1 基础知识
- 8.2 fixture
- 8.3 模拟(mocking)
- 8.4 场景测试
- 8.5 测试序列与并行
- 8.6 测试覆盖
- 8.7 使用虚拟环境和tox
- 8.8 测试策略
- 8.9 Robert Collins访谈
- 第9章 方法和装饰器
- 9.1 创建装饰器
- 9.2 Python中方法的运行机制
- 9.3 静态方法
- 9.4 类方法
- 9.5 抽象方法
- 9.6 混合使用静态方法、类方法和抽象方法
- 9.7 关于super的真相
- 第10章 函数式编程
- 10.1 生成器
- 10.2 列表推导
- 10.3 函数式函数的函数化
- 第11章 抽象语法树
- 11.1 用抽象语法树检查来扩展flake8
- 11.2 Hy
- 11.3 Paul Tagliamonte访谈
- 第12章 性能与优化
- 12.1 数据结构
- 12.2 性能分析
- 12.3 有序列表和二分查找
- 12.4 namedtuple和slots
- 12.5 memoization
- 12.6 PyPy
- 12.7 通过缓冲区协议实现零复制
- 12.8 Victor Stinner访谈
- 第13章 扩展与架构
- 13.1 多线程的注意事项
- 13.2 多进程与多线程
- 13.3 异步和事件驱动架构
- 13.4 面向服务架构
- 第14章 RDBMS和ORM
- 14.1 用Flask和PostgreSQL流化数据
- 14.2 Dimitri Fontaine访谈
- 第15章 Python 3支持策略
- 15.1 语言和标准库
- 15.2 外部库
- 15.3 使用six
- 第16章 少即是多
- 16.1 单分发器
- 16.2 上下文管理器
- 第17章 延伸阅读
- 版权信息
- 版权声明
- 欢迎来到异步社区!
- 异步社区的来历
- 社区里都有什么?
- 购买图书
- 下载资源
- 与作译者互动
- 灵活优惠的购书
- 纸电图书组合购买
- 社区里还可以做什么?
- 提交勘误
- 写作
- 会议活动早知道
- 加入异步