通过字符串查找解决全局命名空间中的Python对象

3 投票
3 回答
1146 浏览
提问于 2025-04-17 18:01

假设你想要获取一串对象名称最后的那个对象:比如有一个字符串 'first_class.second_class.third_class.id',而所有的字符串都像这样 'X1object.X2object...XNobject.what_you_want_is_here_object'

在每种情况下,你都知道有一个活跃的 X1object 实例,不管它具体叫什么。以这个例子为例,代码已经调用了 first_class 的一个实例。你可以用 globals['first_class'] 来加载 first_class,而用 globals['X1object'] 来通用地加载 X1object

你想要的是字符串最后的那个对象(通常是一个值)。所以在这个例子中,你想要的值是 id = first_class.second_class.third_class.id。有没有简单的方法可以把这个字符串转换成可以获取最后那个对象的形式呢?

下面是我为了解决这个问题而写的代码,但看起来像是一种蛮力的方法,它逐个获取每个属性,直到找到最后一个。

first_class = FirstClass()
first_class = go_do_something_wild_in_first_class(first_class)
...

attribute = 'first_class.second_class.third_class.id'
attribute_pieces = attribute.split('.')

fetch_attribute = lambda attribute, name: \
    attribute[name] if attribute == globals() else \
    getattr(attribute, name)

for name in attribute_pieces: # I changed the code from using an index to using a name
    if name == attribute_pieces[0]:
        attribute = fetch_attribute(globals(), name)
    else:
        attribute = fetch_attribute(attribute, name)

id = attribute

3 个回答

1

你应该使用 importlib 这个库。

attribute = 'first_class.second_class.third_class.id'
attribute_pieces = attribute.split('.')

id = getattr(importlib.import_module('.'.join(attribute_pieces[:-1]), attribute_pieces[-1])
1

有一个叫做zope.dottedname的Python库,正好可以满足你的需求:

https://pypi.python.org/pypi/zope.dottedname

这个库可以把任意的字符串转换成Python中的对应对象,包括对象的属性。

4

你可以使用 reduce() 函数:

def resolve_object(name):
    names = name.split('.')
    return reduce(getattr, names[1:], globals()[names[0]])

这里我们首先把 names[0] 当作一个全局变量,然后对其余的名字进行循环,逐个用 getattr 来处理目前的结果。

示例:

>>> class Foo(object): pass
... 
>>> first_class = Foo()
>>> first_class.second_class = Foo()
>>> first_class.second_class.third_class = Foo
>>> first_class.second_class.third_class.id = 'baz'
>>> resolve_object('first_class.second_class.third_class.id')
'baz'

撰写回答