Strony

piątek, 4 listopada 2011

Dear Python, can I create global variables in functions or methods?

Yeeee... no. Global variables in python are global on module level only. So, the answer is noooo... yes, you can.

Having a problem of a sub-process that has to execute just a callable (function, lambda or class with __call__ defined), and following DRY, I've put common functionality in base class and then created a set of children. As this code is part of much bigger project, DIRAC, where have to follow conventions and use everywhere a set of of global variables (references to services, clients, some global functions, etc.). Of course I was going to import them in a base class, but then what?

Globals are visible at the module level, so if I put them to base class, I would be able to use them in base class module (all functions and methods over there). But what I really want, was to use them in inherited classes to.

No problem, you can always store them as a member of base... Yuck! But then instead of just calling "gGlobalVar.doSomethingForMe()" I have to call it by "self.gGlobalVar.doSomethingForMe()". Awkward! Ugly! Bad!

What come to my mind is a python sequence for looking up symbols. There is always __builtins__ module, right? And this one is first in a line of r lookup, right? So what about storing them over there?

So here is an example:


  • let's say this is our module storing "globals", say testGlobals.py:
  • and here is a base class, say testBase.py: Notice, we can't put there anything outside baseClass, as it wouldn't be visible in inherited classes at all. I'm using built-in setattr or __builtins__.__setattr__, cause in pure python __builtins__ is visible as module, but when you import baseClass elsewhere, it would be just a dictionary. If you don't believe just execute this one: once in interactive session:

    and then in batch:
  • and here it is, a testChild.py
  • at least some testing:

  • and its output:
Once you put your stuff to __builtins__, it is visible everywhere. So in fact it's a global symbol created on the fly. Of course, you can do the same with whatever object you like, i.e. os module. It would be imported in baseClass and then once you put it to the __builtins__, it would be visible in testChild.

Dear Python, if you knew how to cook and clean...