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

Global variables within classes.

P: n/a
Hi,
I'm getting myself really confused. I have three classes. Two of them need
to reference the third, like so:

Canvas ---Stack <--- Thing

I am doing this right now:

s = Stack()

And then within <class Canvas:I am referring directly to the global
variable 's' (and again from Thing).

Now, this works, but it bugs me somewhat. I don't want to limit a user to
having to declare a global variable of a particular name.
They should be able to say <Zombie = Stack()>

This may also leads to more confusion because the user can also make Things
directly <mything = Thing()and I want the new things to all reference the
*same* Stack. (Right now it works because I reference 's' within Thing.)

I thought this might be a case for multiple inheritance but I just keep
getting recursion errors as one thing refers to another in a big mess.

Does that makes sense?

\d

Nov 9 '07 #1
Share this Question
Share on Google+
18 Replies


P: n/a
Donn Ingle a écrit :
Hi,
I'm getting myself really confused. I have three classes. Two of them need
to reference the third, like so:

Canvas ---Stack <--- Thing

I am doing this right now:

s = Stack()

And then within <class Canvas:I am referring directly to the global
variable 's' (and again from Thing).

Now, this works, but it bugs me somewhat.
Indeed...
I don't want to limit a user to
having to declare a global variable of a particular name.
They should be able to say <Zombie = Stack()>

This may also leads to more confusion because the user can also make Things
directly <mything = Thing()and I want the new things to all reference the
*same* Stack. (Right now it works because I reference 's' within Thing.)
I thought this might be a case for multiple inheritance
???
but I just keep
getting recursion errors as one thing refers to another in a big mess.

Does that makes sense?
wrt/ all Thing instances having to refer to a same Stack instance,
there's a pretty obvious answer: make the Stack instance an attribute of
class Thing, ie:

class Thing(object):
stack = Stack()

def some_method(self, val):
self.stack.push(val)
# etc...

This way you can access this stack from the Thing class directly, as
well as from any instance, subclass and subclass instance of.

Now the point that isn't clear is the exact relationship between Stack
and Canvas. You didn't give enough details for any answer, advice or
hint to make sens.

HTH
Nov 9 '07 #2

P: n/a
>I thought this might be a case for multiple inheritance
???
Well, in terms of having Canvas and Thing inherit from Stack and thereby
(somehow, not sure how) they would both have access to Stack.stack (a list)
wrt/ all Thing instances having to refer to a same Stack instance,
there's a pretty obvious answer: make the Stack instance an attribute of
class Thing, ie:
class Thing(object):
stack = Stack()

def some_method(self, val):
self.stack.push(val)
# etc...
No can do:
Canvas ---Stack <--- Thing
Both Canvas and Thing have to use the same Stack. It gets things pushed onto
it by them both.
Now the point that isn't clear is the exact relationship between Stack
and Canvas. You didn't give enough details for any answer, advice or
hint to make sens.
Sorry, didn't want to write an overly long post.

a Canvas holds many Things (graphics) and it pushes each Thing onto the
Stack. The Things also push data onto the same Stack. After that the Stack
pops and draws each Thing to the screen.

What I'm asking about is subtle and I don't know how to word it: how can
Classes share common objects without using global variables specifically
named within them?
## == API in another module perhaps ===
Class Stack:
def push(self,stuff):
pass

Class Canvas:
def do(self):
s.push("data") #I don't feel right about 's' here.

Class Thing:
def buzz(self):
print s.pop(0)

## == User space code area ===
s = Stack() #I want to avoid this direct naming to 's'
c = Canvas()
c.push("bozo")
t = Thing()
t.buzz()

Hope that makes more sense.
\d
Nov 9 '07 #3

P: n/a
Donn Ingle a écrit :
>>>I thought this might be a case for multiple inheritance

???

Well, in terms of having Canvas and Thing inherit from Stack and thereby
(somehow, not sure how) they would both have access to Stack.stack (a list)

>>wrt/ all Thing instances having to refer to a same Stack instance,
there's a pretty obvious answer: make the Stack instance an attribute of
class Thing, ie:
class Thing(object):
stack = Stack()

def some_method(self, val):
self.stack.push(val)
# etc...


No can do:
Canvas ---Stack <--- Thing
Sorry but you're exemple is using classes, not instances. So while *you*
may know what you mean, it's not decidable for me.
Both Canvas and Thing have to use the same Stack.
You mean: both Canvas class and Thing class have to use the same Stack
Class ? Or : for all Canvas instances and all Thing instances, there
must be only one same Stack instance ? Or: a given (Canvas instance,
Thing instance) couple must share a same Stack instance ? Or (etc...)
It gets things pushed onto
it by them both.
Both what ? classes ? instances ?-)
>
>>Now the point that isn't clear is the exact relationship between Stack
and Canvas. You didn't give enough details for any answer, advice or
hint to make sens.

Sorry, didn't want to write an overly long post.
There's certainly a balance between being overly vague and being overly
long !-)
a Canvas holds many Things (graphics) and it pushes each Thing onto the
Stack. The Things also push data onto the same Stack. After that the Stack
pops and draws each Thing to the screen.

What I'm asking about is subtle and I don't know how to word it: how can
Classes
I guess you mean "instances", not "classes".
share common objects without using global variables specifically
named within them?
Err...Perhaps a dumb question, but what about passing the "common
objects" to initializers ?
## == API in another module perhaps ===
Class Stack:
def push(self,stuff):
pass

Class Canvas:
def do(self):
s.push("data") #I don't feel right about 's' here.

Class Thing:
def buzz(self):
print s.pop(0)

## == User space code area ===
s = Stack() #I want to avoid this direct naming to 's'
c = Canvas()
c.push("bozo")
t = Thing()
t.buzz()
# API land
class Stack(object):
# ok, we all know what a stack is

class Canvas(object):
def __init__(self, stack):
self.stack = stack
def do(self):
self.stack.push("data")

class Thing(object):
def __init__(self, stack):
self.stack = stack
def buzz(self):
print self.stack.pop(0)
# Userland
s = Stack()
c = Canvas(s)
t = Thing(s)

c.do()
t.buzz()

HTH
Nov 9 '07 #4

P: n/a
I guess you mean "instances", not "classes".
Yes.
Err...Perhaps a dumb question, but what about passing the "common
objects" to initializers ?
s = Stack()
c = Canvas(s)
t = Thing(s)
Okay, I see where you're going. It's better than what I have at the moment.
Thanks.

\d
Nov 9 '07 #5

P: n/a
On 11 10 , 5 48 , Donn Ingle <donn.in...@gmail.comwrote:
## == API in another module perhaps ===
Class Stack:
def push(self,stuff):
pass

Class Canvas:
def do(self):
s.push("data") #I don't feel right about 's' here.

Class Thing:
def buzz(self):
print s.pop(0)

## == User space code area ===
s = Stack() #I want to avoid this direct naming to 's'
c = Canvas()
c.push("bozo")
t = Thing()
t.buzz()

Hope that makes more sense.
\d

If you mean that all instances of Class Canvas and Thing will share
the *same* Stack, I think we can do it kind of like this:
## == API in another module perhaps ===
class Stack:
list = []
def push(self, item):
self.list.append(item)
def pop(self):
item = self.list[-1]
del self.list[-1]
return item

class Canvas:
def __init__(self):
self.s = Stack()
def push(self, item):
self.s.push(item)

class Thing:
def __init__(self):
self.s = Stack()
def buzz(self):
print self.s.pop()

## == User space code area ===
c = Canvas()
c.push("bozo")
t = Thing()
t.buzz()

or: if you want a pair of instances of class Canvas and class Thing
share
the *same* instance of class Stack, maybe we can make it like this:
## == API in another module perhaps ===
class Stack:
def __init__(self):
self.list = []
def push(self, item):
self.list.append(item)
def pop(self):
item = self.list[-1]
del self.list[-1]
return item

class Canvas:
def __init__(self, stack = Stack()):
self.s = stack
def push(self, item):
self.s.push(item)
def getStack(self):
return self.s

class Thing:
def __init__(self, stack = Stack()):
self.s = stack
def buzz(self):
print self.s.pop()
def getStack(self):
return self.s
## == User space code area ===
c = Canvas()
c.push("bozo")
t = Thing(c.getStack()) #associate t with c
t.buzz()

Nov 10 '07 #6

P: n/a
Very interesting reply. I must ask a few questions, interleaved:
If you mean that all instances of Class Canvas and Thing will share
the *same* Stack, I think we can do it kind of like this:
What's the difference between "same Stack" and "same instance of Stack"? I
thought I knew what an instance was, but this code has made me doubt my
basics.
class Stack:
list = []
Okay, this has me a little weirded-out. How is this different from putting
it in:
def __init__(self):
self.list = []
?
I see from tests that it is different, but I don't quite grok it. Who owns
the list ref?
def pop(self):
item = self.list[-1]
del self.list[-1]
return item
Is there some reason you do all that and not a self.list.pop(0)?
class Canvas:
def __init__(self):
self.s = Stack()
Surely this makes a unique instance within Canvas such that it's a new
Stack?
class Thing:
def __init__(self):
self.s = Stack()
Same question again -- my brain is telling me this is *another* Stack and
not the same one that it's in Canvas at all.

It looks like it could work for me, but I gotta get it in my head first :)

or: if you want a pair of instances of class Canvas and class Thing
share
the *same* instance of class Stack, maybe we can make it like this:
c = Canvas()
c.push("bozo")
t = Thing(c.getStack()) #associate t with c
t.buzz()
This one I understand better because it does not imply anything - it's
easier to follow and it's where my head is at with Python, but your first
example is a whole new world.

Thanks for the post!
\d

Nov 10 '07 #7

P: n/a
Donn Ingle <do********@gmail.comwrote:
>class Stack:
list = []
Okay, this has me a little weirded-out. How is this different from
putting it in:
def __init__(self):
self.list = []
?
I see from tests that it is different, but I don't quite grok it. Who
owns the list ref?
The first creates an attribute of the class, the second creates an
attribute in the instance.

When you access an attribute of an instance but the instance does not have
an attribute with the required name Python looks for the attribute in the
class instead. So in the first case it would look as though each instance
has a 'list' attribute, but it is the same value shared between all
instances. In the second case each instance has its own 'list' attribute.

Actually the lookup is somewhat more complex than that when you use new-
style classes (and you should always use new-style classes): properties (or
other objects with a 'get' method) are class attributes but take precedence
over instance attributes.
Nov 10 '07 #8

P: n/a
The first creates an attribute of the class, the second creates an
attribute in the instance.
Given that, can you clarify this:

class Test:
attribute = "original value"

class Bob:
def __init__(self):
self.ref = Test()

class Jim:
def __init__(self):
self.ref = Test()

b = Bob()
j = Jim()

print b.ref.attribute #prints "original value"

b.ref.attribute = "haschanged"
## Where is the value "haschanged" going here?
print b.ref.attribute # print "haschanged"

print j.ref.attribute #prints "original value"
## If it changed and an attribute of the Class, then
## why is it back to "original value" ?
Actually the lookup is somewhat more complex than that when you use new-
style classes (and you should always use new-style classes): properties
(or other objects with a 'get' method) are class attributes but take
precedence over instance attributes.
What is a 'get' method? Do you mean it should get all Java-esque with
getBlah and setBlah for every little thing?

I have been hearing about "new classes" for a while but there's no clarity
in the Python docs (that I can find). Have you any references for me? I
thought they were the standard by now anyway. I've only been pythoning
since 2.3 anyway.
\d

Nov 10 '07 #9

P: n/a
On Sat, 10 Nov 2007 17:00:13 +0200, Donn Ingle wrote:
>The first creates an attribute of the class, the second creates an
attribute in the instance.

Given that, can you clarify this:

class Test:
attribute = "original value"

class Bob:
def __init__(self):
self.ref = Test()

class Jim:
def __init__(self):
self.ref = Test()

b = Bob()
j = Jim()

print b.ref.attribute #prints "original value"

b.ref.attribute = "haschanged"
## Where is the value "haschanged" going here?
To *instance* of `Test` you created and bound to `b.ref`.
print b.ref.attribute # print "haschanged"

print j.ref.attribute #prints "original value"
## If it changed and an attribute of the Class, then
## why is it back to "original value" ?
Because the *instance* of `Test` bound to `j.ref` does not have
`attribute` it is looked up in the *class* `Test`.
>Actually the lookup is somewhat more complex than that when you use new-
style classes (and you should always use new-style classes): properties
(or other objects with a 'get' method) are class attributes but take
precedence over instance attributes.
What is a 'get' method? Do you mean it should get all Java-esque with
getBlah and setBlah for every little thing?
Good $GOD no! He's talking about the `__get__` method on properties. Read
the docs for the built in `property()` function. It's a nice mechanism to
actually avoid all those getters and setters because you can turn "simple"
attributes into "computed" attributes without changing the API of the
objects.

Ciao,
Marc 'BlackJack' Rintsch
Nov 10 '07 #10

P: n/a
Included again for clarity:
>class Test:
attribute = "original value"

class Bob:
def __init__(self):
self.ref = Test()

class Jim:
def __init__(self):
self.ref = Test()

b = Bob()
j = Jim()

print b.ref.attribute #prints "original value"
b.ref.attribute = "haschanged"
## Where is the value "haschanged" going here?

To *instance* of `Test` you created and bound to `b.ref`.
I don't follow you here. I *think* you are saying I created a *new* (on the
fly) ref within b that is also called 'attrib', so that it's kind of
shadowing the original 'attribute' ref (the so-called class attribute.)
?
>print b.ref.attribute # print "haschanged"

print j.ref.attribute #prints "original value"
## If it changed and an attribute of the Class, then
## why is it back to "original value" ?

Because the *instance* of `Test` bound to `j.ref` does not have
`attribute` it is looked up in the *class* `Test`.
Okay, I sort of see that. It's not a property of 'j' so it looks upwards
into the class.
This is kind of weird. It's not clear like Python usually is. Is this
something intentional or did it 'fall through the cracks'? I mean, can one
rely on it or will it be 'fixed'?
Good $GOD no!
:D
He's talking about the `__get__` method on properties. Read
the docs for the built in `property()` function.
Okay, I'll go have a look.

Thx
\d
Nov 10 '07 #11

P: n/a
On Sat, 10 Nov 2007 18:53:08 +0200, Donn Ingle wrote:
Included again for clarity:
>>class Test:
attribute = "original value"

class Bob:
def __init__(self):
self.ref = Test()

class Jim:
def __init__(self):
self.ref = Test()

b = Bob()
j = Jim()

print b.ref.attribute #prints "original value"
b.ref.attribute = "haschanged"
## Where is the value "haschanged" going here?

To *instance* of `Test` you created and bound to `b.ref`.
I don't follow you here. I *think* you are saying I created a *new* (on the
fly) ref within b that is also called 'attrib', so that it's kind of
shadowing the original 'attribute' ref (the so-called class attribute.)
?
In the `__init__()` of `Bob` you created an instance of `Test`. You can't
create a `ref`, that's just a name of an attribute on `Bob` instances.
Then you bind the attribute `attribute` of that instance to the string
"haschanged". This assignment creates the attribute because `Test`
*instances* don't have such an attribute. And yes this `attribute`
shadows the class `attribute` as the lookup rules are instance -class ->
base classes.
>>print b.ref.attribute # print "haschanged"

print j.ref.attribute #prints "original value"
## If it changed and an attribute of the Class, then
## why is it back to "original value" ?

Because the *instance* of `Test` bound to `j.ref` does not have
`attribute` it is looked up in the *class* `Test`.
Okay, I sort of see that. It's not a property of 'j' so it looks upwards
into the class.
Its not an attribute of `j.ref`!

Here's a little ASCII art showing the situation after your code was
executed::

Names | Objects
-------+---------------------------------------------
| +----------+
Test ------>|<class | +----------------+
| |attribute----------->|<str |
| +----------+ |"original value"|
| +----------------+
|
| +------+
j --------->|<Joe| +----------+
| |ref ---->|<Test |
| +------+ +----------+
|
|
| +------+
b --------->|<Bob| +----------+
| |ref ---->|<Test | +------------+
| +------+ |attribute---->|<str |
| +----------+ |"haschanged"|
| +------------+

On the left are the names in the module's namespace and on the right are
the objects in memory. From the `Test` objects there's also a reference
to the `class` that's bound to the name `Test` in the Module that is not
shown in the "drawing" but necessary to look up attributes in the class of
the instances.
This is kind of weird. It's not clear like Python usually is. Is this
something intentional or did it 'fall through the cracks'? I mean, can one
rely on it or will it be 'fixed'?
Don't think so. It's a surprise for many but then class attributes are
not that common in code or they even use this "gotcha" for
immutable default values. As long a the value isn't changed the default
value is just referenced from the class then and not every instance.

Ciao,
Marc 'BlackJack' Rintsch
Nov 10 '07 #12

P: n/a
Thanks for your time and patience Marc, that was some hotshot ascii art.
I'll have to take some time to digest this.

\d

Nov 10 '07 #13

P: n/a
On Sat, 10 Nov 2007 17:39:04 +0000, Marc 'BlackJack' Rintsch wrote:
On Sat, 10 Nov 2007 18:53:08 +0200, Donn Ingle wrote:
>>>print b.ref.attribute # print "haschanged"

print j.ref.attribute #prints "original value"
## If it changed and an attribute of the Class, then
## why is it back to "original value" ?

Because the *instance* of `Test` bound to `j.ref` does not have
`attribute` it is looked up in the *class* `Test`.
Okay, I sort of see that. It's not a property of 'j' so it looks upwards
into the class.

Its not an attribute of `j.ref`!
Oops, this should read: It's not an attribute of `j`, but `j.ref`.

Ciao,
Marc 'BlackJack' Rintsch
Nov 10 '07 #14

P: n/a
On 11 10 , 10 01 , Donn Ingle <donn.in...@gmail.comwrote:
>
def pop(self):
item = self.list[-1]
del self.list[-1]
return item

Is there some reason you do all that and not a self.list.pop(0)?
Hi.
There are no special reasons I do it that way.
Just not familiar with the member function 'pop'.
Thanks for your reminding

Nov 11 '07 #15

P: n/a
On Nov 10, 8:39 pm, Marc 'BlackJack' Rintsch <bj_...@gmx.netwrote:
>
Don't think so. It's a surprise for many but then class attributes are
not that common in code or they even use this "gotcha" for
immutable default values. As long a the value isn't changed the default
value is just referenced from the class then and not every instance.
When changing default value, is there any way to change class
attribute and all referenced attributes too?

class M:
name = u"Marko"

a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name
-Marko Kevac Marko

Is there any way to get here -Kevac Kevac Kevac ?
Or what is the right way of keeping global variables in classes?
Nov 27 '07 #16

P: n/a
Kevac Marko <mk****@gmail.comwrites:
When changing default value, is there any way to change class
attribute and all referenced attributes too?

class M:
name = u"Marko"

a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name
-Marko Kevac Marko

Is there any way to get here -Kevac Kevac Kevac ?
Or what is the right way of keeping global variables in classes?
Simply assign to M.name instead of to a.name. Assigning to a.name
creates an a-specific attribute that overrides the global one.

If you insist on being able to assign to a.name to change M.name, look
up "descriptors" -- but that feels like fighting the language.
Nov 27 '07 #17

P: n/a
Kevac Marko <mke...@gmail.comwrites:
When changing default value, is there any way to change class
attribute and all referenced attributes too?
class M:
name = u"Marko"
a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name
-Marko Kevac Marko
Is there any way to get here -Kevac Kevac Kevac ?
Or what is the right way of keeping global variables in classes?
I suppose this works, but I agree with Hrvoje Niksic that you're
fighting the language, since by forcing such low level features to
behave differently you're going to end up confusing potentially
yourself, and definitely other Python programmers in the long term.

I've probably skipped lots of edge cases which will catch you out in
exciting, fun ways but other than that good luck...
import types
class Meta(type):
def __new__(metacls, name, bases, dictionary):
newClass = super(Meta, metacls).__new__(metacls, name, bases,
dictionary)
def getInstanceAttribute(self, key):
typeSelf = type(self)
if not key.startswith('__'): #If normal key
try: #To get from class
return getattr(typeSelf, key)
except AttributeError: #Not in class
#Get from instance
return super(typeSelf, self).__getattribute__(key)
else: #Else special key
#Get from instance
return super(typeSelf, self).__getattribute__(key)
newClass.__getattribute__ =
types.MethodType(getInstanceAttribute,
None,
newClass)
def setInstanceAttribute(self, key, val):
typeSelf = type(self)
if not key.startswith('__'): #If normal key
if hasattr(typeSelf, key): #If in class
return setattr(typeSelf, key, val)
else: #Else not in class
#Set in instance
return super(typeSelf, self).__setattr__(key, val)
else: #Else special key
return super(typeSelf, self).__setattr__(key, val)
newClass.__setattr__ = types.MethodType(setInstanceAttribute,
None,
newClass)
return newClass

class M(object):
__metaclass__ = Meta
name = u"Marko"
a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name
Nov 30 '07 #18

P: n/a
Kevac Marko a écrit :
On Nov 10, 8:39 pm, Marc 'BlackJack' Rintsch <bj_...@gmx.netwrote:
>Don't think so. It's a surprise for many but then class attributes are
not that common in code or they even use this "gotcha" for
immutable default values. As long a the value isn't changed the default
value is just referenced from the class then and not every instance.

When changing default value, is there any way to change class
attribute and all referenced attributes too?

class M:
name = u"Marko"

a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name
-Marko Kevac Marko

Is there any way to get here -Kevac Kevac Kevac ?
class ClassAttribute(object):
"""
If you dont understand this code, google for
+python +descriptor +protocol
"""
def __init__(self, attrname, default=""):
self.attrname = attrname
self.default = default

def __get__(self, inst, cls):
return getattr(cls, self.attrname, self.default)

def __set__(self, inst, val):
setattr(type(inst), self.attrname, val)

class M(object):
name = ClassAttribute('_name', "Marko")

a, b = M(), M()
a.name = u"Kevac"
print M.name, a.name, b.name

HTH
Nov 30 '07 #19

This discussion thread is closed

Replies have been disabled for this discussion.