如果attr不存在,则Python getattr\uuu创建attr并返回i

2024-03-29 12:29:59 发布

您现在位置:Python中文网/ 问答频道 /正文

一点背景:你会注意到我的评论描述了我以后要经历的事情。假设我有以下对象。。。在

#!/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)

现在,当生成对象时,我可以有一个dict,它看起来像这样:{"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属性存储为现在更填充的容器,并返回已放入内存的newkey值。在

Python陷阱

我希望它是一个简单的hasattr(),但是Python似乎只是将getattr()与默认的None一起使用(递归是真实的!)。我也有很多麻烦让一个try: except:工作。在

当我写这篇文章时,我意识到由于依赖于getattr()hasattr()的递归属性设置,它可能会变得更加复杂,任何建议都将不胜感激。-干杯


Tags: andtheselfidfield属性foovalue
3条回答

看看这个:

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...',而是创建一个新属性并返回它。在

您可以考虑将@property decorator用于私有内部字段。这个想法应该是:

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

    ...

所以要回答问题的第一部分:如何在属性尚未定义的情况下,__getattr__调用{}。python类中有两种属性访问方法:__getattribute__和{}。第一个在每次尝试属性查找时调用,第二个仅在常规属性查找系统失败(包括超类中的查找)时调用。因为您定义的是__getattr__,它只在属性不存在时调用,所以您可以简单地将其代理为对.get的调用。如果您试图查找self的另一个属性,self的另一个属性,__getattr__内部也不存在该属性。避免这种情况的方法是有一个需要特殊处理的键列表,并检查当前请求的属性是否是其中之一。这通常只在实现__getattribute__时需要。在

请注意,.get方法有一个问题:attr和{}未定义。如果我知道.getattr和{}需要什么值,我会给出一个更具体的答案。在

相关问题 更多 >