Skip to content

Commit f225bbc

Browse files
committed
10.12小节完成
1 parent f4b4cfa commit f225bbc

File tree

1 file changed

+26
-53
lines changed

1 file changed

+26
-53
lines changed

source/c10/p12_patching_modules_on_import.rst

+26-53
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55
----------
66
问题
77
----------
8-
You want to patch or apply decorators to functions in an existing module. However, you
9-
only want to do it if the module actually gets imported and used elsewhere.
8+
你想给某个已存在模块中的函数添加装饰器。
9+
不过,前提是这个模块已经被导入并且被使用过。
1010

1111
----------
1212
解决方案
1313
----------
14-
The essential problem here is that you would like to carry out actions in response to a
15-
module being loaded. Perhaps you want to trigger some kind of callback function that
16-
would notify you when a module was loaded.
14+
这里问题的本质就是你想在模块被加载时执行某个动作。
15+
可能是你想在一个模块被加载时触发某个回调函数来通知你。
1716

18-
19-
This problem can be solved using the same import hook machinery discussed in
20-
Recipe 10.11. Here is a possible solution:
17+
这个问题可以使用10.11小节中同样的导入钩子机制来实现。下面是一个可能的方案:
2118

2219
.. code-block:: python
2320
@@ -61,7 +58,7 @@ Recipe 10.11. Here is a possible solution:
6158
6259
sys.meta_path.insert(0, PostImportFinder())
6360
64-
To use this code, you use the when_imported() decorator. For example:
61+
这样,你就可以使用 ``when_imported()`` 装饰器了,例如:
6562

6663
.. code-block:: python
6764
@@ -75,8 +72,7 @@ To use this code, you use the when_imported() decorator. For example:
7572
Threads? Are you crazy?
7673
>>>
7774
78-
As a more practical example, maybe you want to apply decorators to existing definitions,
79-
such as shown here:
75+
作为一个更实际的例子,你可能想在已存在的定义上面添加装饰器,如下所示:
8076

8177
.. code-block:: python
8278
@@ -99,53 +95,30 @@ such as shown here:
9995
----------
10096
讨论
10197
----------
102-
This recipe relies on the import hooks that were discussed in Recipe 10.11, with a slight
103-
twist.
104-
105-
106-
First, the role of the @when_imported decorator is to register handler functions that get
107-
triggered on import. The decorator checks sys.modules to see if a module was already
108-
loaded. If so, the handler is invoked immediately. Otherwise, the handler is added to a
109-
list in the _post_import_hooks dictionary. The purpose of _post_import_hooks is
110-
simply to collect all handler objects that have been registered for each module. In principle,
111-
more than one handler could be registered for a given module.
112-
113-
114-
To trigger the pending actions in _post_import_hooks after module import, the Post
115-
ImportFinder class is installed as the first item in sys.meta_path. If you recall from
116-
Recipe 10.11, sys.meta_path contains a list of finder objects that are consulted in order
117-
to locate modules. By installing PostImportFinder as the first item, it captures all module
118-
imports.
119-
98+
本节技术依赖于10.11小节中讲述过的导入钩子,并稍作修改。
12099

121-
In this recipe, however, the role of PostImportFinder is not to load modules, but to
122-
trigger actions upon the completion of an import. To do this, the actual import is delegated
123-
to the other finders on sys.meta_path. Rather than trying to do this directly, the
124-
function imp.import_module() is called recursively in the PostImportLoader class. To
125-
avoid getting stuck in an infinite loop, PostImportFinder keeps a set of all the modules
126-
that are currently in the process of being loaded. If a module name is part of this set, it
127-
is simply ignored by PostImportFinder. This is what causes the import request to pass
128-
to the other finders on sys.meta_path.
100+
``@when_imported`` 装饰器的作用是注册在导入时被激活的处理器函数。
101+
该装饰器检查sys.modules来查看模块是否真的已经被加载了。
102+
如果是的话,该处理器被立即调用。不然,处理器被添加到 ``_post_import_hooks`` 字典中的一个列表中去。
103+
``_post_import_hooks`` 的作用就是收集所有的为每个模块注册的处理器对象。
104+
一个模块可以注册多个处理器。
129105

130-
After a module has been loaded with imp.import_module(), all handlers currently registered
131-
in _post_import_hooks are called with the newly loaded module as an argument.
106+
要让模块导入后触发添加的动作,``PostImportFinder`` 类被设置为sys.meta_path第一个元素。
107+
它会捕获所有模块导入操作。
132108

109+
本节中的 ``PostImportFinder`` 的作用并不是加载模块,而是自带导入完成后触发相应的动作。
110+
实际的导入被委派给位于sys.meta_path中的其他查找器。
111+
``PostImportLoader`` 类中的 ``imp.import_module()`` 函数被递归的调用。
112+
为了避免陷入无线循环,``PostImportFinder`` 保持了一个所有被加载过的模块集合。
113+
如果一个模块名存在就会直接被忽略掉。
133114

134-
From this point forward, the handlers are free to do what they want with the module.
135-
A major feature of the approach shown in this recipe is that the patching of a module
136-
occurs in a seamless fashion, regardless of where or how a module of interest is actually
137-
loaded. You simply write a handler function that’s decorated with @when_imported()
138-
and it all just magically works from that point forward.
115+
当一个模块被 ``imp.import_module()`` 加载后,
116+
所有在_post_import_hooks被注册的处理器被调用,使用新加载模块作为一个参数。
139117

118+
有一点需要注意的是本机不适用于那些通过 ``imp.reload()`` 被显式加载的模块。
119+
也就是说,如果你加载一个之前已被加载过的模块,那么导入处理器将不会再被触发。
120+
另外,要是你从sys.modules中删除模块然后再重新导入,处理器又会再一次触发。
140121

141-
One caution about this recipe is that it does not work for modules that have been explicitly
142-
reloaded using imp.reload(). That is, if you reload a previously loaded module,
143-
the post import handler function doesn’t get triggered again (all the more reason to not
144-
use reload() in production code). On the other hand, if you delete the module from
145-
sys.modules and redo the import, you’ll see the handler trigger again.
122+
更多关于导入后钩子信息请参考 `PEP 369 <https://www.python.org/dev/peps/pep-0369>`_.
146123

147124

148-
More information about post-import hooks can be found in PEP 369 . As of this writing,
149-
the PEP has been withdrawn by the author due to it being out of date with the current
150-
implementation of the importlib module. However, it is easy enough to implement
151-
your own solution using this recipe.

0 commit comments

Comments
 (0)