[Tutor] Good approach regarding classes attributes

Danny Yoo dyoo at hashcollision.org
Mon Sep 8 06:01:51 CEST 2014


>>>> @property
>>>> def _avatar(self):
>>>> return self._avatar
>>
>> Hi Joel,
>>
>> The above code looks strange to me.  The method and the field name
>> should not use the same name.
>
> ah! good catch Danny.  I didn't write it, I was commenting on the OP code.
>
> But (and maybe this was discussed earlier in the thread), what value
> is using the property decorator instead of just saving the data to
> attributes?


Let's first point to documentation that says what "property" is:

   https://docs.python.org/2/library/functions.html#property

If you read it a bit, one of the key terms that should come up is
"managed attribute".

What do they mean by this?

A managed attribute is an attribute that the class's definition
actively controls.

Let's use a concrete example: say that we'd like to make sure a
Person's name is always capitalized.  We might try to enforce this
capitalization property in the constructor.

###############################
class Person(object):
    def __init__(self, name):
        self.name = name.title()
    def greet(self):
        print("Hi, I'm %s" % self.name)

p = Person("joel goldstick")
p.greet()
###############################

However, this does not stop clients from assigning directly to the name,

#####################
p.name = "joel goldstick"
#####################

and therefore breaking a desire to keep the name capitalized.  So this
might be a problem.

So what we'd like is the following: to make sure that there's some
kind of program logic that kicks in whenever we assign to Person.name.

In some programming languages, we do this by marking the attribute
name in some way that makes it clear not to access it directly, and we
provide "setter" and "getter" methods, the code that can "manage" this
attribute.

#############################
class Person(object):
    def __init__(self, name):
        self._name = name.title()

    def getName(self):
        return self._name

    def setName(self, name):
        self._name = name.title()

    def greet(self):
        print("Hi, I'm %s" % self._name)

## client code:
p = Person("joel goldstick")
print(p.getName())
p.greet()

p.setName("juan christian")
print(p.getName())
p.greet()
#############################


Python allows us to get "setter" and "getter"-like behavior while
still allowing client code to use the attribute with what looks like
direct attribute access:

#################################
class Person(object):
    def __init__(self, name):
        self._name = name.title()

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

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

    def greet(self):
        print("Hi, I'm %s" % self._name)

## client code:
p = Person("joel goldstick")
print(p.name)
p.greet()

p.name= "juan christian"
print(p.name)
p.greet()
#################################

where now the client code looks simpler, but the class definition
still gets to manage the attribute's value.


Hopefully that helps to make the suggestions in this thread a little
more understandable in context.  Python's properties allow us to make
the client code look direct but still allow for attribute management.


More information about the Tutor mailing list