kholidfu
kholidfu

Reputation: 74

Understanding Property in Python

I want to ask about Python Property, I'm writing the code belows...

anyone can explain about my code's output and explain in simple way what is property for and when we should use it?

class C(object):
    def __init__(self):
        self.x = 'sulthan'
        self.y = 'ahnaf'
    @property
    def name(self):
        print self.x
        print self.y

Now when I run the code:

>>> c = C()
>>> c.name
sulthan
ahnaf
sulthan
ahnaf

Why it prints 2 times? Sorry for the question, I'm just noob who wants to understand python OOP...

Upvotes: 3

Views: 729

Answers (4)

wim
wim

Reputation: 362478

This is an %autocall bug in ipython. Related tickets on launchpad and github. It is apparently resolved in the current version of ipython.


The purpose of properties is to hide fancy logic behind what looks like ordinary attribute assignment/access. You should only do this when you have a design reason that makes it necessary, python is not java so writing boilerplate getters and setters on everything is not needed.

What Ignacio is trying to tell you is that there does not seem to be any reason why you have those print statements in the definition of name().

Here is a more usual implementation of your example, with properties.

class Person(object):
  def __init__(self):
    self._name = 'sulthan ahnaf'

  @property
  def name(self):
    return self._name

  @name.setter
  def name(self, value):
    self._name = value

Now you have an attribute, _name, which you can control access to by using the "attribute" name. Consenting adults will leave your _name alone because it has an underscore prepended, but note that this is nothing more than a convention.

Upvotes: 2

gfortune
gfortune

Reputation: 2609

Properties are especially useful when you want to access attributes of an object directly and need to have some extra code around getters/setters in some cases.

Imagine you have a car object.

class Car(object):
    def __init__(self, make, model, year, vin):
        self.make = make
        self.model = model
        self.year = year
        self.vin = vin


my_car = Car('Ford', 'Taurus', 2005, '123ABCVINSARELONG999')

Now imagine that I need to change the year on the car. I might do it a couple different ways.

my_car.year = 2006

my_car.year = '2007'

The second way gives me some serious problems if I'd like to assume the year is a number. See the following:

if(my_car.year > 2010):
    print('Shiney new!')

The challenge is that setting attributes directly is very clean and slick, but is not providing us an opportunity to do any data validation (maybe I want to ensure the make is in a list of known makes, for example) or data type conversion (in the year example).

Properties come to the rescue by allowing us to setup wrapper code around attribute assignment and/or retrieval but not requiring that we do that for all attributes or even requiring us to know ahead of time that we want to do some extra validation. I can, after the fact, modify my Car object as follows and it would still be used in exactly the same way.

class Car(object):
    def __init__(self, make, model, year, vin):
        self.make = make
        self.model = model
        self._year = year
        self.vin = vin

    def get_year(self):
        return self._year

    def set_year(self, val):
        self._year = int(val)

    year = property(get_year, set_year)

You still access year as my_car.year and you still set it with my_car.year = 2006, but it now converts the value into an int where necessary and throws an exception if the value provided by the user doesn't convert into an int properly.

Upvotes: 2

avasal
avasal

Reputation: 14854

It seems to a problem with ipython, if you use python prompt it shows proper output (single time)

[avasal@avasal]$ python
Python 2.7 (r27:82500, Sep 16 2010, 18:02:00) 
[GCC 4.5.1 20100907 (Red Hat 4.5.1-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class C(object):
...     def __init__(self):
...         self.x = 'sulthan'
...         self.y = 'ahnaf'
...     @property
...     def name(self):
...         print self.x
...         print self.y
... 
>>> c1 = C()
>>> c1.name
sulthan
ahnaf
>>> 
[avasal@avasal]$ ipython 
Python 2.7 (r27:82500, Sep 16 2010, 18:02:00) 
Type "copyright", "credits" or "license" for more information.

IPython 0.10.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object'. ?object also works, ?? prints more.

In [1]: class C(object):
   ...:         def __init__(self):
   ...:             self.x = 'sulthan'
   ...:         self.y = 'ahnaf'
   ...:     @property
   ...:     def name(self):
   ...:             print self.x
   ...:         print self.y
   ...: 

In [2]: c1 = C()

In [3]: c1.name
sulthan
ahnaf
sulthan
ahnaf

In [4]:

Upvotes: 3

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798456

You use properties when you want to be able to change how an attribute assignment or access behaves without having to change how you do it. It certainly isn't for the purpose of running random/arbitrary statements for no reason.

Upvotes: 0

Related Questions