1

I have a class, Tariff, with a quantity and some prices:

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 

I can use it as such:

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

I want a function that will tell me the total of an individual item. For example:

print(purchase.totals.item_1) > 500 

What is the best way of going around this? Is this possible/easy?

7
  • 2
    One time you wrote total (singular), the other time you wrote totals (plural). Are these supposed to be the same property, or two separate properties? Commented Sep 28, 2018 at 8:08
  • @Aran-Fey one is the overall total, one is meant to be an attribute with all the subtotals as sub-attributes Commented Sep 28, 2018 at 8:51
  • Note also that you probably shouldn't have this data structure. Why not making an Item a namedtuple (or a class itself) and have a list of items instead? Commented Sep 28, 2018 at 8:52
  • @AdamSmith This is a simplification of something I'm doing with sqlalchemy, so the tariff object is actually a sqlalchemy model Commented Sep 28, 2018 at 8:54
  • @user1518321 I can't imagine any underlying data structure where this is the proper model, is all. Commented Sep 28, 2018 at 8:56

2 Answers 2

1

You can create a descriptor class that returns a subclass of int with the __getattr__ method overridden to obtain the total of a given individual item on the fly:

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() 

so that:

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) 

would output:

1200 500 700 0 
Sign up to request clarification or add additional context in comments.

Comments

1

A straight-forward way of doing it would be:

@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) 

Then this would return a dictionary containing all wanted information. To access the elements in the dict you would need to use the indexing syntax, though:

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

If you can live with this, this is what I would go for.

If you need to have attributes, you would need to create an object which contains these attributes (or at least fakes them). Have a look at collections.namedtuple for this:

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) 

Then you could use:

print(purchase.totals.item_1) > 500 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.