如何动态加载Python类

发布于 2024-07-14 09:18:46 字数 322 浏览 11 评论 0原文

给定一个Python类的字符串,例如my_package.my_module.MyClass,加载它的最佳方法是什么?

换句话说,我正在寻找 Java 中等效的 Class.forName() 函数,Python 中的函数。 它需要在 Google App Engine 上运行。

最好是一个函数,它接受类的 FQN 作为字符串,并返回对该类的引用:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

Given a string of a Python class, e.g. my_package.my_module.MyClass, what is the best possible way to load it?

In other words I am looking for a equivalent Class.forName() in Java, function in Python. It needs to work on Google App Engine.

Preferably this would be a function that accepts the FQN of the class as a string, and returns a reference to the class:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

随心而道 2024-07-21 09:18:47

如果您不想自己动手,pydoc 模块中提供了一个函数来完成此操作:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

与此处列出的其他方法相比,此方法的优点是 locate 将在提供的虚线路径中找到任何 python 对象,而不仅仅是直接在模块内的对象。 例如my_package.my_module.MyClass.attr

如果您好奇他们的配方是什么,请查看以下函数:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

它依赖于 pydoc.safeimport 函数。 以下是相关文档:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

If you don't want to roll your own, there is a function available in the pydoc module that does exactly this:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

The advantage of this approach over the others listed here is that locate will find any python object at the provided dotted path, not just an object directly within a module. e.g. my_package.my_module.MyClass.attr.

If you're curious what their recipe is, here's the function:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

It relies on pydoc.safeimport function. Here are the docs for that:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""
伤痕我心 2024-07-21 09:18:47

如果您使用的是 Django,则可以使用 导入字符串

是的,我知道 OP 没有要求 django,但我在寻找 Django 解决方案时遇到了这个问题,但没有找到,并将其放在这里供下一个寻找它的男孩/女孩使用。

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

请记住,如果您想导入没有 . 的内容,例如 reargparse 使用:

re = __import__('re')

If you're using Django you can use import_string.

Yes i'm aware OP did not ask for django, but i ran across this question looking for a Django solution, didn't find one, and put it here for the next boy/gal that looks for it.

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

Keep in mind, if you want to import something that doesn't have a ., like re or argparse use:

re = __import__('re')
我一直都在从未离去 2024-07-21 09:18:47
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
姜生凉生 2024-07-21 09:18:47

这里分享一下我在尝试解决这个问题时在 __import__ 和 importlib 上发现的一些东西。

我正在使用Python 3.7.3。

当我尝试访问模块 abc 中的类 d 时,

mod = __import__('a.b.c')

mod 变量引用顶部命名空间 a

因此,为了到达 d 类,我需要:

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

如果我们尝试这样做,

mod = __import__('a.b.c')
d = getattr(mod, 'd')

我们实际上是在尝试寻找 ad

当使用importlib时,我想库已经为我们完成了递归getattr。 因此,当我们使用 importlib.import_module 时,我们实际上获得了最深层模块的句柄。

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

Here is to share something I found on __import__ and importlib while trying to solve this problem.

I am using Python 3.7.3.

When I try to get to the class d in module a.b.c,

mod = __import__('a.b.c')

The mod variable refer to the top namespace a.

So to get to the class d, I need to

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

If we try to do

mod = __import__('a.b.c')
d = getattr(mod, 'd')

we are actually trying to look for a.d.

When using importlib, I suppose the library has done the recursive getattr for us. So, when we use importlib.import_module, we actually get a handle on the deepest module.

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d
萌化 2024-07-21 09:18:47
def my_import(name):
    components = name.split('.')
    mod = __import__(".".join(components[:-1]))
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

修复 python 3.11 上的错误导入

def my_import(name):
    components = name.split('.')
    mod = __import__(".".join(components[:-1]))
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

Fix error import on python 3.11

阳光下慵懒的猫 2024-07-21 09:18:47

好的,对我来说,这就是它的工作方式(我使用的是 Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

然后,b 是类“MyClass”的实例

OK, for me that is the way it worked (I am using Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

Then, b is an instance of class 'MyClass'

酒几许 2024-07-21 09:18:47

如果您碰巧已经拥有所需类的实例,则可以使用“type”函数提取其类类型并使用它来构造一个新实例:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

If you happen to already have an instance of your desired class, you can use the 'type' function to extract its class type and use this to construct a new instance:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()
杯别 2024-07-21 09:18:47

Python 有一个内置库 importlib 来完成这项工作。 :,如何绕过包名称作为参数动态访问模块方法和类方法。 下面给出一个例子。

模块1:

def get_scenario_data():
    return "module1 scenario data"


class Module1:

    def module1_function1(self):
        return "module1_function"

    def module1_function2(self):
        return "module2_function"

模块2:

def get_scenario_data():
    return "module2 scenario data"



class Module2:

    def module2_function1(self):
        return "module2_function1"

    def module2_function2(self):
        return "module2_function2"

ModuleTest:

  1. 将根据包名称作为参数动态访问模块方法
  2. 将根据包名称作为参数动态访问类方法。

模块测试

import importlib

module = importlib.import_module('pack1.nestedpack1.module1')
print(module.get_scenario_data())
modul1_cls_obj = getattr(module, 'Module1')()
print(modul1_cls_obj.module1_function1())
print(modul1_cls_obj.module1_function2())

module = importlib.import_module('pack1.nestedpack1.module2')
modul2_cls_obj = getattr(module, 'Module2')()
print(modul2_cls_obj.module2_function1())
print(modul2_cls_obj.module2_function2())
print(module.get_scenario_data())

结果

module1 scenario data
module1_function
module2_function
module2_function1
module2_function2
module2 scenario data

Python has an inbuilt library importlib to get the job done. :, How to access module method and class method dynamically bypassing package name as a param. An example is given below.

Module 1:

def get_scenario_data():
    return "module1 scenario data"


class Module1:

    def module1_function1(self):
        return "module1_function"

    def module1_function2(self):
        return "module2_function"

Module 2:

def get_scenario_data():
    return "module2 scenario data"



class Module2:

    def module2_function1(self):
        return "module2_function1"

    def module2_function2(self):
        return "module2_function2"

ModuleTest:

  1. Will access the module methods dynamically based on the package name as param
  2. Will access the class methods dynamically based on the package name as param.

ModuleTest

import importlib

module = importlib.import_module('pack1.nestedpack1.module1')
print(module.get_scenario_data())
modul1_cls_obj = getattr(module, 'Module1')()
print(modul1_cls_obj.module1_function1())
print(modul1_cls_obj.module1_function2())

module = importlib.import_module('pack1.nestedpack1.module2')
modul2_cls_obj = getattr(module, 'Module2')()
print(modul2_cls_obj.module2_function1())
print(modul2_cls_obj.module2_function2())
print(module.get_scenario_data())

Results

module1 scenario data
module1_function
module2_function
module2_function1
module2_function2
module2 scenario data
柏拉图鍀咏恒 2024-07-21 09:18:47

PyPI 模块自动加载器和 导入

# PyPI imports
import pkg_resources, subprocess, sys

modules   = {'lxml.etree', 'pandas', 'screeninfo'}
required  = {m.split('.')[0] for m in modules}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing   = required - installed

if missing:
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', *missing])

for module in set.union(required, modules):
    globals()[module] = __import__(module)

测试:

print(pandas.__version__)
print(lxml.etree.LXML_VERSION)

PyPI module autoloader & import

# PyPI imports
import pkg_resources, subprocess, sys

modules   = {'lxml.etree', 'pandas', 'screeninfo'}
required  = {m.split('.')[0] for m in modules}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing   = required - installed

if missing:
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', *missing])

for module in set.union(required, modules):
    globals()[module] = __import__(module)

Tests:

print(pandas.__version__)
print(lxml.etree.LXML_VERSION)
冰雪梦之恋 2024-07-21 09:18:47

为现有答案添加一点复杂性......

根据用例,必须显式指定完整路径可能会有些不方便(例如 package.subpackage.module...)您要导入的类/方法的名称。 在 importlib 之上,我们可以利用 __init__.py 使事情变得更加干净。

假设我有一个 python 包,如下所示:

├── modes
│   ├── __init__.py
│   ├── bar.py
│   ├── foo.py
│   ├── modes.py

foo.py,比如说,有一些我们想在程序中其他地方使用的类/函数:

from modes.modes import Mode

class Foo(Mode):
    def __init__(self, *arg, **kwargs):
        super(Foo, self).__init__(*arg, **kwargs)
        
    def run(self):
        self.LOG.info(f"This is FOO!")

使用命令行参数,我可以传递与我想要运行的模式相对应的参数。 我希望能够做到这样的事情:

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes.foo')
    getattr(module, mode)().run()

哪个输出:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

工作正常,但是我们真正想要得到的是:

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes')  # only import the package, not modules explicitely
    getattr(module, mode)().run()

这会引发错误:

>> set_mode("Foo")
>> AttributeError: module 'modes' has no attribute 'Foo'

但是,我们可以将以下内容添加到 / mode/__init__.py

from .foo import Foo
from .bar import Bar

那么,我们可以这样做:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

>> set_mode("Bar")
>> engine_logger:INFO - This is BAR!

在其他世界中,我们在 init.py 中导入的所有子模块/函数/类都可以直接使用 importlib.import_module(...) 找到,而不必指定来自外部的完整路径。

Adding a bit of sophistication to the existing answers....

Depending on the use case, it may be somewhat inconvenient to have to explicitly specify the full path (E.g. package.subpackage.module...) of the class/method you want to import. On top of importlib, we can leverage __init__.py to make things even cleaner.

Let's say I have a python package, like so:

├── modes
│   ├── __init__.py
│   ├── bar.py
│   ├── foo.py
│   ├── modes.py

foo.py, say, have some class/functions we'd like to use somewhere else in our program:

from modes.modes import Mode

class Foo(Mode):
    def __init__(self, *arg, **kwargs):
        super(Foo, self).__init__(*arg, **kwargs)
        
    def run(self):
        self.LOG.info(f"This is FOO!")

With a command line argument, I can pass an argument that corresponds to a mode that I want to run. I'd like to be able to so something like this:

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes.foo')
    getattr(module, mode)().run()

which outputs:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

That works fine, however what we'd REALLY want to get at is this:

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes')  # only import the package, not modules explicitely
    getattr(module, mode)().run()

Which raises an error:

>> set_mode("Foo")
>> AttributeError: module 'modes' has no attribute 'Foo'

However, we can add the following to /modes/__init__.py:

from .foo import Foo
from .bar import Bar

Then, we can do:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

>> set_mode("Bar")
>> engine_logger:INFO - This is BAR!

In other worlds, all sub modules/functions/classes we import in init.py will be found directly with importlib.import_module(...), without having to specify the full path from outside.

剪不断理还乱 2024-07-21 09:18:47

我已经创建了这个方法

import importlib
import sys
import os


def import_classes(root_directory: str):
    imported_classes, import_errors = [], []
    for root, dirs, files in os.walk(root_directory):

    if os.path.isabs(root):
        """
            When an absolute path is specified: 'C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery\\scenarios'
            we will add the parent directory: 'C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery' into "sys.path" variable
            and we will start to create the import path starting from the last parent directory: "scenarios"
        """
        parent_dir, last_parent_directory = os.path.dirname(root), os.path.basename(root)

    else:
        # When a relative path is specified; just add the current working directory into "sys.path" variable
        parent_dir, last_parent_directory = os.getcwd(), root

    """
    Python searches for modules starting from each path specified in "sys.path" list.
        Example:
            Current working directory: "C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery"
            last_parent_directory:  "scenarios"

            If current working directory in sys.path, python will try to import the module from:
                "C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery\\scenarios"
    
    This is why we add the parent directory into "sys.path" variable
    """
    if parent_dir not in sys.path:
        sys.path.insert(0, parent_dir)

    # Import classes from Python Files
    for filename in files:
        if filename.endswith('.py'):
            module_name = os.path.splitext(filename)[0]  # Remove the file extension to get the module name
            last_parent_directory = last_parent_directory.replace("..\\", "").replace("../", "").replace(".\\", "").replace("./", "")  # Remove relative path prefix
            last_parent_directory = last_parent_directory.replace("\\", ".").replace("/", ".")  # Replace path separators with dots

            module_import_path = f"{last_parent_directory}.{module_name}"  # Build module import path

            try:
                # Force the module to be reimported if it has already been imported
                if module_import_path in sys.modules:
                    del sys.modules[module_import_path]
                
                module_object = importlib.import_module(module_import_path)
                
                # Iterate over items in the module_object
                for attribute_name in dir(module_object):
                    # Get the attributes from the module_object
                    attribute = getattr(module_object, attribute_name)

                    # Check if it's a class and append to list
                    if isinstance(attribute, type):
                        imported_classes.append(attribute)

            except Exception as import_error:
                # In case of import errors; save the import arguments and the error and continue with other files
                import_errors.append((parent_dir, module_import_path, import_error))

return imported_classes, import_errors

现在,假设我们有以下文件夹结构和类:

scenarios_root (directory)
  scenarios (directory)
    scenario1.py
      -> Scenario1 (class)
      -> Scenario2 (class)
      -> Scenario3 (class)
                
    scenario2.py
      -> ScenarioA (class)
      -> ScenarioB (class)
      -> ScenarioC (class)

如果我们执行导入函数:

if __name__ == '__main__':
  imported_clas, import_err = import_classes(r"..\_dev\2023_08_30_plugin_discovery\scenarios_root")
  print(f"Number of imported classes: {len(imported_clas)}")
  print(f"Imported classes: {imported_clas}")
  print(f"Import errors: {import_err}", end="\n\n")

输出:

Number of imported classes: 6
Imported classes: [<class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario1'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario2'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario3'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioA'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioB'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioC'>]
Import errors: []

I have created this method

import importlib
import sys
import os


def import_classes(root_directory: str):
    imported_classes, import_errors = [], []
    for root, dirs, files in os.walk(root_directory):

    if os.path.isabs(root):
        """
            When an absolute path is specified: 'C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery\\scenarios'
            we will add the parent directory: 'C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery' into "sys.path" variable
            and we will start to create the import path starting from the last parent directory: "scenarios"
        """
        parent_dir, last_parent_directory = os.path.dirname(root), os.path.basename(root)

    else:
        # When a relative path is specified; just add the current working directory into "sys.path" variable
        parent_dir, last_parent_directory = os.getcwd(), root

    """
    Python searches for modules starting from each path specified in "sys.path" list.
        Example:
            Current working directory: "C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery"
            last_parent_directory:  "scenarios"

            If current working directory in sys.path, python will try to import the module from:
                "C:\\Users\\admin\\PycharmProjects\\my_project\\_dev\\plugin_discovery\\scenarios"
    
    This is why we add the parent directory into "sys.path" variable
    """
    if parent_dir not in sys.path:
        sys.path.insert(0, parent_dir)

    # Import classes from Python Files
    for filename in files:
        if filename.endswith('.py'):
            module_name = os.path.splitext(filename)[0]  # Remove the file extension to get the module name
            last_parent_directory = last_parent_directory.replace("..\\", "").replace("../", "").replace(".\\", "").replace("./", "")  # Remove relative path prefix
            last_parent_directory = last_parent_directory.replace("\\", ".").replace("/", ".")  # Replace path separators with dots

            module_import_path = f"{last_parent_directory}.{module_name}"  # Build module import path

            try:
                # Force the module to be reimported if it has already been imported
                if module_import_path in sys.modules:
                    del sys.modules[module_import_path]
                
                module_object = importlib.import_module(module_import_path)
                
                # Iterate over items in the module_object
                for attribute_name in dir(module_object):
                    # Get the attributes from the module_object
                    attribute = getattr(module_object, attribute_name)

                    # Check if it's a class and append to list
                    if isinstance(attribute, type):
                        imported_classes.append(attribute)

            except Exception as import_error:
                # In case of import errors; save the import arguments and the error and continue with other files
                import_errors.append((parent_dir, module_import_path, import_error))

return imported_classes, import_errors

Now, lets suppose we have the following folder structure and classes:

scenarios_root (directory)
  scenarios (directory)
    scenario1.py
      -> Scenario1 (class)
      -> Scenario2 (class)
      -> Scenario3 (class)
                
    scenario2.py
      -> ScenarioA (class)
      -> ScenarioB (class)
      -> ScenarioC (class)

If we execute the import function:

if __name__ == '__main__':
  imported_clas, import_err = import_classes(r"..\_dev\2023_08_30_plugin_discovery\scenarios_root")
  print(f"Number of imported classes: {len(imported_clas)}")
  print(f"Imported classes: {imported_clas}")
  print(f"Import errors: {import_err}", end="\n\n")

Output:

Number of imported classes: 6
Imported classes: [<class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario1'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario2'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario1.Scenario3'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioA'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioB'>, <class '_dev.2023_08_30_plugin_discovery.scenarios_root.scenarios.scenario2.ScenarioC'>]
Import errors: []
泛泛之交 2024-07-21 09:18:47

大家可以试试这个:

from pydoc import locate

module = locate("path to py file"))
if module != None:
  classname = getattr(module, "class name")
  if classname != None:
       classobject = classname("arguments")

One can try this:

from pydoc import locate

module = locate("path to py file"))
if module != None:
  classname = getattr(module, "class name")
  if classname != None:
       classobject = classname("arguments")
葵雨 2024-07-21 09:18:47

在 Google App Engine 中,有一个名为 import_stringwebapp2 函数。 有关详细信息,请参阅此处:https://webapp-improved.appspot.com/api/webapp2 .html

因此,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

例如,这在 webapp2.Route 中使用,您可以在其中使用处理程序或字符串。

In Google App Engine there is a webapp2 function called import_string. For more info see here:https://webapp-improved.appspot.com/api/webapp2.html

So,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

For example this is used in the webapp2.Route where you can either use a handler or a string.

ˇ宁静的妩媚 2024-07-21 09:18:47
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
热风软妹 2024-07-21 09:18:46

从 python 文档中,这是您想要的函数:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

简单的 __import__ 不起作用的原因是因为包字符串中第一个点之后的任何导入都是您所在模块的属性输入。 因此,这样的东西是行不通的:

__import__('foo.bar.baz.qux')

你必须像这样调用上面的函数:

my_import('foo.bar.baz.qux')

或者在你的例子中:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

编辑:我对此有点偏离。 您基本上想要做的是:

from my_package.my_module import my_class

仅当您有一个 fromlist 时才需要上述函数。 因此,适当的调用将如下所示:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

From the python documentation, here's the function you want:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

The reason a simple __import__ won't work is because any import of anything past the first dot in a package string is an attribute of the module you're importing. Thus, something like this won't work:

__import__('foo.bar.baz.qux')

You'd have to call the above function like so:

my_import('foo.bar.baz.qux')

Or in the case of your example:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT: I was a bit off on this. What you're basically wanting to do is this:

from my_package.my_module import my_class

The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')
那支青花 2024-07-21 09:18:46
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文