赞
踩
Python 一般存在以下三种方式:
最后介绍一下在动态加载时经常用到的 inspect 模块。
__import__ (name[, globals[, locals[, fromlist[, level]]]])
参数说明:
- # test.py
- def test():
- print("test")
-
- class Test(object):
- def __init__(self):
- print("Test Create")
-
- class SubTest(Test):
- def __init__(self):
- print("Test2 Create")
动态加载 test.py
- c = __import__('test')
-
- print(c)
-
- c.test()
- obj = c.Test()
- obj_sub = c.SubTest()
- '''
- <module 'test' from '**************\\test.py'>
- test
- Test Create
- Test2 Create
- '''
如果输入的参数如果带有 “.”,采用 __import__ 直接导入 module 容易造成意想不到的结果。 OpenStack 的 oslo.utils 封装了 __import__,支持动态导入 class, object 等。
- # Copyright 2011 OpenStack Foundation.
- # All Rights Reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may
- # not use this file except in compliance with the License. You may obtain
- # a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- # License for the specific language governing permissions and limitations
- # under the License.
-
- """
- Import related utilities and helper functions.
- """
-
- import sys
- import traceback
-
-
- def import_class(import_str):
- """Returns a class from a string including module and class.
- .. versionadded:: 0.3
- """
- mod_str, _sep, class_str = import_str.rpartition('.')
- __import__(mod_str)
- try:
- return getattr(sys.modules[mod_str], class_str)
- except AttributeError:
- raise ImportError('Class %s cannot be found (%s)' %
- (class_str,
- traceback.format_exception(*sys.exc_info())))
-
-
- def import_object(import_str, *args, **kwargs):
- """Import a class and return an instance of it.
- .. versionadded:: 0.3
- """
- return import_class(import_str)(*args, **kwargs)
-
-
- def import_object_ns(name_space, import_str, *args, **kwargs):
- """Tries to import object from default namespace.
- Imports a class and return an instance of it, first by trying
- to find the class in a default namespace, then failing back to
- a full path if not found in the default namespace.
- .. versionadded:: 0.3
- .. versionchanged:: 2.6
- Don't capture :exc:`ImportError` when instanciating the object, only
- when importing the object class.
- """
- import_value = "%s.%s" % (name_space, import_str)
- try:
- cls = import_class(import_value)
- except ImportError:
- cls = import_class(import_str)
- return cls(*args, **kwargs)
-
-
- def import_module(import_str):
- """Import a module.
- .. versionadded:: 0.3
- """
- __import__(import_str)
- return sys.modules[import_str]
-
-
- def import_versioned_module(module, version, submodule=None):
- """Import a versioned module in format {module}.v{version][.{submodule}].
- :param module: the module name.
- :param version: the version number.
- :param submodule: the submodule name.
- :raises ValueError: For any invalid input.
- .. versionadded:: 0.3
- .. versionchanged:: 3.17
- Added *module* parameter.
- """
-
- # NOTE(gcb) Disallow parameter version include character '.'
- if '.' in '%s' % version:
- raise ValueError("Parameter version shouldn't include character '.'.")
- module_str = '%s.v%s' % (module, version)
- if submodule:
- module_str = '.'.join((module_str, submodule))
- return import_module(module_str)
-
-
- def try_import(import_str, default=None):
- """Try to import a module and if it fails return default."""
- try:
- return import_module(import_str)
- except ImportError:
- return default
-
-
- def import_any(module, *modules):
- """Try to import a module from a list of modules.
- :param modules: A list of modules to try and import
- :returns: The first module found that can be imported
- :raises ImportError: If no modules can be imported from list
- .. versionadded:: 3.8
- """
- for module_name in (module,) + modules:
- imported_module = try_import(module_name)
- if imported_module:
- return imported_module
-
- raise ImportError('Unable to import any modules from the list %s' %
- str(modules))

动态加载某个模块
- import importlib
-
- itertools = importlib.import_module('itertools')
importlib.import_module(name, package=None) 参数说明:
import_module() 函数是一个对 importlib.__import__() 进行简化的包装器。 这意味着该函数的所有主义都来自于 importlib.__import__()。 这两个函数之间最重要的不同点在于 import_module() 返回指定的包或模块 (例如 pkg.mod),而 __import__() 返回最高层级的包或模块 (例如 pkg)。
如果动态导入一个自从解释器开始执行以来被创建的模块(即创建了一个 Python 源代码文件),为了让导入系统知道这个新模块,可能需要调用 invalidate_caches()。
判断某个模块是否可以被加载
- import importlib.util
- import sys
-
- # For illustrative purposes.
- name = 'itertools'
-
- spec = importlib.util.find_spec(name)
- if spec is None:
- print("can't find the itertools module")
- else:
- # If you chose to perform the actual import ...
- module = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(module)
- # Adding the module to sys.modules is optional.
- sys.modules[name] = module
其中 importlib.util.find_spec(name, package=None) 参数与 importlib.import_module(name, package=None) 意义相同,其返回一个命名空间,其中包含用于加载模块的相关导入信息。importlib.util.module_from_spec(spec) 从 spec 中创建一个新的模块,之后就可以是使用 module 当 itertools 使用。spec.loader.exec_module(module) 执行某个模块。
直接从文件中加载
- import importlib.util
- import sys
-
- # For illustrative purposes.
- import tokenize
- file_path = tokenize.__file__
- module_name = tokenize.__name__
-
- spec = importlib.util.spec_from_file_location(module_name, file_path)
- module = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(module)
- # Optional; only necessary if you want to be able to import the module
- # by name later.
- sys.modules[module_name] = module
importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None) 其根据指向某个文件的路径创建一个 ModuleSpec 实例。例子中 module 可以直接当成 tokenize 使用。
通过 importer 来管理 finder 和 loader
- import importlib.machinery
- import sys
-
- # For illustrative purposes only.
- SpamMetaPathFinder = importlib.machinery.PathFinder
- SpamPathEntryFinder = importlib.machinery.FileFinder
- loader_details = (importlib.machinery.SourceFileLoader,
- importlib.machinery.SOURCE_SUFFIXES)
-
- # Setting up a meta path finder.
- # Make sure to put the finder in the proper location in the list in terms of
- # priority.
- sys.meta_path.append(SpamMetaPathFinder)
-
- # Setting up a path entry finder.
- # Make sure to put the path hook in the proper location in the list in terms
- # of priority.
- sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))

实现 importlib.import_module 函数
- import importlib.util
- import sys
-
- def import_module(name, package=None):
- """An approximate implementation of import."""
- absolute_name = importlib.util.resolve_name(name, package)
- try:
- return sys.modules[absolute_name]
- except KeyError:
- pass
-
- path = None
- if '.' in absolute_name:
- parent_name, _, child_name = absolute_name.rpartition('.')
- parent_module = import_module(parent_name)
- path = parent_module.__spec__.submodule_search_locations
- for finder in sys.meta_path:
- spec = finder.find_spec(absolute_name, path)
- if spec is not None:
- break
- else:
- msg = f'No module named {absolute_name!r}'
- raise ModuleNotFoundError(msg, name=absolute_name)
- module = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(module)
- sys.modules[absolute_name] = module
- if path is not None:
- setattr(parent_module, child_name, module)
- return module

- eval(expression, globals=None, locals=None)
-
- exec(object[, globals[, locals]])
参数说明:
exec 函数与 eval 函数有很多类似之处,主要的不同有以下两点:
- x = 10
-
- def func():
- y = 20
- a = eval('x + y')
- print('a: ', a)
- b = eval('x + y', {'x': 1, 'y': 2})
- print('b: ', b)
- c = eval('x + y', {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
- print('c: ', c)
- d = eval('print(x, y)')
- print('d: ', d)
-
- func()
-
- '''
- a: 30
- b: 3
- c: 4
- 10 20
- d: None
- '''

- x = 10
- expr = """
- z = 30
- sum = x + y + z
- print(sum)
- """
- def func():
- y = 20
- exec(expr)
- exec(expr, {'x': 1, 'y': 2})
- exec(expr, {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
-
- func()
- '''
- 60
- 33
- 34
- '''

inspect.getmembers(object[, predicate])
其实现了提取某个对象 object 中的所有成员,以(name,value)对组成的列表返回。其中第二个参数通常可以根据需要调用如下16个方法:
inspect.ismodule(object): 是否为模块
inspect.isclass(object):是否为类
inspect.ismethod(object):是否为方法(bound method written in python)
inspect.isfunction(object):是否为函数(python function, including lambda expression)
inspect.isgeneratorfunction(object):是否为python生成器函数
inspect.isgenerator(object):是否为生成器
inspect.istraceback(object): 是否为traceback
inspect.isframe(object):是否为frame
inspect.iscode(object):是否为code
inspect.isbuiltin(object):是否为built-in函数或built-in方法
inspect.isroutine(object):是否为用户自定义或者built-in函数或方法
inspect.isabstract(object):是否为抽象基类
inspect.ismethoddescriptor(object):是否为方法标识符
inspect.isdatadescriptor(object):是否为数字标识符,数字标识符有__get__ 和__set__属性; 通常也有__name__和__doc__属性
inspect.isgetsetdescriptor(object):是否为getset descriptor
inspect.ismemberdescriptor(object):是否为member descriptor
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。