direct initialization of class attributes vs. declarations w/in __init__

D

digitalorganics

What's the difference between initializing class variables within the
class definition directly versus initializing them within the class's
__init__ method? Is there a reason, perhaps in certain situations, to
choose one over the other?

Thank you.
 
D

Diez B. Roggisch

What's the difference between initializing class variables within the
class definition directly versus initializing them within the class's
__init__ method? Is there a reason, perhaps in certain situations, to
choose one over the other?

You are confusing class variables with instance variables. The former
are what you can initialize inside the class-statement. However, they
are shared amongst _all_ instances. Consider this little example:

class Foo(object):
FOO = 1
BAR = []

def __init__(self, FOO):
self.FOO = FOO
self.BAR.append(FOO)

def __repr__(self):
return "FOO: %r\nBAR: %r\n" % (self.FOO, self.BAR)


f1 = Foo(1)
print f1
f2 = Foo(2)
print f2
print f1


------
meskal:~/Projects/CameraCalibrator deets$ python2.4 /tmp/test.py
FOO: 1
BAR: [1]

FOO: 2
BAR: [1, 2]

FOO: 1
BAR: [1, 2]


-----

As you can see, the list BAR is shared. And you can also see that
_assigning_ to something like this:

self.FOO

will create an instance-variable. Even if a variable of the same name
existed on the class before!

Which is precisely the difference between using variable initialization
in __init__ and inside the class-statement.

BTW,

self.__class__.FOO = value

will set class-variables inside a method. Just if you wondered.

Diez
 
D

digitalorganics

Ah, you've brought me much clarity Diez, thank you. That would explain
some "bugs" I've been having...

What's the difference between initializing class variables within the
class definition directly versus initializing them within the class's
__init__ method? Is there a reason, perhaps in certain situations, to
choose one over the other?

You are confusing class variables with instance variables. The former
are what you can initialize inside the class-statement. However, they
are shared amongst _all_ instances. Consider this little example:

class Foo(object):
FOO = 1
BAR = []

def __init__(self, FOO):
self.FOO = FOO
self.BAR.append(FOO)

def __repr__(self):
return "FOO: %r\nBAR: %r\n" % (self.FOO, self.BAR)


f1 = Foo(1)
print f1
f2 = Foo(2)
print f2
print f1


------
meskal:~/Projects/CameraCalibrator deets$ python2.4 /tmp/test.py
FOO: 1
BAR: [1]

FOO: 2
BAR: [1, 2]

FOO: 1
BAR: [1, 2]


-----

As you can see, the list BAR is shared. And you can also see that
_assigning_ to something like this:

self.FOO

will create an instance-variable. Even if a variable of the same name
existed on the class before!

Which is precisely the difference between using variable initialization
in __init__ and inside the class-statement.

BTW,

self.__class__.FOO = value

will set class-variables inside a method. Just if you wondered.

Diez
 
D

digitalorganics

Wait a minute! It doesn't explain my bugs. I've got "class variables"
acting like instance variables. What's weirder is that this behavior
occurs on my computer (in both of my installed WinXP copies) but not on
my laptop (WinXP Pro).

See the following test:

class Boo:
jerk = "yes"

def killjerk(self):
self.jerk = self.jerk + "no"
print self.jerk
print self.__class__.jerk

bing = Boo()
bing.killjerk()

outputs:

yesno
yes

At first, I thought that self.jerk was resolving to the class attribute
instead of creating a new variable (w/ a differing scope). But we can
see that there are actually two variables because a direct reference to
self.__class__.jerk returns "yes", not yesno (what we would get if
self.jerk pointed to the same data/object as self.__class__.jerk). Yet,
it's treating self.jerk as a combination of the two (it always add the
class attribute to the instance attribute). Is this normal behavior??
It doesn't work this way on my laptop...

Perhaps you can see why I'd be confused!

Thanks.

Ah, you've brought me much clarity Diez, thank you. That would explain
some "bugs" I've been having...

What's the difference between initializing class variables within the
class definition directly versus initializing them within the class's
__init__ method? Is there a reason, perhaps in certain situations, to
choose one over the other?

You are confusing class variables with instance variables. The former
are what you can initialize inside the class-statement. However, they
are shared amongst _all_ instances. Consider this little example:

class Foo(object):
FOO = 1
BAR = []

def __init__(self, FOO):
self.FOO = FOO
self.BAR.append(FOO)

def __repr__(self):
return "FOO: %r\nBAR: %r\n" % (self.FOO, self.BAR)


f1 = Foo(1)
print f1
f2 = Foo(2)
print f2
print f1


------
meskal:~/Projects/CameraCalibrator deets$ python2.4 /tmp/test.py
FOO: 1
BAR: [1]

FOO: 2
BAR: [1, 2]

FOO: 1
BAR: [1, 2]


-----

As you can see, the list BAR is shared. And you can also see that
_assigning_ to something like this:

self.FOO

will create an instance-variable. Even if a variable of the same name
existed on the class before!

Which is precisely the difference between using variable initialization
in __init__ and inside the class-statement.

BTW,

self.__class__.FOO = value

will set class-variables inside a method. Just if you wondered.

Diez
 
F

Fredrik Lundh

At first, I thought that self.jerk was resolving to the class attribute
instead of creating a new variable (w/ a differing scope).

When you access an instance attribute, Python first looks in the
instance object, and then in the class object.

When you assign to an instance attribute, it's *always* assigned to the
instance object, whether there's a class attribute with the same name or
not.

If there's already a class attribute with the same name, that attribute
will be shadowed (but can still be accessed via the class object, of
course).
It doesn't work this way on my laptop...

Python's always worked that way, so I find that a bit hard to believe.

</F>
 
D

Dennis Lee Bieber

Wait a minute! It doesn't explain my bugs. I've got "class variables"
acting like instance variables. What's weirder is that this behavior
occurs on my computer (in both of my installed WinXP copies) but not on
my laptop (WinXP Pro).
Don't know about the laptop but...
See the following test:
See the following modified version:

-=-=-=-=-=-=-
class Boo:
jerk = "yes"

def killjerk(self):
print id(self.jerk), id(self.__class__.jerk)
self.jerk = self.jerk + "no"
print self.jerk, id(self.jerk)
print self.__class__.jerk

bing = Boo()
bing.killjerk()
bing.killjerk()
-=-=-=-=-=-=-=-
10837696 10837696
yesno 18264128
yes
18264128 10837696
yesnono 18289600
yes

The initial lookup for "self.jerk" does not find it in the instance,
so it looks higher, into the class.

THEN when you "assign" the result to "self.jerk" you create an
instance specific name entry, which is bound to a string at a different
location. The lookup on the left side does not go outside of the
instance. Notice how the second "bing.killjerk()" results in "self.jerk"
being bound to a third address.

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
D

digitalorganics

Fredrik said:
When you access an instance attribute, Python first looks in the
instance object, and then in the class object.

When you assign to an instance attribute, it's *always* assigned to the
instance object, whether there's a class attribute with the same name or
not.

If there's already a class attribute with the same name, that attribute
will be shadowed (but can still be accessed via the class object, of
course).


Python's always worked that way, so I find that a bit hard to believe.

No need to be obnoxious. I do appreciate your efforts to help, but you
must admit, your last statement is a bit snide and certainly not
useful. I'm telling you that the code runs differently on my laptop.
Why this is, I don't know any more /or/ less than you do apparently.
Now, it is of course possible that I'm interpreting the results
incorrectly, but that doesn't change the fact that I'm getting
different results per computer with identical code.
 
D

digitalorganics

Thank you Dennis, this makes the behavior so much clearer to me. I see
now that when self.jerk = self.jerk + 1 is executed that even though
the names are identical, at this point I'm referring to two different
values (one which is being created in part from the other).

As for my laptop, I'm not really sure what's up there. I can change the
class variable self.jerk all I want but it has no influence over the
instance variable. Here's the code:

class Boo:
jerk = 10

def killjerk(self):
self.jerk += 1
print self.jerk
print self.__class__.jerk

bing = Boo()
bing.killjerk()

On my desktop, I get:

11
10

On my laptop, I get:

1
10

Now, if I remove the class variable, I get an AttributeError, as you'd
expect. This happens on both the desktop and laptop. However, on the
laptop it seems not to care what value I give the class variable jerk,
it only requires that it exist. Any clue what's behind this behavior?
I'm running the same python version on both computers (the ActiveState
distro).

Thanks for all the help...
 
D

digitalorganics

Fredrik said:
a missing plus sign.

</F>

Thanks for the guess but not possible given the following:

class Boo:
jerk = 10

def killjerk(self):
counter = 3
while counter !=0:
counter -= 1
self.jerk += 1
print self.jerk
print self.__class__.jerk


bing = Boo()
bing.killjerk()

Output from desktop comp.:
11
10
12
10
13
10

Output from laptop comp.:

1
10
2
10
3
10

?? . . .
 
D

Diez B. Roggisch

No need to be obnoxious. I do appreciate your efforts to help, but you
must admit, your last statement is a bit snide and certainly not
useful.
> I'm telling you that the code runs differently on my laptop.

It certainly doesn't. There is absolutely no imaginable way how this
behavior could be different, even if the python versions would differ
considerably. Apart from quantum-fluctuations. Or other SciFi voodoo.
Why this is, I don't know any more /or/ less than you do apparently.

Frederik (as one of the most profiled python developers out there) might
not be the most amicable of posters, but he certainly is not wrong when
it comes to the most basic parts of python's semantics.
Now, it is of course possible that I'm interpreting the results
incorrectly, but that doesn't change the fact that I'm getting
different results per computer with identical code.

It is NOT identical code, otherwise you won't see different
results. It might be code from which you _believe_ it is identical, and
the difference might be subtle to see. But if you'd store it in a file,
execute on your laptop, use an usb-stick and then transfer it to
whatever the other machine of yours is, it will yield the exact same
results.

Diez
 
F

Fredrik Lundh

Output from laptop comp.:

1
10
2
10
3
10

so how are you entering and running the code on your laptop ?

what happens if you set the class attribute to 100 instead of 10 ?

</F>
 
D

Dennis Lee Bieber

As for my laptop, I'm not really sure what's up there. I can change the
class variable self.jerk all I want but it has no influence over the
instance variable. Here's the code:
One: Try embedding a few "print id(whatever)" statements in it, so
you can track the object identities being read/written.

Two: minimize machine differences -- if possible put the source file
on a network mount so both machines are accessing the identical source
file.

Three: look for stray .pyc or .pyo files -- ActiveState's install,
for some time, has had the misfortune of putting those ahead of the .py
on the search path, with the result that sometimes a test run finds an
older compiled file and not the edited .py version.

Four: dump the version strings


C:\Documents and Settings\Dennis Lee Bieber>python
ActivePython 2.4.3 Build 12 (ActiveState Software Inc.) based on
Python 2.4.3 (#69, Apr 11 2006, 15:32:42) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
so we can look for anomalies.
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
D

digitalorganics

Oh wow, I wasn't expecting so much help. I really appreciate it. My
problem, however, has been solved. I uninstalled my ActiveState Python
distro on my laptop and installed the distro from python.org along with
Stan's Python Editor. I ran the same code I'd run before and guess
what? The behavior now matches that of my desktop! Why? *shrug*

As for the code being identical, it certainly was as I emailed the .py
file to myself (from the laptop) and downloaded it to my desktop where
I then ran it just as I had done on the laptop, with PythonWin. Unless
Google programmed Gmail to muck w/ people's python code....
Additionally, the bytes on the files match. Thus, I feel I can
guarantee that the code is indeed identical.

Here's my wild guess: for some reason a bug in PythonWin was causing my
changes to the class attribute (i.e. jerk variable) not to be reflected
in the actual code. This explanation, if you can call it one, still
doesn't make sense to me however because I could make other changes to
the code and it would indeed be reflected in execution. Add to the fact
that PythonWin is essentially just a text editor, I don't see how/why
it would selectively save code changes.

It is true that I never restarted the PythonWin IDE after a change of
the class attribute to something other than 0, and perhaps reinstalling
python etc. was unnecessary. I'm only coming to this realization now.

In any event, I am now problem free and quite pleased to be able to
exchange .py files between computers and know they'll behave the same
(rather, I'm assuming this henceforth).

Furthermore, I'd like to thank everyone who tried to help, and that
certainly includes Fredrik.


Cheers,

DigiO
 
D

digitalorganics

Fredrik said:
so how are you entering and running the code on your laptop ?

what happens if you set the class attribute to 100 instead of 10 ?

</F>

You can see my other post which I just sent but, I was using PythonWin:

1. type code in editor
2. hit run
3. observe output in interactive window
 
D

digitalorganics

Diez said:
It certainly doesn't. There is absolutely no imaginable way how this
behavior could be different, even if the python versions would differ
considerably. Apart from quantum-fluctuations. Or other SciFi voodoo.
Hmmm


Frederik (as one of the most profiled python developers out there) might
not be the most amicable of posters,

Although he dropped what I perceived to be a snide and unhelpful
comment, two things. One, I understand what's behind it in the sense
that the behavior I was describing goes against the semantic
fundamentals of python, and should therefore be impossible. Two,
Fredrik is no doubt a sweetheart and he showed it by continuing to put
his efforts toward helping me despite my criticism of him. I can't
thank him enough. Honestly, I believe newsgroups need more people like
him . . .

...

It is NOT identical code, otherwise you won't see different
results. It might be code from which you _believe_ it is identical, and
the difference might be subtle to see. But if you'd store it in a file,
execute on your laptop, use an usb-stick and then transfer it to
whatever the other machine of yours is, it will yield the exact same
results.

Diez

Read my other post. The code was/is definitely identical. In any event,
I don't really care. It's working properly now, and if I have similarly
weird problems in future, I'll deal with them at that time. I don't
know what was up, but I understand it doesn't make sense from any
visible standpoint of logic. Thank you for your efforts Diez...
 
S

Steve Holden

You can see my other post which I just sent but, I was using PythonWin:

1. type code in editor
2. hit run
3. observe output in interactive window
Frankly I'd be less incredulous if you'd said you transferred the code
between machines using some network- or file-based transfer mechanism.
The facts are that if you have been entering "the same" code separately
on two machines then by far the most likely source of any discrepancy is
typographical error (a subject with which regular readers will know I am
intimately familiar).

The Python behaviour you now understand (access to class variables in
the absence of an eponymous instance variable) is long-standing, and it
is therefore unlikely that two correct Python installations will give
different results for the same code. Ergo, the two pieces of code are
different.

Unless, that is, you can tell us different beyond all possibility of
transcription errors.

regards
Steve
 
S

Steve Holden

Read my other post. The code was/is definitely identical. In any event,
I don't really care. It's working properly now, and if I have similarly
weird problems in future, I'll deal with them at that time. I don't
know what was up, but I understand it doesn't make sense from any
visible standpoint of logic. Thank you for your efforts Diez...
It would be nice to know where the discrepancy arose, but now I see you
were using email to transfer the source code I happily withdraw my
accusations of typographical error.

regards
Steve
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top