当我尝试使用 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(程序包)
答案 0 :(得分:0)
TLDR:您只加载模块,而不加载所包含的类。
请注意,包和模块大多只是Python的任意命名空间。没有一个类到其包含的模块的强映射。让模块dog_input
实现类DogInput
不会使另一个成为别名-DogInput
是dog_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注册类。