[Tutor] Problems with references

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Wed Jun 2 15:10:53 EDT 2004


> I understand what is going on in your explenation, but there is still
> one funny thing that I still do not understand.
>
> This is how part of the class definition looked like, before I edited
> according to your recomendations:
>
> class DiaObjectEntity:
>     # attributes of the entity
>     attributes = {}
>
>     # keys of the entity
>     keys = []
>
>     # wheater or not it is a weak entity
>     weak = 0
>
>     # the name of the entity
>     name = ""
>
>     def __init__(self, DiaId):
>         self.DiaId = DiaId
>
>
> I moved the generation of the attribute "attributes" down into the
> __init__ method, and now they are instance specific, instead of shared.


Hi Martin,


I'm glad it's starting to come together a little beetter.  *grin* So what
does the class definition look like, now?



> The funny thing however is the attribute name. Eventhough it is defined
> like the above, the content is still instence specific, and not shared.
> Meaning, that I have given each instance an unique name, at some point
> efter the instantiation, and that name is only hold for that instance,
> and is not given to the other instances.



Hmmm.  Ok, let me guess the situation again.  Do you mean something like
this?

###
class Person:
    name = "Foobar"

    def __init__(self):
        pass

    def greet(self):
        print self.name, "greets you with great joy"

    def rename(self, newName):
        self.name = newName
###


[Advance warning: we'll see that the code above is actually not such a hot
idea to write.]


Let's see what happens here:

###
>>> class Person:
...     name = "Foobar"
...     def __init__(self):
...         pass
...     def greet(self):
...         print self.name, "greets you with great joy"
...     def rename(self, newName):
...         self.name = newName
...
>>> p1 = Person()
>>> p1.greet()
Foobar greets you with great joy
>>> p2 = Person()
>>> p2.rename("Martin")
>>> p2.greet()
Martin greets you with great joy
>>> p1.greet()
Foobar greets you with great joy
###


If you're doing something like this, don't!  *grin*


What's happening here is a mixture of class and instance attribute stuff,
and it's potentially confusing.  The class defined above,

###
class Person:
    name = "Foobar"
    def __init__(self):
        pass
    def greet(self):
        print self.name, "greets you with great joy"
    def rename(self, newName):
        self.name = newName
###

is very bug-prone, because it first defines a class attribute named
'name', but also allows one to use an instance attribute named 'name'.

Any new Person that's instantiated here doesn't yet have a instance
attribute to make it unique, so when we call greet(), we get the class
attribute value:

###
>>> p1 = Person()
>>> p1.greet()
Foobar greets you with great joy
###


But when we rename a person, we end up adding a new instance attribute to
our Person.  Instance attributes, if defined, will shadow class
attributes:

###
>>> p2 = Person()
>>> p2.rename("Martin")
>>> p2.greet()
Martin greets you with great joy
###


And the real reason this is really not a good situation is because our
method, greet(),

    def greet(self):
        print self.name, "greets you with great joy"

has two different behaviors here, depending if rename() had been called
previously.  greet() will print out the class attribute if that instance
attribute hadn't been defined yet, but will print out the instance
attribute if one is defined for the instance.



Beginners will often try to use class attributes to define default values
for attributes.  However, it's probably a better idea to set those
defaults up in the initializer:

###
class Person:
    def __init__(self):
        self.name = "Foobar"

    def greet(self):
        print self.name, "greets you with great joy"

    def rename(self, newName):
        self.name = newName
###

and avoid the whole class-vs-instance attribute mess.  In fact, I'd
recommend avoiding class attributes altogether... well, at least for a
while.  *grin*




If you have Java/C++ experience, and if you're familiar with things like:

/*** Pseudo-Java ***/
class Person {
    String name;
    Person(String name) {
        this.name = name;
    }
}
/******/

then the appropriate translation of this into Python is:

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

and there's no need to declare the attributes of a Person elsewhere.
Class attributes follow a similar model to the way we use local variables
in Python: we just assign to them to define them.



Good luck to you!




More information about the Tutor mailing list