I'm new to Python, but I've managed to make some nice progress up to this point. After some code refactoring, I ran into a class design problem and I was wondering what the experts thought. It goes something like this:
On Wed, Dec 2, 2009 at 8:55 PM, cmckenzie <mckenzi...@gmail.com> wrote: > Hi.
> I'm new to Python, but I've managed to make some nice progress up to > this point. After some code refactoring, I ran into a class design > problem and I was wondering what the experts thought. It goes > something like this:
> I can't figure out what the correct way to construct the "nested" > class so it can belong to "module".
> I want a class level construct of "nested" to belong to "module", but > I keep getting nestedClass isn't defined.
Here's the scoping reason why it fails (remember that the nested class is a class variable of the containing class):
<BEGIN PENDING FAQ SUBMISSION>
Why do I get errors when accessing class variables (a.k.a. static variables)? --------------------------------------------------------------------------- ---------- If you try something like the following::
class Foo(object): class_variable = 42
def method(self, x): return x + class_variable
Foo().method(7)
You'll get an error about Python being unable to find the class variable::
Traceback (most recent call last): ... NameError: global name 'class_variable' is not defined
This is because class-level scope is not consulted when looking up plain names in methods. When looking up a name, the following scopes are consulted, in order: Local variables, Variables in nested functions, Global variables, and finally, Built-ins.
To refer to class variables, you must be more explicit. There are several ways to go about it:
* Refer to the class by name::
def method1(self, x): return x + Foo.class_variable
* Refer to the class of the object dynamically. If you class is subclassed, this will allow the subclasses to override the value of the class variable. ::
def method2(self, x): return x + self.__class__.class_variable
* Exploit the fact that attribute lookups on an object fall back to its class. Be warned that if you have both instance and class variables with the same name, the instance variable will shadow the class variable. ::
def method3(self, x): return x + self.class_variable
* If your method is not truly an instance method (i.e. does not utilize ``self``), make it a class method ::
@classmethod def method4(cls, x): return x + cls.class_variable
<END FAQ EXCERPT>
However, there's pretty much no reason to nest classes anyway in Python (it's not Java!). Just make them both top-level in the file. If one class is only used internally in the module, just use the normal private naming convention of starting its name with an underscore.
Also note that class names should generally use StudlyCaps, and that naming a class "module" is rather confusing.
Cheers, Chris -- If the Python.org webmasters are listening, add the FAQ entry already! http://blog.rebertia.com
On Wed, Dec 2, 2009 at 11:55 PM, cmckenzie <mckenzi...@gmail.com> wrote: > Hi.
> I'm new to Python, but I've managed to make some nice progress up to > this point. After some code refactoring, I ran into a class design > problem and I was wondering what the experts thought. It goes > something like this:
> I'm new to Python, but I've managed to make some nice progress up to > this point. After some code refactoring, I ran into a class design > problem and I was wondering what the experts thought. It goes > something like this:
Python will not look into the current class scope when trying to resolve "nested", that is why the explicit call including the scope is required. The code above runs fine with python 2.5.
Chris Rebert wrote: > On Wed, Dec 2, 2009 at 8:55 PM, cmckenzie <mckenzi...@gmail.com> wrote:
>> Hi.
>> I'm new to Python, but I've managed to make some nice progress up to >> this point. After some code refactoring, I ran into a class design >> problem and I was wondering what the experts thought. It goes >> something like this:
>> I can't figure out what the correct way to construct the "nested" >> class so it can belong to "module".
>> I want a class level construct of "nested" to belong to "module", but >> I keep getting nestedClass isn't defined.
> Here's the scoping reason why it fails (remember that the nested class > is a class variable of the containing class):
> [snip interesting reminder/faq]
> However, there's pretty much no reason to nest classes anyway in > Python (it's not Java!).
A little bit off topic,ahere is a nested class pattern I'm using quite often :
class Device """Holds the different device services."""
class OS: # UPPERCASE means it holds constants """Operating system of one device.""" VXWORKS = 'vxWorks' ECOS = 'ecos'
def init(self, _os = None): self.os = _os
device = Device(Device.OS.VXWORKS)
Whenever I get a Device instance in my code I can match its OS without tedious imports:
# no "from whatever import Device" is required if device.os is device.OS.VXWORKS: print 'you are using vxWorks'
I'm using this pattern whenever I can now: 1/ it removes all magically 'inside code' defined strings or numbers, only class attributes are used. 2/ if required, it allows to write complete and detailed documentation for nested class constants 3/ you can match attributes with the nested class values without further import, everything is accessible from the instance itself
Sigh, I'm using Google Groups and it seems I can't see my original post and everyone's replies. I'm really keen to reply back, so I'll just re-post my follow up for now and make sure I don't make a habit of this. (I'll get a news reader) Here goes:
I agree, I'm C# and Java influenced, but I've got some messy Perl experience too.
It was late when I posted my example, so I don't think I made my question clear enough. I want to be able to construct a class level class variable, so its global to the class, then reference it from a class method. I wrote a web server that uses reflection to dynamically load modules which are mapped to url paths. e.g. module "search.py" maps to "search.html", etc... It all works great, but I want my modules to be able to __init__ classes that belong to the module, then when a request comes in and is passed to the module, I can reference that initialized class.
The declaration of a class level nestedClass class variable is wrong, but I was hoping someone could just say, "dummy, this is how to declare a class variable when you can't construct it just yet", or "you have to construct an empty version of nestedClass at the class level, then just re-construct it with any parameters during __init__".
> Sigh, I'm using Google Groups and it seems I can't see my original > post and everyone's replies. I'm really keen to reply back, so I'll > just re-post my follow up for now and make sure I don't make a habit > of this. (I'll get a news reader) Here goes:
> I agree, I'm C# and Java influenced, but I've got some messy Perl > experience too.
> It was late when I posted my example, so I don't think I made my > question clear enough. I want to be able to construct a class level > class variable, so its global to the class, then reference it from a > class method. I wrote a web server that uses reflection to dynamically > load modules which are mapped to url paths. e.g. module "search.py" > maps to "search.html", etc... It all works great, but I want my > modules to be able to __init__ classes that belong to the module, then > when a request comes in and is passed to the module, I can reference > that initialized class.
> The declaration of a class level nestedClass class variable is wrong, > but I was hoping someone could just say, "dummy, this is how to > declare a class variable when you can't construct it just yet", or > "you have to construct an empty version of nestedClass at the class > level, then just re-construct it with any parameters during __init__".
> I can't figure out what the correct way to construct the "nested" > class so it can belong to "module".
which one you want?
1. The Outside's class contains a nested class class Outside(object): class Inside(object): ...
2. The Outside's class contains an instance of the nested class class Outside(object): class inside(object): ... inside = inside()
3. The Outside's instance contains an instance of the nested class class Outside(object): class Inside(object): ... def __init__(self): self.inside = Outside.Inside()
> Sigh, I'm using Google Groups and it seems I can't see my original > post and everyone's replies. I'm really keen to reply back, so I'll > just re-post my follow up for now and make sure I don't make a habit > of this. (I'll get a news reader) Here goes:
> I agree, I'm C# and Java influenced, but I've got some messy Perl > experience too.
> It was late when I posted my example, so I don't think I made my > question clear enough. I want to be able to construct a class level > class variable, so its global to the class,
"global to the class" that's contradictory!
> then reference it from a > class method. > I wrote a web server that uses reflection to dynamically > load modules which are mapped to url paths. e.g. module "search.py" > maps to "search.html",
Be careful of someone requesting an ../insecure.html
> etc... It all works great, but I want my > modules to be able to __init__ classes that belong to the module, then > when a request comes in and is passed to the module, I can reference > that initialized class.
When a module is "import"-ed, it's body is executed, unless you put it inside a if __name__ == '__main__': block which is only executed when the module itself is executed (instead of being imported). Basically, the module's body is like the module's __init__()
That way if your directory is like this: /data - /__init__.py - /one.py /run_server.py
your one.py would contains something like:
class MyClass(object): ... instance = MyClass()
and your run_server.py would reference the already instantiated module in the class as such:
from data.one import instance
# serve something using the instance
> The declaration of a class level nestedClass class variable is wrong, > but I was hoping someone could just say, "dummy, this is how to > declare a class variable when you can't construct it just yet", > or > "you have to construct an empty version of nestedClass at the class > level, then just re-construct it with any parameters during __init__".
That sounds like C/C++ forward declaration. Not something you'd need in a language that has dynamic name resolution.
On Thu, 03 Dec 2009 06:59:43 -0800, cmckenzie wrote: > It was late when I posted my example, so I don't think I made my > question clear enough. I want to be able to construct a class level > class variable, so its global to the class, then reference it from a > class method.
My brain is spinning, because you seem to be using terms in ways that aren't common in Python circles (or at least not familiar to *me*). This makes it really hard for me to be sure I understand you.
You say you want a "class level class variable" -- what do you mean by that? What's "class level" mean to you? When you say "class variable", do you mean "a variable that is a class", like a string variable is a variable that is a string, or do you mean an attribute of the class?
What do you mean by "global to the class"?
In your code sample, you say:
class module: nestedClass
but nestedClass isn't defined. Assuming nestedClass already exists, defined elsewhere (which implies it is NOT nested at all!) it would be syntactically legal, but meaningless. It would be as pointless as this:
class module: # Define class [1, 2, 3] # create a list and throw it away immediately
Where is nestedClass defined? Outside the class "module"? Inside the class? If so, where?
I *think* you mean you want a class attribute which happens to hold a class, which you want to be nested, but I'm not sure. If that's what you want, you would write it like this:
class module: # Horrible name, because module is a term already # used in Python for something else
class nestedclass: pass
Once you do that, you have a class "module" containing a nested class "nestedclass" which is available as a class-attribute "module.nestedclass".
> The declaration of a class level nestedClass class variable is wrong, > but I was hoping someone could just say, "dummy, this is how to declare > a class variable when you can't construct it just yet",
Python doesn't need declarations. If you can't declare something, don't. You could put a placeholder and test for it:
class K: attribute = None # Placeholder for the real value. def method(self): if self.attribute is None: print "attribute not initialised yet, this design sucks" else: print "do something useful"
or simply catch the AttributeError:
class K: def method(self): try: self.attribute except AttributeError: print "attribute not initialised yet, this design sucks" else: print "do something useful"
> or "you have to > construct an empty version of nestedClass at the class level, then just > re-construct it with any parameters during __init__".
which still makes nestedClass an attribute on the instance, not the class. To make it a class attribute, you have to refer to the class directly. Either of these will do, although the first is better because it will do the right thing if you subclass: