cool77
cool77

Reputation: 1136

property() returns different values

I am trying to fill the gap in my understanding of Pythons property(). Below is the code that I have come up with, to understand property():

class Temperature:
    def __init__(self, temp = 10):
        self.set_temp(temp)

    def to_farenheit(self):
        return (self._temp * 1.8) + 32

    def get_temp(self):
        print "getting temperature value"
        return self._temp

    def set_temp(self, temp):
        print "setting temperature value"

        if temp < -237:
            raise ValueError("this shud be above -273")
        else:
            self._temp = temp

    temps = property(get_temp, set_temp)

I execute the above class and do the following:

>>> t = Temperature()
setting temperature value

>>> t.temps
getting temperature value
10

>>> t.temps = 13

>>> t.temps
13
>>> t.get_temp()
getting temperature value
10
>>> 

As you can see above, when I try to set temp value by assigning t.temps = 13 the set_temp() function is not getting called which I was expecting would be called because of property() functionality. Also I am ending up with 2 different values for variable temp

What am I missing?

Upvotes: 3

Views: 83

Answers (3)

Josh K
Josh K

Reputation: 28893

Use new-style classes which leverages descriptors for properties.

class Temperature(object):
    def __init__(self, temp=10):
        self.temps = temp

    def to_farenheit(self):
        return (self._temp * 1.8) + 32

    def get_temp(self):
        print "getting temperature value"
        return self._temp

    def set_temp(self, temp):
        print "setting temperature value"

        if temp < -237:
            raise ValueError("this shud be above -273")
        else:
            self._temp = temp

    temps = property(get_temp, set_temp)

This gives you the “right” behavior.

In [30]: t = Temperature()
setting temperature value

In [31]: t.temps
getting temperature value
Out[31]: 10

In [32]: t.temps = 100
setting temperature value

In [33]: t.temps
getting temperature value
Out[33]: 100

In [34]: t.__dict__
Out[34]: {'_temp': 100}

Upvotes: 1

MSeifert
MSeifert

Reputation: 152820

It's simply because you use Python 2 and forgot to subclass object. In your case property simply doesn't work because it's an old-style class.

Better you subclass object:

class Temperature(object):
    ...

Or even better: Use Python 3. Python 3 doesn't have old-style classes anymore and you can omit the (object) part because it's implicit.

However you really shouldn't define get_temp or set_temp functions when you could use the decorator syntax. And you definitely shouldn't call them directly.

This would be much more pythonic:

class Temperature(object):
    def __init__(self, temp = 10):
        self.temps = temp

    def to_farenheit(self):
        return (self._temp * 1.8) + 32

    @property
    def temps(self):
        print("getting temperature value")
        return self._temp

    @temps.setter
    def temps(self, temp):
        print("setting temperature value")
        if temp < -237:
            raise ValueError("this shud be above -273")
        else:
            self._temp = temp

That example will work on Python 2 and Python 3.

Upvotes: 8

Aran-Fey
Aran-Fey

Reputation: 43306

This problem only occurs in python 2.

From the docs:

class property([fget[, fset[, fdel[, doc]]]])

Return a property attribute for new-style classes (classes that derive from object).

(Emphasis mine.)

If you make Temperature a new-style class by inheriting from object, the property will work as expected.

Upvotes: 1

Related Questions