By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,760 Members | 1,202 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,760 IT Pros & Developers. It's quick & easy.

Unclear On Class Variables

P: n/a
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.

It is late and I am probably missing the obvious. Enlightenment appreciated ...
--
----------------------------------------------------------------------------
Tim Daneliuk tu****@tundraware.com
PGP Key: http://www.tundraware.com/PGP/
Jul 18 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Tim Daneliuk wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.

It is late and I am probably missing the obvious. Enlightenment
appreciated ...


Without actual code how you set the vars, no one can answer that question.

--
Regards,

Diez B. Roggisch
Jul 18 '05 #2

P: n/a
On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tu****@tundraware.com> wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.


I can see why you might think that:
class Spam(object): .... eggs = 4
.... spam = Spam()
spam2 = Spam()
spam.eggs 4 spam2.eggs 4 spam.eggs = 2
spam.eggs 2 spam2.eggs 4

But you are being mislead by the fact that integers are immutable.
'spam.eggs = 2' is *creating* an instance member - there wasn't one
before. Have a look at what happens with a mutable object:
class Spam(object): .... eggs = [3]
.... spam = Spam()
spam2 = Spam()
spam.eggs [3] spam2.eggs [3] spam.eggs.append(5)
spam.eggs [3, 5] spam2.eggs

[3, 5]

--
Cheers,
Simon B,
si***@brunningonline.net,
http://www.brunningonline.net/simon/blog/
Jul 18 '05 #3

P: n/a
Hi Tim,

If you have

class Foo(object) :
x = 0
y = 1

foo = Foo()

foo.x # reads either instance or class attribute (class in this case)

foo.x = val # sets an instance attribute (because foo is instance not
class)

Foo.x = val # sets a class attribute
foo.__class.__x = val # does the same

this might be sometimes confusing. IMHO, the following is especially
nasty:
foo = Foo()
foo.x += 1

print foo.x 1 print Foo.x
0

although the += operator looks like an inplace add it isn't.
it is just syntactic sugar for foo.x = foo.x + 1.
- harold -
On 13.01.2005, at 07:18, Tim Daneliuk wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.

It is late and I am probably missing the obvious. Enlightenment
appreciated ...
--
-----------------------------------------------------------------------
-----
Tim Daneliuk tu****@tundraware.com
PGP Key: http://www.tundraware.com/PGP/
--
http://mail.python.org/mailman/listinfo/python-list

--
Everyone is a genius.
It's just that some people are too stupid to realize it.

Jul 18 '05 #4

P: n/a
Op 2005-01-13, Simon Brunning schreef <si************@gmail.com>:
On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tu****@tundraware.com> wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.


I can see why you might think that:
class Spam(object): ... eggs = 4
... spam = Spam()
spam2 = Spam()
spam.eggs 4 spam2.eggs 4 spam.eggs = 2
spam.eggs 2 spam2.eggs 4

But you are being mislead by the fact that integers are immutable.
'spam.eggs = 2' is *creating* an instance member - there wasn't one
before. Have a look at what happens with a mutable object:
class Spam(object): ... eggs = [3]
... spam = Spam()
spam2 = Spam()
spam.eggs [3] spam2.eggs [3] spam.eggs.append(5)
spam.eggs [3, 5] spam2.eggs

[3, 5]


Well I find this a confusing behaviour on python's part. The fact
that instance.field can mean something different, depending on
where in a statement you find it, makes the behaviour inconsistent.

I know people in general here are against declarations, but declarations
could IMO provide more consistency here and thus more obvious behaviour.

--
Antoon Pardon
Jul 18 '05 #5

P: n/a
Op 2005-01-13, harold fellermann schreef <ha***************@upf.edu>:
Hi Tim,

If you have

class Foo(object) :
x = 0
y = 1

foo = Foo()

foo.x # reads either instance or class attribute (class in this case)

foo.x = val # sets an instance attribute (because foo is instance not
class)

Foo.x = val # sets a class attribute
foo.__class.__x = val # does the same

this might be sometimes confusing. IMHO, the following is especially
nasty:
foo = Foo()
foo.x += 1

print foo.x 1 print Foo.x

0

although the += operator looks like an inplace add it isn't.
it is just syntactic sugar for foo.x = foo.x + 1.


Except is x belongs to a mutable class that implements the
+= operator as an inplace add.

Try the same but with x = [2]
and foo.x += [3]

--
Antoon Pardon
Jul 18 '05 #6

P: n/a
Simon Brunning wrote:
On 13 Jan 2005 07:18:26 EST, Tim Daneliuk <tu****@tundraware.com> wrote:
But you are being mislead by the fact that integers are immutable.
'spam.eggs = 2' is *creating* an instance member - there wasn't one
before. Have a look at what happens with a mutable object:


Simon, it's really not about mutability at all. You've changed
the example, which was binding a name (specifically setting an
attribute), to one in which you are simply calling a method on
the object. If you change your example to bind the name the
same way, even with a mutable, it will work the same way as Tim's
original did with integers:
class Spam(object): .... eggs = [3]
.... spam = Spam()
spam2 = Spam()
spam.eggs = [7]
spam2.eggs

[3]

-Peter
Jul 18 '05 #7

P: n/a
On Thu, 13 Jan 2005 08:56:10 -0500, Peter Hansen <pe***@engcorp.com> wrote:
Simon, it's really not about mutability at all. You've changed
the example,


Err, there *wasn't* an example, not really. The OP just mentioned
'setting the values' of instance members. That *can* mean name
binding, but (to my mind at least) it can also mean calling mutating
methods. I just wanted to show both.

--
Cheers,
Simon B,
si***@brunningonline.net,
http://www.brunningonline.net/simon/blog/
Jul 18 '05 #8

P: n/a
>
Well I find this a confusing behaviour on python's part. The fact
that instance.field can mean something different, depending on
where in a statement you find it, makes the behaviour inconsistent.

I know people in general here are against declarations, but declarations
could IMO provide more consistency here and thus more obvious behaviour.


Well just to show how confusing python can be, the following piece of
code.

| class Spam:
| eggs = [2, 3]
|
|
| sp1 = Spam()
| sp2 = Spam()
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
|
| sp1.eggs += [4,]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
|
| Spam.eggs = [3,5]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'

Which produces:

[2, 3] 1075958860
[2, 3] 1075958860
--------------------
[2, 3, 4] 1075958860
[2, 3, 4] 1075958860
--------------------
[2, 3, 4] 1075958860
[3, 5] 1075959084
--------------------

Jul 18 '05 #9

P: n/a
Tim Daneliuk wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
What it actually does is define names with the given values *in the
class namespace*.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.
I imagine here you are setting instance variables, which then *mask* the
presence of class variables with the same name, because "self-relative"
name resolution looks in the instance namespace before it looks in the
class namespace.
It is late and I am probably missing the obvious. Enlightenment
appreciated ...


You can refer to class variables using the class name explicitly, both
within methods and externally:
class X: ... count = 0
... def getCt(self):
... return self.count
... def inc(self):
... self.count += 1
... x1 = X()
x2 = X()
id(x1.count) 168378284 x1.inc()
id(x1.count) 168378272 id(x2.count) 168378284 id(X.count) 168378284 x1.getCt() 1 x2.getCt() 0


regards
Steve
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/
Holden Web LLC +1 703 861 4237 +1 800 494 3119

Jul 18 '05 #10

P: n/a
Tim Daneliuk wrote:
I am a bit confused. I was under the impression that:

class foo(object):
x = 0
y = 1

means that x and y are variables shared by all instances of a class.
But when I run this against two instances of foo, and set the values
of x and y, they are indeed unique to the *instance* rather than the
class.


"set" as in:

obj = foo()
obj.x = 10 # set x

?

if so, the "obj.x=" line is *adding* an instance variable to the "x" object, which will
then hide the "x" at the class level.
class foo(object): .... x = 0
.... y = 1
.... obj = foo()
obj.__dict__ {} obj.x 0 obj.y 1 foo.x 0 obj.x = 10
obj.__dict__ {'x': 10} obj.x 10 foo.x 0

if you want to assign to the class variable, assign to the class variable:
obj = foo()
obj.x 0 foo.x = 20
obj.__dict__ {} obj.x 20 foo().x

20

</F>

Jul 18 '05 #11

P: n/a
Antoon Pardon a écrit :
Well I find this a confusing behaviour on python's part. The fact
that instance.field can mean something different, depending on
where in a statement you find it, makes the behaviour inconsistent.

I know people in general here are against declarations, but declarations
could IMO provide more consistency here and thus more obvious behaviour.

Well just to show how confusing python can be, the following piece of
code.

| class Spam:
| eggs = [2, 3]
|
|
| sp1 = Spam()
| sp2 = Spam()
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
|
| sp1.eggs += [4,]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
|
| Spam.eggs = [3,5]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'

Which produces:

[2, 3] 1075958860
[2, 3] 1075958860
--------------------
[2, 3, 4] 1075958860
[2, 3, 4] 1075958860
--------------------
[2, 3, 4] 1075958860
[3, 5] 1075959084
--------------------


Well ... and could someone explain this behaviour ?
I don't catch it !

Pierre
Jul 18 '05 #12

P: n/a
Pierre Barbier de Reuille a écrit :
Antoon Pardon a écrit :
Well I find this a confusing behaviour on python's part. The fact
that instance.field can mean something different, depending on
where in a statement you find it, makes the behaviour inconsistent.

I know people in general here are against declarations, but declarations
could IMO provide more consistency here and thus more obvious behaviour.


Well just to show how confusing python can be, the following piece of
code.

| class Spam:
| eggs = [2, 3]
| | | sp1 = Spam()
| sp2 = Spam()
| | print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
| | sp1.eggs += [4,]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'
|
| Spam.eggs = [3,5]
|
| print sp1.eggs, id(sp1.eggs)
| print sp2.eggs, id(sp2.eggs)
| print '--------------------'

Which produces:

[2, 3] 1075958860
[2, 3] 1075958860
--------------------
[2, 3, 4] 1075958860
[2, 3, 4] 1075958860
--------------------
[2, 3, 4] 1075958860
[3, 5] 1075959084
--------------------


Well ... and could someone explain this behaviour ?
I don't catch it !

Pierre


Ok, I think I got it ! I speak with friends working with Python too ...
It seems that "a += l" if "a" and "l" are lists is equivalent to :

a.extend(l)
a = a

The second line could seem meaningless but it is not ! Indeed, in the
example above, the first "sp1.eggs" (the one with the extend) is a class
variable but, the second "sp1.eggs" (the one before the "=") is an
instance variable !

So, at the end, we append to get sp1.eggs and Spam.eggs references to
the same structure. But sp1.eggs is an instance variable of sp1 and no
more the class variable. To test that, it's possible to modify slightly
the code with :

|sp1.eggs += [4,]
|del sp1.eggs

Then, sp1.eggs still exists !!! But it's again the class variable ...

Ok, back to the documentation ...

In the doc, there is a special case for the use of "+=" with the class
members. IMHO, this should not be !!! But, it says that :

ob.a += b

is translated into :

ob.__setattr__( "a", ob.__getattr__("a").__iadd__(b) )

My opinion is : it would be much more simpler to explain than :

a += b <=> a.__iadd__(b); a = a

and not give any special case for class members. In both cases, the
resulting behaviour is the same, but it would be less confusing.

Then, this change of scope of variables in python is very very annoying.
Both for new and old programmers (we have both in my lab ...).

Well, I hope I got it write this time ... but this is a feature to fear !!!

Pierre
Jul 18 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.