如何创建带有动态子属性的@property?

时间:2018-09-28 08:06:44

标签: python

我有一个Tariff类,其中包含数量和一些价格:

class Tariff():
    quantity = 0
    item_1_price = 250
    item_1_selected = False
    item_2_price = 350
    item_2_selected = False
    item_3_price = 165
    item_3_selected = False

    @property
    def total(self):
        return sum([
            self.item_1_price * self.item_1_selected,
            self.item_2_price * self.item_2_selected,
            self.item_3_price * self.item_3_selected,
            ]) * self.quantity

我可以这样使用它:

purchase = Tariff()
purchase.quantity = 2
purchase.item_1_selected = True
purchase.item_2_selected = True
print(purchase.total)
> 1200

我想要一个函数,该函数可以告诉我单个项目的总数。 例如:

print(purchase.totals.item_1)
> 500

解决此问题的最佳方法是什么?这可能/容易吗?

2 个答案:

答案 0 :(得分:1)

一种简单的方法是:

@property
def total(self):
    return dict(
        sum=sum([ self.item_1_price * self.item_1_selected,
                  self.item_2_price * self.item_2_selected,
                  self.item_3_price * self.item_3_selected,
                ]) * self.quantity,
        item_1=item_1_price,
        item_2=item_2_price,
        item_3=item_3_price)

这将返回一个包含所有所需信息的字典。但是,要访问字典中的元素,您将需要使用索引语法:

print(purchase.totals['item_1'])
> 500

如果您可以忍受,这就是我想要的。

如果需要具有属性,则需要创建一个包含这些属性的对象(或至少伪造它们)。看看collections.namedtuple

Totals = collections.namedtuple('total',
                                ['item_1', 'item_2', 'item_3', 'sum'])
return Totals(sum=sum([ self.item_1_price * self.item_1_selected,
                        self.item_2_price * self.item_2_selected,
                        self.item_3_price * self.item_3_selected,
                     ]) * self.quantity,
              item_1=item_1_price,
              item_2=item_2_price,
              item_3=item_3_price)

然后您可以使用:

print(purchase.totals.item_1)
> 500

答案 1 :(得分:1)

您可以创建一个descriptor class并返回一个int的子类,并重写__getattr__方法以动态获取给定单个项的总数:

class Tariff:
    quantity = 0
    item_1_price = 250
    item_1_selected = False
    item_2_price = 350
    item_2_selected = False
    item_3_price = 165
    item_3_selected = False

    class TotalProperty:
        def __get__(self, obj, objtype):
            class Total(int):
                def __getattr__(self, item):
                    return getattr(obj, item + '_price') * getattr(obj, item + '_selected') * obj.quantity

            return Total(sum([
                obj.item_1_price * obj.item_1_selected,
                obj.item_2_price * obj.item_2_selected,
                obj.item_3_price * obj.item_3_selected,
                ]) * obj.quantity)

    total = TotalProperty()

这样:

purchase = Tariff()
purchase.quantity = 2
purchase.item_1_selected = True
purchase.item_2_selected = True
print(purchase.total)
print(purchase.total.item_1)
print(purchase.total.item_2)
print(purchase.total.item_3)

将输出:

1200
500
700
0