使用字符串给定的名称来导入模块
我们已经有了需要导入的模块名称,但是这个名称保存在一个字符串中。我们像在字符串上执行import命令。
当模块和包的名称以字符串的形式给出的时候,我们可以使用importlib.import_module()函数来手动导入这个模块:
>>> import importlib
>>> math = importlib.import_module('math')
>>> math.sin(2)
0.9092974268256817
>>> mod = importlib.import_module('urllib.request')
>>> u = mod.urlopen('http://www.python.org')
>>>
importmodule基本上和import完成的步骤相同,但是import__module会把模块对象作为结果返回给你。我们只需要将他保存在一个变量里,之后把它当作普通的模块使用就好。
如果要同包打交道,import_module()也可以用来实现相对导入。但是,需要提供一个额外的参数:
import importlib
# Same as 'from . import b'
b = importlib.import_module('.b', __package__)
使用import_module()手动导入模块的问题通常出现在以某种方式编写修改或覆盖模块的代码时候。例如,也许你正在执行某种自定义导入机制,需要通过名称来加载一个模块,通过补丁加载代码。
在旧的代码,有时你会看到用于导入的内建函数__import__()。尽管它能工作,但是importlib.import_module() 通常更容易使用。
利用import钩子从远程机器上加载模块
首先要提出来的是安全问题。本节讨论的思想如果没有一些额外的安全和认知机制的话会很糟糕。 也就是说,我们的主要目的是深入分析Python的import语句机制。 如果你理解了本节内部原理,你就能够为其他任何目的而自定义import。 有了这些,让我们继续向前走。
本节核心是设计导入语句的扩展功能。有很多种方法可以做这个, 不过为了演示的方便,我们开始先构造下面这个Python代码结构:
testcode/
spam.py
fib.py
grok/
__init__.py
blah.py
这些文件的内容并不重要,不过我们在每个文件中放入了少量的简单语句和函数, 这样你可以测试它们并查看当它们被导入时的输出。例如:
# spam.py
print("I'm spam")
def hello(name):
print('Hello%s' % name)
# fib.py
print("I'm fib")
def fib(n):
if n < 2:
return 1
else:
return fib(n-1) + fib(n-2)
# grok/__init__.py
print("I'm grok.__init__")
# grok/blah.py
print("I'm grok.blah")
这里的目的是允许这些文件作为模块被远程访问。 也许最简单的方式就是将它们发布到一个web服务器上面。在testcode目录中像下面这样运行Python:
bash % cd testcode
bash % python3 -m http.server 15000
Serving HTTP on 0.0.0.0 port 15000 ...
服务器运行起来后再启动一个单独的Python解释器。 确保你可以使用urllib访问到远程文件。例如:
>>> from urllib.request import urlopen
>>> u = urlopen('http://localhost:15000/fib.py')
>>> data = u.read().decode('utf-8')
>>> print(data)
# fib.py
print("I'm fib")
def fib(n):
if n < 2:
return 1
else:
return fib(n-1) + fib(n-2)