I wondered if anyone had ideas about a design pattern I've been playing with. Is it perverse?
I don't want to create global variables at the module level, but have a lot of information that many objects need to share and keep current about, possibly update. I don't always know these variables at the time my objects get initialized. Some become available later.
So the idea is to have my classes inherit from a base class the main purpose of which is to get runtime "globals". These may be defined well after the subclass objects have been initialized.
Also, I don't explicitly initialize this shared parent class either (it doesn't have an __init__ method) -- I just stuff it with variables at the class level when I want to communicate them to the children.
I think I might find it confusing because of the way names get bound to certain things at class level, but overridden at the instance level. Like this:
class Holder: ... pass ... class Foo(Holder): ... def __init__(self): ... self.a = 1 ... o=Foo() o.a 1 Holder.b = 3 o.b 3 class Goo(Holder): ... def __init__(self): ... self.q = 2 ... k=Goo() k.q 2 k.b 3 o.b=5 k.b 3 Holder.b=5 k.b 5 k.b=7 Holder.b 5
So, one instance changing the value does not change it in other instances, unless they all always explicitly access it as Holder.x What I have done (and I am certainly not saying it is the best way, or even any better than what you have) is to create a separate module that just holds a bunch of names that many other modules need to access. Everyone always refers to it by it's full name and so everyone always has the same information. It's kind of a global namespace that is not global, if that makes any sense. In pygsear, it is the conf module. Some things that I keep in there are the size of the window, sound system status, time count (ticks), and I am probably going to put a handle for the currently running Game instance there too. _________________________________________________________________ Add photos to your messages with MSN 8. Get 2 months FREE*. http://join.msn.com/?page=features/featuredemail
I think I might find it confusing because of the way names get bound to certain things at class level, but overridden at the instance level.
I think you're right. It's not that great a design pattern, for the reason you mention: children can't easily update each other. This pattern is mainly for when the children don't have their own versions of the same variables -- basically read-only access to the parent is what's going on here. If I want children to all update the same variables, one option is to stuff a globals class into the parent and then update it explicitly, as you say.
class Globals: # some shared variables a = 1 b = 2
class Foo:
globals = Globals() def __init__(self): x = 1
o1 = Foo() o2 = Foo() o1.globals.a 1 o1.globals.a = 1999 o2.globals.a 1999
I can also stick new attributes into Foo.globals at runtime, and they'll join the pack of shared updatables.
What I have done (and I am certainly not saying it is the best way, or even any better than what you have) is to create a separate module that just holds a bunch of names that many other modules need to access. Everyone always refers to it by it's full name and so everyone always has the same information.
Interesting approach. The general idea is we're looking to create a shared namespace that's not truly global, but still lets as many objects as we like in on the same secrets.
It's kind of a global namespace that is not global, if that makes any sense.
Sure.
In pygsear, it is the conf module. Some things that I keep in there are the size of the window, sound system status, time count (ticks), and I am probably going to put a handle for the currently running Game instance there too.
That's very similar to my challenge: I'm working on one of those multi-banded reports, with title, summary, group and detail bars (headers, footers). All these objects need to share information about the page, especially how much room is left before a page break is required. Kirby
Keeping state shared across many instances is what the Singleton pattern is commonly used for. Alex Martelli has a great recipe on the Python Cookbook site about how to create instance variables which share state, called the Borg pattern[1]. This may be overkill for what you're doing, but it offers an interesting perspective. In the situation you describe I've taken several tactics. One is to have a *single* global object to store preferences or other shared state. Another is to pass the shared state around in one object that various parts of the system all have access to. And the Extreme Programming folks would preach YAGNI (You Ain't Gonna Need It). There is a perception that globals are evil and should never be used, but a) python's namespaces already help protect from the worst aspects of globals (most 'globals' are really module-local), and b) if a program is small or one-off it doesn't make sense to overdesign it just to remove globals that won't effect anything. My first drafts of programs are often littered with globals. When I have a working version and want to add more utility, or reuse bits in another program, or find it growing to the point that the globals are getting in the way, I refactor them into a single object and use it as above. But only after I find myself returning to the program again and again, so that I know the effort will be worth it. --Dethe "the city carries such a cargo of pathos and longing that daily life there vaccinates us against revelation" -- Pain Not Bread, The Rise and Fall of Human Breath
In the situation you describe I've taken several tactics. One is to have a *single* global object to store preferences or other shared state. Another is to pass the shared state around in one object that various parts of the system all have access to.
I've sort of gone with the single global object, but it's not really global, it's an object in the base class which only the object's children (subclasses) share and communicate through.
And the Extreme Programming folks would preach YAGNI (You Ain't Gonna Need It). There is a perception that globals are evil and should never be used, but a) python's namespaces already help protect from the worst aspects of globals (most 'globals' are really module-local), and b) if a program is small or one-off it doesn't make sense to overdesign it just to remove globals that won't effect anything.
Yes, globals and side effects are supposedly evil. But then class methods and variables are supposedly *not* evil. So by making my "globals" live in the mind of the parent class, I'm really just exploiting the power of inheritance.
My first drafts of programs are often littered with globals. When I have a working version and want to add more utility, or reuse bits in another program, or find it growing to the point that the globals are getting in the way, I refactor them into a single object and use it as above. But only after I find myself returning to the program again and again, so that I know the effort will be worth it.
--Dethe
A good strategy. Don't waste a lot of time polishing one-off code (or even infrequently needed code) to make it text book perfect. Life is short. Kirby
participants (3)
-
Dethe Elza
-
Kirby Urner
-
Lee Harr