Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Gabriel Nunes
Gabriel Nunes
6,161 Points

Logic flaw into the Object code

Hi, first of all, I already got the green badge and continued on the course, but I really do not understand what is happening here.

greenbadge_answer.py
class Product:
    _price = 0.0
    tax_rate = 0.12

    def __init__(self, base_price):
        self._price = base_price

    @property
    def price(self):
        return self._price + (self._price * self.tax_rate)

    @price.setter
    def price(self, new_price):
        self._price = new_price

I refactored some of the variable names, and the calculation of the property to make it more explicit.

refactored_greenbadge_answer.py
class Product:
    _price_without_taxes = 0.0
    tax_rate = 0.12

    def __init__(self, base_price):
        self._price_without_taxes = base_price

    @property
    def price_with_taxes(self):
        return self._price_without_taxes * (1 + self.tax_rate)

    @price_with_taxes.setter
    def price_with_taxes(self, new_price):
        self._price_without_taxes = new_price

On my understand the setter method is used to change directly the value of a protected attribute, but it must maintain the logic of the Object, just as on the example of the Circle class, setting the radius to 5 must change the diameter to 10.

On this challenge the answer that is accepted as correct gives me some really strange behavior when run at the workspaces:

That is the expected behavior for the Product object:

behavior.py
prod = Product(100) # should create an object with the following properties 
prod._price_without_taxes = 100 
prod.price_with_taxes = 112

Then when we use the setter method:

setter_expected_behavior.py
prod.price_with_taxes = 224  # should update the property to this
prod._price_without_taxes = 200

With the answer that triggers the green sign the behavior is the following, when using the setter method:

pass_codetest_behavior.py
prod.price_with_taxes = 224  # which set the prod._price_without_taxes to 224
prod.prices_with_taxes = 250.88   # dynamically set
prod.price_without_taxes = 224

This occurs because the setter will not really set the value of the attribute, but run some code that allows us to change the generator value of this protected attribute.

correct_logic.py
    @price_with_taxes.setter
    def price_with_taxes(self, new_price):
        self._price_without_taxes = new_price / 1 - self.tax_rate

Please give me some insight!

Thanks

2 Answers

Michael Hulet
Michael Hulet
47,912 Points

Before I start, I wanna say that I like your version of this code better than the challenge's. It's far clearer to me to have separate properties for the price before tax, the tax rate, and the price after tax is calculated. I think doing that is far clearer than what the challenge's code does, which is have the price property represent 2 different things depending on if you're getting or setting it.

In the challenge's code, when you set the price, you're directly setting the price of the Product, without any calculation done to account for tax. However, when you get the price, it gives you back the value after adding tax. In other words, price represents the price before tax when you set it, but it represents the price after tax when you get it. I don't like this because if you set the value of price and then immediately get it on the next line, it'll be a different value than when you set it, which is really confusing imo.

I like what your idea idea better, where you maintain a separate property for price before and after tax (though I think you have a mathematical error in your implementation of your setter):

class Product:
    price_without_tax = 0.0
    tax_rate = 0.12

    def __init__(self, base_price):
        self.price_without_tax = base_price

    @property
    def price_with_tax(self):
        return self.price_without_tax * (1 + self.tax_rate)

    @price_with_tax.setter
    def price_with_tax(self, new_price):
        self.price_without_tax = new_price * (1 - self.tax_rate)
Gabriel Nunes
Gabriel Nunes
6,161 Points

Hi Michael,

I indeed get an error on my code, but I mistyped the minus sign, it should be a plus.

math.py
x: price without taxes
y: price with taxes
t: taxes

y = x + x*t
y = x * (1+t)
x = y / (1+t)

I understand now that what the Challenge asks is really for you to mess with the logic of the object, diferently than the circle example used on the video, where it keeps the logic intact.

Thank you