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