5
5
----------
6
6
问题
7
7
----------
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
+ 不过,前提是这个模块已经被导入并且被使用过。
10
10
11
11
----------
12
12
解决方案
13
13
----------
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
+ 可能是你想在一个模块被加载时触发某个回调函数来通知你。
17
16
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小节中同样的导入钩子机制来实现。下面是一个可能的方案:
21
18
22
19
.. code-block :: python
23
20
@@ -61,7 +58,7 @@ Recipe 10.11. Here is a possible solution:
61
58
62
59
sys.meta_path.insert(0 , PostImportFinder())
63
60
64
- To use this code, you use the when_imported() decorator. For example:
61
+ 这样,你就可以使用 `` when_imported() `` 装饰器了,例如:
65
62
66
63
.. code-block :: python
67
64
@@ -75,8 +72,7 @@ To use this code, you use the when_imported() decorator. For example:
75
72
Threads? Are you crazy?
76
73
>> >
77
74
78
- As a more practical example, maybe you want to apply decorators to existing definitions,
79
- such as shown here:
75
+ 作为一个更实际的例子,你可能想在已存在的定义上面添加装饰器,如下所示:
80
76
81
77
.. code-block :: python
82
78
@@ -99,53 +95,30 @@ such as shown here:
99
95
----------
100
96
讨论
101
97
----------
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小节中讲述过的导入钩子,并稍作修改。
120
99
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
+ 一个模块可以注册多个处理器。
129
105
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
+ 它会捕获所有模块导入操作。
132
108
109
+ 本节中的 ``PostImportFinder `` 的作用并不是加载模块,而是自带导入完成后触发相应的动作。
110
+ 实际的导入被委派给位于sys.meta_path中的其他查找器。
111
+ ``PostImportLoader `` 类中的 ``imp.import_module() `` 函数被递归的调用。
112
+ 为了避免陷入无线循环,``PostImportFinder `` 保持了一个所有被加载过的模块集合。
113
+ 如果一个模块名存在就会直接被忽略掉。
133
114
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被注册的处理器被调用,使用新加载模块作为一个参数。
139
117
118
+ 有一点需要注意的是本机不适用于那些通过 ``imp.reload() `` 被显式加载的模块。
119
+ 也就是说,如果你加载一个之前已被加载过的模块,那么导入处理器将不会再被触发。
120
+ 另外,要是你从sys.modules中删除模块然后再重新导入,处理器又会再一次触发。
140
121
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 >`_.
146
123
147
124
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