tags:

views:

114

answers:

4

whats the reason to use the variable the self._age? A similar name that doesn't link to the already used self.age?

class newprops(object):
    def getage(self):
        return 40
    def setage(self, value):
        self._age = value
    age = property(getage, setage, None, None)
+1  A: 

What you wrote would never be written in python. Often times, though, there are actions that need to be performed when saving a property (such as serialization), and this can be transparently cached in a property.

Since the protocol for calling a property and accessing a member are the same, the python style is to wait as long as possible to turn member variables into properties.

Mike Axiak
+4  A: 

self.age is already occupied by the property, you need to give another name to the actual variable, which is _age here.

BTW, since Python 2.6, you could write this with decorators:

def newprops(object):

    @property
    def age(self):
        return 40

    @age.setter
    def age(self, value):
        self._age = value
KennyTM
Using a name starting with an underscore has another advantage: It's the commonly recognized naming convention for "private" (= "don't touch unless you must") things.
delnan
And using a name starting with a double underscore is the commonly recognised convention for "really private". In one of Python's nastier warts, double-underscore names are mangled so that you can't even call them unless you hack the mangling yourself!
katrielalex
@delnan: I'd rather say it's the convention for "protected", and overly-cautious programmers use the pseudo-private name mangling feature to somewhat simulate "private" variables.
AndiDog
A: 

Your example is actually nonsense because the getter returns a constant. A separate underscore-named variable in usually used in conjunction with properties, which can be

1) read-only

class C(object):
    @property
    def age(self):
        return self._age

In this case, instance.age can only be read but not assigned to. The convention is to write to self._age internally.

2) read-write

class C(object):
    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
       assert value >= 0
       self._age = value

Having getter and setter only makes sense if you have to do extra calculations or checks when assigning the value. If not, you could simply declare the variable without the underscore, as properties and instance variables are accessed in the same way (in terms of code). That's why _age and the property age of course must be named differently.

AndiDog
correct! Thanks. I'm going through this book, and that was the example...I was like WTF, where did this come from?
shawn
in the first example, `instance.age` can certainly be assigned to. Try `instance.age = sqlite3.connect(':memory:')`. because it doesn't define a `__set__`, any assignment goes straight into the instances `__dict__` and future attempts to access the descriptor go straight to `__dict__`.
aaronasterling
if you want a read-only property, define `__set__` to `raise AttributeError`
aaronasterling
@AaronMcSmooth: Sorry, that's not true. You certain forgot to derive from `object` when trying out the code ;). Assigning to a read-only property will raise "AttributeError: can't set attribute".
AndiDog
@AndiDog. My bad. I didn't try the code (`object` is a moot point. descriptors only work on new style classes). `propery` must be setting `__set__` to `raise AttributeError` automagically. My comments apply to manually created descriptors.
aaronasterling
+1  A: 

Some object oriented languages have what is called private attributes, which cannot be accessed from outside the class methods. This is important because some attributes are not meant to be changed directly, instead, they are meant to be changed as a function of something else, or validated before they are changed. In Python you don't have private attributes, but you can implement something similar by using getters and setters to a variable which starts with underscore - Python's convention for private methods and attributes.

For instance. The hypotenuse of a rectangular triangle is given by h=sqrt(a*a+b*b), so you cannot change h directly because the relationship must hold. Also, say that a name must me in the format LASTNAME COMMA FIRSTNAME, then you have to verify that this is the case before you assign self.lastname.

The property getter allows you to get the hypotenuse, but forbids you from setting it. The property setter allows you to set a property but you can make checks before actually setting the property.

So:

class Person(object)
 def __init__(self):
  # The actual attribute is _name
  self._name = None
 @property
 def name(self):
  # when I ask for the name, I mean to get _name
  return self._name
 @name.setter
 def name(self, value):
  # before setting name I can ensure that it has the right format
  if regex_name.match(value):
   # assume you have a regular expression to check for the name
   self._name = value
  else:
   raise ValueError('invalid name')

Another example:

class Triangle(object):
 def __init__(self, a, b):
  # here a and b do not need to be private because
  # we can change them at will. However, you could
  # make them private and ensure that they are floats
  # when they are changed
  self.a = a 
  self.b = b
 @property
 def h(self):
  return math.sqrt(a*a+b*b)
 # notice there is no h.setter - you cannot set h directly
Arrieta