Declaring a class level nested class?

6 views
Skip to first unread message

cmckenzie

unread,
Dec 2, 2009, 11:55:06 PM12/2/09
to
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:

class module:
nestedClass

def __init__():
self.nestedClass = nested()
print self.nestedClass.nestedVar

class nested():
nestedVar = 1
def __init__(self):
print "Initialized..."

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.

My example isn't great or 100% accurate, but I hope you get the idea.

Thanks.

Chris Rebert

unread,
Dec 3, 2009, 12:13:03 AM12/3/09
to cmckenzie, pytho...@python.org
On Wed, Dec 2, 2009 at 8:55 PM, cmckenzie <mcken...@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:
>
> class module:
>   nestedClass
>
>   def __init__():
>      self.nestedClass = nested()
>      print self.nestedClass.nestedVar
>
>   class nested():
>      nestedVar = 1
>      def __init__(self):
>         print "Initialized..."
>
> 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

inhahe

unread,
Dec 3, 2009, 12:14:55 AM12/3/09
to cmckenzie, pytho...@python.org
it seems to me like it should work just fine if you just take out the
second line where it just says nestedClass

> --
> http://mail.python.org/mailman/listinfo/python-list
>

Jean-Michel Pichavant

unread,
Dec 3, 2009, 7:52:41 AM12/3/09
to cmckenzie, pytho...@python.org
class module:

class nested:


nestedVar = 1
def __init__(self):
print "Initialized..."

def __init__(self):
self.nestedClass = module.nested()
print self.nestedClass.nestedVar

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.

Jean-Michel

Jean-Michel Pichavant

unread,
Dec 3, 2009, 8:13:19 AM12/3/09
to Chris Rebert, pytho...@python.org, cmckenzie
Chris Rebert wrote:

> On Wed, Dec 2, 2009 at 8:55 PM, cmckenzie <mcken...@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:
>>
>> class module:
>> nestedClass
>>
>> def __init__():
>> self.nestedClass = nested()
>> print self.nestedClass.nestedVar
>>
>> class nested():
>> nestedVar = 1
>> def __init__(self):
>> print "Initialized..."
>>
>> 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

JM


cmckenzie

unread,
Dec 3, 2009, 9:59:43 AM12/3/09
to
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__".

class module:
nestedClass

def __init__():
self.nestedClass = nested(10)
print self.nestedClass.nestedVar

def getNestedVar(self):
return self.nestedClass.nestedVar

class nested():
nestedVar = 1

def __init__(self, value):
nestedVar = value
print "Initialized..."

Thanks and sorry for double posting, it won't happen again.

cmckenzie

unread,
Dec 3, 2009, 10:01:02 AM12/3/09
to

Ok, it seems that my original post was present, just not searchable?
Forget my confusion on this. Thanks.

Lie Ryan

unread,
Dec 3, 2009, 10:07:27 AM12/3/09
to
On 12/3/2009 3:55 PM, cmckenzie wrote:
> 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()


4.

Lie Ryan

unread,
Dec 3, 2009, 10:43:18 AM12/3/09
to
On 12/4/2009 1:59 AM, cmckenzie wrote:
> 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.

Steven D'Aprano

unread,
Dec 3, 2009, 7:30:27 PM12/3/09
to
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__".
>
> class module:
> nestedClass
>
> def __init__():
> self.nestedClass = nested(10)
> print self.nestedClass.nestedVar


That gives every instance of "module" its own instance-level attribute
called "nestedClass".

It will only work if nested is a global-level function. To call the
method called "nested" as you probably intend, you need to do this:

def __init__():
self.nestedClass = self.nested(10)
print self.nestedClass.nestedVar

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:

self.__class__.nestedClass = self.nested(10)
module.nestedClass = self.nested(10)


> class nested():
> nestedVar = 1
> def __init__(self, value):
> nestedVar = value
> print "Initialized..."


Given that every instance is given an attribute nestedVar, what's the
point of the class attribute "nestedVar"? It's never used.


--
Steven

Reply all
Reply to author
Forward
0 new messages