我在模块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使用@
作为语法糖的原因,找出这种情况如此普遍的原因。