一点背景:你会注意到我的评论描述了我稍后会经历的内容。假设我有以下对象......
#!/usr/bin/python
import os
import sys
class ContainerField(object):
''' An attribute/object storage device '''
def __init__(self, field=None, value=None):
self.m_field = field
self.m_value = value
def __getattr__(self, key):
'''
What can we do here that runs the .get() command but -only- if the key
does not exist.
'''
# super(ContainerField, self).__getattr__(key)
def __call__(self):
return self.get()
def value(self):
return self.m_value
def setValue(self, value):
self.m_value = value
def _recurseSetAttr(self, attr, values):
'''Generate our attributes/objects and store them succinctly.'''
# Container
# \_Container
# \_Container
# \_Container...
for field, value in values.items():
if not hasattr(attr, field):
setattr(attr,
field,
# field type is known from model caching
ContainerField(value=value, field=field_type(field)))
fdbf = getattr(attr, field)
if isinstance(value, dict):
self._recurseSetAttr(fdbf, value)
else:
fdbf.setValue(value)
def get(self):
# Create the new object from scratch and proliferate it's
# attributes recursively. 'values' come in the form of a
# dictionary that we can then use to setattr().
# So... Create container, set value, find keys for this
# and create containers that hold the values of those keys
# and repeate...
self._recurseSetAttr(self, attr, values)
现在,在生成对象时,我可以看到类似这样的字典:{"myContainer" : { "id" : 2, "foo" : { "id" : 3, "bar" : 1 } }}
,一旦创建,就可以这样调用:myContainer.foo.id.value()
在场景中有self.m_field
告诉应用程序对象的实际数据类型。这是关于Django模型的引用,但任何python都可以应用。
作为实例化的一部分,所有容器都将具有id
(或pk
)密钥。这是强制性的。
理想情况下,我们会填充顶级属性,并且只有当用户请求其下方的属性时,我们才会根据id
值和field
类型构建它们。
最后,假设myContainer.foo.bar
属性具有外键字段类型。如果我们调用myContainer.foo.bar.newkey.value()
应用程序应该理解'newkey'属性不存在,请查询我们的django实例,将bar
属性存储为现在填充更多的Container,并返回{{1已被存入记忆的价值。
我希望它是一个简单的newkey
,但Python似乎只使用hasattr()
和默认的getattr()
(递归是真的!)。我在使None
工作时也遇到了麻烦。
在我写这篇文章时,我意识到由于依赖于try: except:
和getattr()
的递归属性设置,可能会有多复杂。任何建议都会非常感激。 - 干杯
答案 0 :(得分:1)
您可以考虑将@property装饰器与私有内部字段一起使用。这个想法是这样的:
class ContainerField(object):
def __init__(self, field=None, value=None):
self._m_field = field
self._m_value = value
@property
def m_field(self):
if self._m_field is None:
self._m_field = self.function_to_populate_m_field()
return self._m_field
@property
def m_value(self):
if self._m_value is None:
self._m_value = self.function_to_populate_m_value()
return self._m_value
...
答案 1 :(得分:1)
所以回答问题的第一部分:如果仅在未定义属性时如何调用__getattr__
self.get()
。 python类中有两个属性访问方法:__getattribute__
和__getattr__
。每次尝试进行属性查询时都会调用第一个,第二个仅在普通属性查找系统失败时调用(包括超类中的查找)。由于您定义的__getattr__
仅在属性尚未存在时调用,因此您只需将其代理为对.get
的调用即可。在遇到递归问题的情况下,如果您尝试在self
内部查找__getattr__
的另一个属性,该属性也不存在。避免这种情况的方法是获得需要特殊处理的密钥列表,并检查所请求的当前属性是否是其中之一。这通常仅在实施__getattribute__
时才需要。
请注意,您的.get
方法存在问题:attr
和values
未定义。如果我知道__getattr__
.get
和attr
想要什么值,我会在values
中给出一个更具体的答案。
答案 2 :(得分:0)
检查出来:
class Test(object):
def __init__(self):
self.a = 5
self.b = 6
def __getattr__(self, key):
return 'created a new key: {}'.format(key)
obj = Test()
print(obj.a, obj.b)
print(obj.c)
此处,您不是返回'created a new key...'
,而是创建新属性并将其返回。