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



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

Class Outer:
Class Nested:
pass

我可以成功实例化Outer对象,如下所示

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

然而,当我用"Outer.Nested"代替"Outer"时,我得到:

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中被视为对象。因此,当你在模块中声明一个类时,该类是该模块的属性;当你声明一个内部类时,内部类是外部类属性,而不是模块的属性。当您将"Outer.Nested"交给模块的getattr时,您正在请求模块属性,因此在属性的名称中有.。这和属性的属性不太一样。Python的解释器会处理一个属性的属性。当它在解析时,这就是为什么你会感到困惑。

By

我也许应该澄清一下,上面的代码是用来实例化那些直到运行时才知道类型的类的。显然,我不是在寻找instance = Outer.Nested()。您的意思是直到运行时才知道名称吗?Python中所有类型都是在运行时确定的。

如果是这样,你可以选择一个奇特的,但常见的技巧,调用者可以在运行时提交类型。

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

你永远不需要知道你的代码运行时提交了什么——这是由你的用户/客户在运行时决定的。

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

相关内容

  • 没有找到相关文章

最新更新