Carga dinámica de Python

Carga dinámica de Python

Python generalmente tiene las siguientes tres formas:

  • Función __import __ () incorporada
  • módulo importlib
  • función ejecutiva

Finalmente, presentaré el módulo de inspección que se usa a menudo durante la carga dinámica.

función __import__

__import__ (name[, globals[, locals[, fromlist[, level]]]])

Descripción de parámetros:

  • nombre (obligatorio): el nombre del módulo cargado
  • globals (opcional): un diccionario que contiene variables globales. Esta opción rara vez se usa y usa el valor predeterminado global ()
  • locals (opcional): un diccionario que contiene variables locales, que no son utilizadas por la implementación estándar interna, y usan el valor predeterminado local ()
  • fromlist (opcional): el nombre del submódulo importado
  • level (Opcional): opción de ruta de importación. El valor predeterminado en Python 2 es -1, lo que significa que se admiten tanto la importación absoluta como la importación relativa. El valor predeterminado en Python 3 es 0, lo que significa que solo se admite la importación absoluta. Si es mayor que 0, significa el nivel relativo del directorio padre importado, es decir, 1 es similar a '.' Y 2 es similar a '..'.
# test.py
def test():
	print("test")

class Test(object):
	def __init__(self):
		print("Test Create")
		
class SubTest(Test):
	def __init__(self):
		print("Test2 Create")

Cargar test.py dinámicamente 

c = __import__('test')

print(c)

c.test()
obj = c.Test()
obj_sub = c.SubTest()
'''
<module 'test' from '**************\\test.py'>
test
Test Create
Test2 Create
'''

Si el parámetro de entrada contiene ".", Usar __import__ para importar directamente el módulo puede generar fácilmente resultados inesperados. Oslo.utils de OpenStack   encapsula __import__ y admite la importación dinámica de clases, objetos, etc.

# 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))

módulo importlib

Cargar un módulo dinámicamente

import importlib

itertools = importlib.import_module('itertools')

importlib.import_module (nombre, paquete = Ninguno) descripción del parámetro:

  • nombre: Qué módulo importar en modo de importación absoluta o relativa (por ejemplo, como este pkg.mod o este ..mod)
  • paquete: si el nombre del parámetro se especifica mediante una importación relativa, los paquetes de parámetros se deben establecer en el nombre del paquete, que sirve como punto de anclaje para analizar el nombre del paquete (por ejemplo, import_module ('.. mod', 'pkg.subpkg' ) Importará pkg.md).

La función import_module () es un contenedor simplificado para importlib .__ import __ (). Esto significa que toda la ideología de esta función proviene de importlib .__ import __ (). La diferencia más importante entre estas dos funciones es que import_module () devuelve el paquete o módulo especificado (como pkg.mod), mientras que __import __ () devuelve el paquete o módulo de nivel más alto (como pkg).

Si importa dinámicamente un módulo que se ha creado desde que el intérprete comenzó a ejecutarse (es decir, se crea un archivo de código fuente de Python), para que el sistema de importación sepa sobre el nuevo módulo, es posible que deba llamar a invalidate_caches ().

Determinar si se puede cargar un módulo

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

El parámetro importlib.util.find_spec (nombre, paquete = Ninguno) tiene el mismo significado que importlib.import_module (nombre, paquete = Ninguno). Devuelve un espacio de nombres que contiene información de importación relevante para cargar módulos. importlib.util.module_from_spec (spec) crea un nuevo módulo a partir de la especificación, y luego puede usar el módulo como itertools. spec.loader.exec_module (módulo) Ejecuta un módulo.

Cargar directamente desde el archivo

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 (nombre, ubicación, *, loader = None, submodule_search_locations = None) Crea una instancia de ModuleSpec basada en la ruta a un archivo determinado. En el ejemplo, el módulo se puede usar directamente como tokenizar.

Gestionar buscador y cargador a través del importador

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))

Implementar la función 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

función ejecutiva

eval(expression, globals=None, locals=None)

exec(object[, globals[, locals]])

Descripción de parámetros:

  • globals: parámetro opcional, que representa el espacio de nombres global (almacenando variables globales). Si se proporciona, debe ser un objeto de diccionario. Normalmente se pasa en globals (), que devuelve un diccionario que representa la tabla de identificadores globales actual. Este es siempre el diccionario del módulo actual (dentro de una función o método, esto se refiere al módulo que define la función o método, no al módulo que llama a la función o método)
  • locals: parámetro opcional, que representa el espacio de nombres local actual (almacenando variables locales), si se proporciona, puede ser cualquier objeto de mapeo. Si se omite este parámetro, tomará el mismo valor que los globales. Normalmente se pasa en locals (), que actualiza y devuelve un diccionario que representa la tabla de identificadores locales actual. Cuando se llama a una variable libre dentro de una función, la función locals () la devolverá; cuando no se llama a una variable libre, la función locals () no la devolverá.

Existen muchas similitudes entre la función exec y la función eval. Las principales diferencias son las siguientes:

  • La función eval () solo puede calcular el valor de una sola expresión, mientras que la función exec () puede ejecutar segmentos de código de forma dinámica.
  • La función eval () puede tener un valor de retorno y el valor de retorno de la función exec () es siempre Ninguno.
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
'''

inspeccionar módulo

  • Juicio de operaciones en clases, módulos, miembros, clases y tipos de módulos
  • Obtén el código fuente
  • Obtener información de parámetros de una clase o función
  • Pila de análisis
inspect.getmembers(object[, predicate])

Implementa la extracción de todos los miembros de un objeto y lo devuelve como una lista de pares (nombre, valor). El segundo parámetro generalmente puede llamar a los siguientes 16 métodos según sea necesario:

  1. inspect.ismodule (objeto): si es un módulo

  2. inspect.isclass (objeto): si es una clase

  3. inspect.ismethod (objeto): si es un método (método vinculado escrito en Python)

  4. inspect.isfunction (objeto): si es una función (función de python, incluida la expresión lambda)

  5. inspect.isgeneratorfunction (objeto): si es una función generadora de Python

  6. inspect.isgenerator (objeto): si es un generador

  7. inspect.istraceback (objeto): si es rastreo

  8. inspect.isframe (objeto): si es un marco

  9. inspect.iscode (objeto): si es código

  10. inspect.isbuiltin (objeto): si es una función incorporada o un método incorporado

  11. inspect.isroutine (objeto): si es una función o método definido por el usuario o incorporado

  12. inspect.isabstract (objeto): si es una clase base abstracta

  13. inspect.ismethoddescriptor (objeto): ¿Es un identificador de método?

  14. inspect.isdatadescriptor (objeto): ya sea un identificador digital, los identificadores digitales tienen atributos __get__ y __set__; por lo general, también tienen atributos __name__ y __doc__

  15. inspect.isgetsetdescriptor (objeto): si es un descriptor getset

  16. inspect.ismemberdescriptor (objeto): si es un descriptor de miembro

Supongo que te gusta

Origin blog.csdn.net/a40850273/article/details/94404363
Recomendado
Clasificación