Using properties

T

tkpmep

I have a class with a name attribute, which I want to modify using
property.The following code works just fine:

class Portfolio(object):

def __init__( self, name="Port1"):
self.name=name

def getname(self):
return self._name

def setname(self,newname="Port2"):
self._name=newname

name=property(getname,setname,None,None)

However, it no longer works if I modify getname and setname to

def getname(self):
return self.name

def setname(self,newname="Port2"):
self.name=newname

Why is it so critical to have getname and setname modify _name and not
name? The constructor does not make name a private attribute, so why do
getname and setname have to treat it as such?

Thomas Philips
 
T

Terry Reedy

I have a class with a name attribute, which I want to modify using
property.The following code works just fine:

class Portfolio(object):

def __init__( self, name="Port1"):
self.name=name

def getname(self):
return self._name

def setname(self,newname="Port2"):
self._name=newname

name=property(getname,setname,None,None)

However, it no longer works if I modify getname and setname to

What does 'no longer works' mean? Do you get and exception and traceback?
If so, what?
def getname(self):
return self.name
def setname(self,newname="Port2"):
self.name=newname

These both look like infinite loops. Did you got the related exceptions?
Why is it so critical to have getname and setname modify _name and not
name? The constructor does not make name a private attribute, so why do
getname and setname have to treat it as such?

I believe because getting and setting name calls getname and setname. The
initializer (not constructor) setting of name results in a call to setname.

Terry J. Reedy
 
L

Leif K-Brooks

name=property(getname,setname,None,None)

However, it no longer works if I modify getname and setname to

def getname(self):
return self.name

def setname(self,newname="Port2"):
self.name=newname

That's because you're actually modifying the property in setname instead
of modifying the normal attribute. It's equivalent to doing:

def setname(self, newname="Port2"):
self.setname(newname)
 
B

bruno modulix

I have a class with a name attribute, which I want to modify using
property.The following code works just fine:

class Portfolio(object):

def __init__( self, name="Port1"):
self.name=name

This may not do what you think it does (see below)
def getname(self):
return self._name
def setname(self,newname="Port2"):
self._name=newname

name=property(getname,setname,None,None)

However, it no longer works if I modify getname and setname to

def getname(self):
return self.name

def setname(self,newname="Port2"):

what's the use of putting a default value here ?
self.name=newname

How could this work, since self.name is now a property object that calls
on setname() and getname() ?
Why is it so critical to have getname and setname modify _name and not
name?

because 'name' is how you named your property...
The constructor does not make name a private attribute,

Note that there is in fact no notion of private/public in Python (I mean
: in the language). The underscore stuff is nothing more than a convention.

Now you don't seem to understand what happens when __init__ is called.
Try this:

8<------------------------------------------------
class Portfolio(object):

def __init__( self, name="Port1"):
self.name=name
print "self._name is %s" % self._name
print "self.__class__.name is %s" % self.__class__.name

def _getname(self):
print "in getname"
return self._name

def _setname(self, newname):
print "in setname"
try:
print "self._name is %s" % self._name
except AttributeError, e:
print "got AttributeError %s" % e
print "when trying to access self._name"
self._name=newname

name=property(fget=_getname, fset=_setname)
print "in Portfolio class definition : name is %s" % name

p = Portfolio()
8<------------------------------------------------

As you can see, the 'name=property(...)' statement at the end of your
class definition is executed when the class definition is first eval'd
(this is when the code is loaded in the interpreter). So when __init__
is called, the statement 'self.name = name' does not create an instance
variable 'name', but calls the existing property, which in turn creates
the instance variable '_name'.
so why do
getname and setname have to treat it as such?

From a technical POV, we don't care if the attribute accessed by a
property is 'private' or whatever. The only thing is that it can't have
the same name as the property...

From a conceptual POV, it makes no sense (well, IMHO) to use a property
for a 'public' (by convention...) attribute. Either you want a property
(think : a computed attribute) and then you hide the implementation
details, or you're ok with a plain old 'public' attribute and then you
don't use a property.

BTW, this is also true of the setter and getter used by the property:
they are implementation details, and as such should not be exposed as
part of the interface.

HTH
 
T

tkpmep

Thanks for the help. I now understand it better. As Bruno points out, I
really don't need a property in this case, as my attribute is public,
and I will remove it.

Thomas Philips
 
T

Terry Reedy

Thanks for the help. I now understand it better. As Bruno points out, I
really don't need a property in this case, as my attribute is public,
and I will remove it.

As much to the point is that your name attribute is static in the sense of
being a fixed object between settings. Should you later want to make it
dynamic (or perhaps lazy) in the sense of being computed on demand, then
you can do so with property() *without* changing the external interface to
the class.

A third reason for property() is when you want to do something in addition
to the access, such as reporting the access to something else.

Terry J. Reedy
 
A

alex23

Thanks for the help. I now understand it better. As Bruno points out, I
really don't need a property in this case, as my attribute is public,
and I will remove it.

Should you need it to be a property at a latter date, it's worth noting
that you can achieve what you were initially after by wrapping the
property's get/set around the objects '__dict__' attribute:

def getname(self): return self.__dict__['name']
def setname(self): self.__dict__['name'] =newname

Hope this helps.

-alex23
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,240
Messages
2,571,205
Members
47,843
Latest member
eicamotu

Latest Threads

Top