1. import_hook
所谓import hook就是指直接自定义finder和loader,并将finder放入导入过程,以实现一些特殊的运行时行为的技巧.
利用这个可以做到很多非常神奇的事情,比如
- import某个特定模块时触发某个回调函数来通知我们
- import一个远程服务器上的模块
- 直接import其他语言的模块来使用
本节需要的先验知识包括:
1.1. import hook的基本形式
import hook通常是以一个单文件模块的形式出现的,其中的过程说白了就是自定义finder和loader,因此自定义这两个类都是必须的,然后就是将定义的finder实例化,并将这个实例加入sys.meta_path.下面是模板代码.
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict   class ClientImportLoader(Loader):     @classmethod     def create_module(clz,spec):         """用于创建模块的."""         module = __create_module_from_spec(spec)         return module or None      @classmethod     def exec_module (clz, module):         """每次执行引入模块或者重载模块时会执行的操作"""         pass  loader= ClientImportLoader()   class ClientImportFinder(MetaPathFinder):      @classmethod     def find_spec (klass, full_name, paths=None, target=None):         """查找模块的逻辑"""         pass         return ModuleSpec(full_name, loader, origin=module_full_path)   sys.meta_path.insert(0, ClientImportFinder()) 当这个定义import hook的模块被加载后,他就可以正常的执行自己的功能了,因此通常这个import hook的模块需要优先加载.
1.2. import某个特定模块时触发某个回调函数来通知我们
这个例子来自python cookbook,不过上面的代码已经比较过时了,这边给出python3.5+推荐的写法
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) @when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') import numpy ********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] import a ********None finder._skip set() 为了避免陷入无线循环,ClientImportFinder维护了一个所有被加载过的模块集合_skip,如果一个模块在加载过程中又有另一个地方来加载,那么就会跳过这个加载器
1.3. import一个远程服务器上的模块
这个例子主要是复写finder以可以查找到目标服务器上的模块文件.同时复写loader的create_module方法用远端的代码生成服务.
我们的远程代码以http服务的形式放在静态服务器上
testcode-|          |-spam.py          |-fib.py          |-grok-|                 |-__init__.py                 |-blah.py spam.py
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 0fib.py
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 1grok/__init__.py
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 2grok/blah.py
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 3使用python自带的http服务启动:
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 4import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 5import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 61.3.1. 最简单的方法
这个流程也描述了最通用的模块导入流程.我们可以使用imp.new_module新建一个空的模块对象,再使用内置方法compile()将源码编译到一个代码对象中,然后在模块对象的字典中来执行它.
这种方式没有嵌入到通常的import语句中,如果要支持更高级的结构比如包就需要更多的工作了.
下面是使用这个函数的方式:
import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 7import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 8import importlib from importlib.abc import (     MetaPathFinder,      PathEntryFinder,     Loader ) from importlib.machinery import ModuleSpec import sys from collections import defaultdict  _post_import_hooks = defaultdict(list)  class ClientImportLoader(Loader):     def __init__(self, finder):         self._finder = finder       def create_module(self,spec):         """这边只要调用父类的实现即可."""         return super().create_module(spec)      def exec_module (self, module):         """在_post_import_hooks中查找对应模块中的回调函数并执行."""         for func in _post_import_hooks[module.__name__]:             func(module)         self._finder._skip.remove(module.__name__)  class ClientImportFinder(MetaPathFinder):      def __init__(self):         self._skip = set()      def find_spec(self, full_name, paths=None, target=None):         if full_name in self._skip:             return None         self._skip.add(full_name)         loader = ClientImportLoader(self)         return ModuleSpec(full_name, loader, origin=paths)   def when_imported(fullname):     def decorate(func):         if fullname in sys.modules:             func(sys.modules[fullname])         else:             _post_import_hooks[fullname].append(func)         return func     return decorate  finder = ClientImportFinder() sys.meta_path.insert(0, finder) 9@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 0@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 1@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 2@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 31.3.2. 使用 import hook实现隐式调用远端模块
如果我们想要导入文件系统中某个文件作为模块,我们会这样写以确保文件目录Python解释器可以找到.
@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 4我们希望远端的也可以实现这种与标准流程统一的方式,这时候就需要使用import hook了.
因为访问的地址和文件系统不同,因此可以使用sys.path_hooks为这个特定的地址设置一个finder
此处我们需要
- 定义finder
- 定义loader
- 定义handle_url()函数作为钩子 - sys.path_hooks.append(handle_url)变量中注册着查找- sys.path的钩子,当- sys.path的实体被处理时会调用- sys.path_hooks中的函数.如果任何一个函数返回了一个finder,那么这个对象就被用来为- sys.path实体加载模块.
这个例子完全使用标准库实现
@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 5@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 6@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 7@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 8@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 9import numpy 0@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 7import numpy 2import numpy 3@when_imported('numpy') def warn_numpy(mod):     print('numpy? Are you crazy?') 7import numpy 5import numpy 61.4. 直接import其他语言的模块来使用
一个更加酷的用法是直接导入别的语言的代码成为模块.这有两种途径
- 通过一个自定义的编译器将源码编译为python可以直接import的动态链接库,之后再导入这个动态链接库
- 通过一个自定义的语法解释器将特定源码转化为python对象
1.4.1. 导入Fortran代码作为模块
这个例子我们来尝试第一种方法,其基本流程是:
- 定义一个finder用于找到以 - .f,- .f90或者- .f95位后缀的文件作为源文件- 需要注意的这个需求依然会用到文件系统,Fortran的源码很大的可能性与python的原生源文件共存,因此不适合使用 - sys.path_hook.
- 使用numpy中自带的工具 - f2py来实现Fortran代码的编译工作- f2py无法指定输出的动态链接库位置,需要进一步的文件系统操作.这边可以利用标准库- Pathlib和- shutil
- 将编译成功后的动态链接库导入到程序中. - 需要注意引入动态链接库时不能使用 - import或者- __import__或者- importlib.import_module这些直接生成完整模块对象的方式,否则会递归调用. 此处应该使用如下的方式借由生成spec来生成模块.- import numpy7- 再借由这个spec的loader来执行模块 - import numpy8
当然了这个例子并没有考虑fortain本身的语法和多文件编译的问题,可能还会有些问题.
import numpy 9********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 0********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 1********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 2********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 3********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 4********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 5********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 6********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 7********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 8********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 9import a 0import a 1import a 2********None ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_finder', 'create_module', 'exec_module', 'load_module', 'module_repr'] 91.5. 使用警告
import hook是python中非常高级的语言技巧,并不提倡用户使用,如果非要使用,请使用warnning在导入时提醒用户



 
		 
		 
		

还没有评论,来说两句吧...