Getattr加载模块而不是类

2024-09-29 22:29:56 发布

您现在位置:Python中文网/ 问答频道 /正文

当我尝试使用getattr动态加载类时,我得到的是一个模块类而不是真正的类。你知道吗

module = importlib.import_module("bigpackage.animals")
class_ = getattr(module, "dog_input")
pprint(type(class_))
# Outputs <class 'module'>

我的狗输入类:

from bigpackage.animals.animal import AbstractAnimal

class DogInput(AbstractAnimal):

    def __init__(self):
        self.b = "bb"

    @property
    def name(self):
        prefix = super(DogInput, self).name
        return prefix + "Name"

我有以下套餐:

  • 大包装(package)

    • 动物(包装)
      • 抽象动物(类)
      • 狗输入(类)
      • 初始化
    • 初始化
    • 我(尝试)动态加载类的服务器(类)

Tags: 模块nameimportselfprefixdef动态class
1条回答
网友
1楼 · 发布于 2024-09-29 22:29:56

TLDR:您只加载模块,而不是所包含的类。你知道吗


请注意,对于Python来说,包和模块大多只是任意的名称空间。类与其包含的模块之间没有强映射。让一个模块dog_input实现类DogInput不会使一个成为另一个的别名DogInputdog_input的常规成员,后者可能包含任意其他类和值。你知道吗


当您知道类位于何处时,最简单的方法是导入模块,然后从中获取类:

module = importlib.import_module("bigpackage.animals.dog_input")
class_ = getattr(module, "DogInput")
print(class_)

如果只有类名,但有一致的命名方案,则可以从类名中提取模块名。看这个question on converting CamelCase to lower-case-with-underscores。你知道吗

submodule_name = convert("DogInput")
module = importlib.import_module("bigpackage.animals.%s" % submodule_name)
class_ = getattr(module, "DogInput")
print(class_)

注意,在Python中,这通常是不受欢迎的。您隐式地依赖于每一个知道您的命名约定的维护人员——至少可以说,这很容易打破。你知道吗


你也可以让人们提供一个限定名dog_input.DogInput,而不是仅仅DogInput。这取决于您允许多少嵌套(模块和/或内容),从简单到非常复杂。你知道吗

# relative module.class
qname = "dog_input.DogInput"
# add the module part to the import
module = importlib.import_module("bigpackage.animals.%s" % qname('.')[0])
# fetch the class part from the module
class_ = getattr(module, qname('.')[1])
print(class_)

这是一种非常强大但也很脆弱的方法。如果输入来自信任的、有经验的、需要很大灵活性的用户,就可以使用它。因为它可能允许执行任意代码,所以不要将其用于公共服务。你知道吗


如果存在一组固定的/已知的允许类,则最容易显式地对它们进行索引。这为您提供了实现灵活性和安全性。你知道吗

# bigpackage.animals
from dog_input import DogImport

# mapping from identifier to class
ANIMALS = {'DogImport': DogImport}

# bigpackage.server
from bigpackage.animals import ANIMALS
class_ = ANIMALS['DogImport']
print(class_)

这为您提供了最大的灵活性,但限制了用户可以做什么。如果将来需要更改代码,并且用户是外部的,那么它是理想的。注意,可以动态地构建映射,例如通过decorator或entry_points注册类。你知道吗

相关问题 更多 >

    热门问题