Getattr加载模块而不是类

时间:2018-09-11 09:12:21

标签: python python-3.x

当我尝试使用 getattr 动态加载类时,我得到了一个模块类,而不是我的真实类。

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

我的dog_input类:

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"

我有以下软件包:

  • bigpackage(程序包)

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

1 个答案:

答案 0 :(得分:0)

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

这为您提供了最大的灵活性,但限制了用户可以执行的操作。如果将来需要更改代码并且用户是外部的,则是理想的选择。请注意,您可以动态构建映射,例如通过装饰器或entry_points注册类。