global declarations

Bengt Richter bokr at oz.net
Tue Dec 24 11:12:20 EST 2002


On Tue, 24 Dec 2002 00:05:41 +0100 (MET), Frederik  Fuest <ffrederik at gmx.de> wrote:

>> x = 10
>> class ManagerOfX:
>>     def printIt(self):
>>         global x
>>         print x
>>         x = x + 1
>> 
>>     def restoreIt(self):
>>         global x
>>         x = 10
>> 
>> m = ManagerOfX()
>> m.printIt()
>> m.printIt()
>> m.restoreIt()
>> m.printIt()
>> 
>> 
>>   Global variables lock you into some bad patterns, make code hard to
>> reuse/scale.  Avoid their use where possible.  For example, the above
>> should
>> be rewritten as...
>> 
>> class ManageOfX:
>>     x = 10
>> 
>>     def printIt(self):
>>         print self.x
>>         self.x = self.x + 1
>> 
>>     def restoreIt(self):
>>         self.x = 10
>
>
>thank you very much, this was exactly was i needed to know!
>now i've killed almost all global variables in my code, and it runs! 

But if you are using the above, there's a good chance "it runs" doing
something different than you think ;-)

 >>> class ManageOfX:
 ...  x = 10
 ...  def printIt(self):
 ...      print self.x
 ...      self.x = self.x + 1
 ...  def restoreIt(self):
 ...      self.x = 10
 ...

Ok. Here's an instance
 >>> mx = ManageOfX()

We write what looks like an instance attribute access:
 >>> mx.x
 10

And what we got was the class variable x. So far so good, if that was the intent.
 >>> vars(mx)
 {}
This shows what instance attributes there are. None at this time.

 >>> mx.printIt()
 10
That printed the same class variable x, and used it on the right hand
side of the assignment statement, but on the left hand side, it does NOT
replace the class variable binding, it creates an instance attribute x:
 >>> vars(mx)
 {'x': 11}
As the above shows.

 >>> ManageOfX.x
 10
The class variable is still there, as the above shows.

 >>> mx.restoreIt()
 >>> vars(mx)
 {'x': 10}
The effect of restoreIt was to rebind the instance attribute,
not touching the class variable
 >>> mx.x
 10
The above saw the instance attribute, so let's get rid of it
and see what happens:
 >>> del mx.x
 >>> mx.x
 10
This is no longer the instance attribute, but the search finds the
class variable value.
 >>> vars(mx)
 {}
The above shows that the instance attribute is gone
 >>> ManageOfX.x
 10
and the class variable is still there.

If you use printIt more than one time, the presence of the instance attribute
created the first time will shadow the class attribute, and thus the addition
will succeed in accumulating. If we change the restoring value to something
different from the class variable, it will show that you can't reach a
class variable with self.x = something (unless you have defined a property
that acts on class variables, but that's a different story).

To illustrate:

 >>> class ManageOfX:
 ...  x = 10
 ...  def printIt(self):
 ...      print self.x
 ...      self.x = self.x + 1
 ...  def restoreIt(self):
 ...      self.x = 20
 ...
 >>> mx = ManageOfX()
 >>> ManageOfX.x
 10
 >>> mx.x
 10
 >>> vars(mx)
 {}
 >>> mx.restoreIt()
 >>> mx.x
 20
That was the instance attribute x not the class variable x
 >>> ManageOfX.x
 10
as you can see by accessing explicitly
 >>> vars(mx)
 {'x': 20}

There are lots of options. Defining a module that you can import into
any module in your app that needs to share app-wide-global globals
may be a good option. If the file is MyGlobals.py and you import MyGlobals,
you can access things like print MyGlobals.x and you can also set them
with MyGlobals.x = 'new value' etc.

You could also have MyGlobals.py create an instance of ManageOfX the first
time it's imported (subsequent imports don't normally re-execute the code, so
other imports will see the results of the first just like the first importer
sees it). It there were a statement in MyGlobals.py like mx = ManageOfX()
(after the class definition code) (to use the example), then you could access mx
after import MyGlobals like MyGlobals.mx.printIt() or plain MyGlobals.mx.x or
MyGlobals.ManageOfX.x etc. analogous to the way we were doing interactively.

So you can play combinations. Also, you could write __init__ code in the
ManageOfX class to read a config file or whatever, and store things in the
mx instance. If you want to have actions triggered when you access what looks
like ordinary instance attributes, you can define properties in its class
definition to do anything you like. So there is tremendous flexibility ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list