Setting a Global Default for class construction?
Geoff Gerrietts
geoff at gerrietts.net
Fri Jan 31 17:55:22 EST 2003
Quoting Josh English (english at spiritone.com):
> Here is the code that I am struggling with in a Python module:
>
> _Thing = "it"
>
> def SetThing(s):
> global _Thing
> _Thing = str(s)
>
> class NewThing:
> def __init__(self,thing=_Thing):
> self.Thing = _Thing
>
> I thought that this would work if I called:
>
> >>>SetThing('hallo')
> >>>a = NewThing()
> >>>a.Thing
> 'it'
>
> I would expect a.Thing to return 'hallo', not 'it'. Is this possible to
> do in Python?
Lots of ways to do it. The quick and dirty way is not as nice as the
easy way, so we'll do the easy way:
class _ThingClass:
thing = "it"
_Thing = _ThingClass()
def SetThing(s):
global _Thing
_Thing.thing = str(s)
class NewThing:
def __init__(self, thing=_Thing):
self.Thing = thing.thing
def alternate_init(self):
self.Thing = _Thing.thing
def second_alternate(self):
self.Thing = _Thing
Now, the code will do roughly what you expect.
>>> SetThing('hallo')
>>> a = NewThing()
>>> a.Thing
'hallo'
But one thing that's important to note is that if we continue, it
might not.
>>> SetThing('goodbye')
>>> a.Thing
'hallo'
The issue you're running up against is that your assignment in
SetThing is changing which object (string) the global name "_Thing" is
bound to. You're not changing some object "_Thing", you're pointing
the name "_Thing" at some new object.
In your example, the name "self.Thing" is being pointed at the value
of the global name "_Thing", at construction time for the instance.
When the object is constructed, _Thing points at "it".
Meanwhile, thing=_Thing is pointing the name "thing" at the object
pointed to by the global name "_Thing". This assignment is performed
at "compile-time", when the __init__ function is defined. That means
"thing" will always point at "it", regardless of when you instantiate
your objects.
A rough diagram:
before SetThing:
+---------+ +------+
| _Thing | ----------> | "it" |
+---------+ +------+
+---------+
| "hallo" |
+---------+
after SetThing:
+------+
| "it" |
+------+
+---------+ +---------+
| _Thing | ----------> | "hallo" |
+---------+ +---------+
In the revised code example, __init__ assigns the local name "thing"
to the object pointed to by the global name "_Thing". The global name
"_Thing" points to an instance of the _ThingClass class. Then, we
assign the name "self.thing" to point at the "thing" attribute on that
object. This results in the behavior you were expecting, because the
object never changes -- its attributes do.
A diagram:
before SetThing:
+---------+ +--------+
| _Thing |-->| object |
+---------+ |--------| +------+
| *thing |--->| "it" |
+--------+ +------+
+---------+
| "hallo" |
+---------+
after SetThing:
+------+
| "it" |
+---------+ +--------+ +------+
| _Thing |-->| object |
+---------+ |--------| +---------+
| *thing |--->| "hallo" |
+--------+ +---------+
In the code example, the alternate_init is equivalent to the __init__,
but without the "optional" argument. The second_alternate doesn't do
exactly the same thing as the other examples. This second alternate
could be used to always have access to the newest _Thing.thing value,
but it would require printing a.Thing.thing instead of a.Thing.
Wow, a lot more than I meant to write on this topic, hope it helps.
--G.
--
Geoff Gerrietts "People talk fundamentals and superlatives
<geoff at gerrietts net> and then make some changes of detail."
http://www.gerrietts.net --Oliver Wendell Holmes Jr
More information about the Python-list
mailing list