如何在__init__中创建动态属性

时间:2018-03-02 19:28:03

标签: python

我有一个简单的场景。我将一个kwarg prop_nameprop_func传递到我的类init中,我希望将其转换为以下属性:

class A:
    def __init__(self, *args, prop_name=None, prop_func=None, **kwargs):
        if prop_name is not None and prop_func is not None:
            setattr(self, prop_name, property(prop_func))
        super().__init__(*args, **kwargs)

为什么我不能这样做:

a = A(prop_name='some_name', prop_func=lambda _: 1)
print(a.some_name)

结果是:

>>> <property object at 0x7feb3f27cf98>

然而,这有效:

class A:
    some_name = property(lambda _: 1)

a = A()
print(a.some_name)

>>> 1

编辑:可能的解决办法,以获得相同的行为。如果有任何实际差异,请更正。

class A:
    def __init__(self, *args, prop_name=None, prop_func=None, **kwargs):
        self._prop_name = prop_name
        self._prop_func = prop_func

    def __getattr__(self, item):
        if item == self._prop_name:
            return self._prop_func(self)  # this solution does not accept arguments
        super().__getattr__(self, item)

a = A(prop_name='some_name', prop_func=lambda _: 1)
print(a.some_name)
>>> 1

编辑2:解释为什么需要此行为解决方案。 对于django视图,此行为应该在Mixin中发生。目标是能够动态创建相关对象之间的相关视图。例如:

class Country(models.Model):
    ... some attributes ...


class City(models.Model):
    country = models.ForeignKey(Country)
    .... some attributes ...

如果直接在视图中我们可以一般性地引用City的对象,那将是非常好的:

self.parent

我已经在现在显示的Mixin中完成了这项工作,它超出了范围。但是,为了方便起见,如果我们可以将这个parent对象直接引用为字段名称本身,那就太好了,即:

self.continent # basically just calls self.parent

这使得代码非常直观易读。一个非常简化的视图示例:

class CountryDetailView(ParentMixin, DetailView):
    model = Country
    parent_model = Continent

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['continent'] = self.continent  # equivalent to self.parent
        return context

0 个答案:

没有答案