如何使用 python 的 __import__() 和 getattr() 正确实例化嵌套的 类?

How does one use python's __import__() and getattr() to correctly to instantiate nested classes?

我在模块 xyz 中有以下代码:

Class Outer:
   Class Nested:
       pass

我可以成功实例化Outer个对象如下

module = __import__("xyz", fromlist=[''])
the_class = getattr(module, "Outer")
instance = the_class()

但是,当我将 "Outer" 替换为 "Outer.Nested" 时,我得到:

AttributeError: module 'xyz' has no attribute Outer.Nested

如何使这项工作成功?

我或许应该澄清一下,上面的代码用于实例化 类,其类型在运行时是未知的。显然我不是在寻找 instance = Outer.Nested().

有两种方法,假设您有一个表示属性访问的字符串和一个嵌套对象:

>>> from types import SimpleNamespace
>>> module = SimpleNamespace(foo=SimpleNamespace(bar=SimpleNamespace(baz='tada!')))
>>> module
namespace(foo=namespace(bar=namespace(baz='tada!')))

首先是通过拆分并在循环中使用 getattr(甚至 reduce!)来基本上自己解析字符串:

>>> from functools import reduce
>>> reduce(getattr, "foo.bar.baz".split('.'), module)
'tada!'

相当于:

>>> result = module
>>> for attr in "foo.bar.baz".split("."):
...     result = getattr(result, attr)
...
>>> result
'tada!'

或者一次性使用内置的functools.attrgetter工厂函数:

>>> import operator
>>> operator.attrgetter("foo.bar.baz")(module)
'tada!'

以@juanpa.arrivillaga的回答为基础(但解释原因):

类 并且模块在 Python 中被视为对象。所以当你在模块中声明一个class时,class是模块的一个属性;当您声明一个内部 class 时,内部 class 是外部 class 属性 ,但不是 的属性模块。当您将 "Outer.Nested" 交给模块的 getattr 时,您正在请求模块的 属性 ,其中有一个 . 在属性名称中。与属性的属性不太一样。 Python 的解释器在解析时会执行“属性的属性”,因此您会感到困惑。

I should perhaps clarify that the above code is being used to instantiate classes whose type is unknown until runtime. Obviously I am not looking for instance = Outer.Nested(). do you mean that the name is not known until runtime? All types in Python are determined at runtime anyway.

如果是这样,您也可以做一个花哨但常见的技巧,即调用者可以在 运行 时间提交类型。

# xyz.py
def get_instance(the_class):
  return the_class()
# unknown_third_party
Class Outer:
   Class Nested:
       pass
# main.py
from xyz import get_instance
import unknown_third_party
instance = get_instance(unknown_third_party.Outer.Nested)

您永远不需要知道将您的代码提交给 运行 的内容——这由您的 user/customer 和 运行 时间决定。

研究 Python 对 @ 语法糖的使用,以找出这种情况如此普遍的原因。