Python 递归 __getattribute__
我需要实现这样的功能:
obj.attr1.attr2.attr3 --> obj.attr1__attr2__attr3
看起来我需要重写对象的类中的 __getattribute__
方法,并且还要以某种方式使用 Python 的描述符。
更新:
我正在做一个 Django 项目。
obj 是 django-haystack 的 SearchResult 实例,它包含了很多来自 Django 模型的去规范化数据(比如 user__name
和 user__address
),我需要以 result.user.name
的方式来访问这些数据,以保持兼容性。
针对 THC4k 的回答的更新:
如果我有:
class Target(object):
attr1 = 1
attr1__attr2__attr3 = 5
>>> proxy.attr1
1
>>> proxy.attr1.attr2.attr3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'attr2'
任何帮助都将非常感谢。
3 个回答
0
class A:
def __init__(self, a):
self.a = a
# create objects with many a atributes..
a = A(A(A(A('a'))))
x = a
# as long as a has atribute a continue...
while hasattr(x, 'a'):
print x
x = x.a
当然可以!请把你想要翻译的内容发给我,我会帮你把它变得更简单易懂。
3
我希望你知道自己在做什么,而不是仅仅想通过这种方式来 逃避修复你现有的代码。
我觉得这样做是有合理理由的,毕竟我在Lua中也做过类似的事情,目的是为了给一些C代码做一个包装,而不需要为每个暴露出来的函数都写代码。
不过,你至少应该把实际的类和代理分开:
# the proxy maps attribute access to another object
class GetattrProxy(object):
def __init__(self, proxied, prefix=None):
self.proxied = proxied
self.prefix = prefix
def __getattr__(self, key):
attr = (key if self.prefix is None else self.prefix + '__' + key)
try:
# if the proxied object has the attr return it
return getattr(self.proxied, attr)
except AttributeError:
# else just return another proxy
return GetattrProxy(self.proxied, attr)
# the thing you want to wrap
class Target(object):
attr1__attr2__attr3 = 5
t = Target()
proxy = GetattrProxy(t)
print proxy.attr1.attr2.attr3
@katrielalex的建议:
class GetattrProxy2(GetattrProxy):
def __getattr__(self, key):
attr = (key if self.prefix is None else self.prefix + '__' + key)
proxy = GetattrProxy2(self.proxied, attr)
# store val only if the proxied object has the attribute,
# this way we still get AttributeErrors on nonexisting items
if hasattr(self.proxied, attr):
proxy.val = getattr(self.proxied, attr)
return proxy
proxy = GetattrProxy2(t)
proxy.attr1.val # 1
proxy.attr1.attr2.attr3.val # 5
proxy.attr1.attr2.val # raise AttributeError
4
如果你有一系列属性名称,可以使用 itertools()
函数(在 Python 3.x 中用 functools.reduce()
)和内置的 getattr()
函数来处理这些属性:
下面是一个例子:
In [1]: class A:
...: def __init__(self):
...: self.a1 = B()
...:
In [2]: class B:
...: def __init__(self):
...: self.b1 = C()
...:
In [3]: class C:
...: def __init__(self):
...: self.c1 = 7
...:
In [4]: from functools import reduce
In [5]: reduce(getattr, [A(), 'a1', 'b1', 'c1'])
Out[5]: 7