Re: Nesting class definitions

Jim Roskind (jar@infoseek.com)
Fri, 29 Jul 1994 22:01:51 -0700

> Date: Fri, 29 Jul 1994 23:59:05 -0400 (EDT)
> From: Paul Everitt <paul@cminds.com>
>
> Can you nest class definitions? I have a subclass that only needs to be
> seen within an instance of the parent class:
>
> class FORM(BaseEntTag):
> def __init__(self,owner,action,method,enctype,value):
> ...
>
> class TEXTAREA:
> def __init__(self,value):
> self.value=value
> def render(self):
> print '<TEXTAREA>'+self.value+'</TEXTAREA>'
> class --other tags for forms that don't belong anywhere else--
>
> Then, I want to say:
> form1=FORM('http://localhost/cgi-bin/foo.py','POST, \
> '',[TEXTAREA('Some text'),TEXTAREA('Some text') ])
>
> The point is, those are tags that are meaningful only to the FORM class.
> When I make the FORM class definition, with the nested class, the
> interpreter allows it. However, when I create the instance above, I get a
> NameError for TEXTAREA.

The short answer is that you could say "FORM.TEXTAREA" rather than
"TEXTAREA" in your call and it would "work," but you might want to do
some of the stuff that I'll talk about in a second.

> So, where is the TEXTAREA class in the NameSpace, and how could I use it?

I *think* that the term "NameSpace" carries some baggage that means
"static or unchanging lexical scope." The right phrase is that
"TEXTAREA" is entered into the dictionary (a potentially dynamic and
changing entity) when the above nested definitions are interpreted.
This dictionary can be accessed using the "FORM." prefix. In
addition, this class dictionary is used as an "alternate place to
look" for names referenced in an instance of class FORM. Hence, if
"f" is an instance of class "FORM," and "f" doesn't have a member
(a.k.a., slot) called "TEXTAREA," then "f.TEXTAREA" will also resolve
(dynamically, at run time) to be the class "FORM.TEXTAREA." I talked
about these lookup rules in a recent posting, and this is yet another
related example of how the dynamic lookup rules are applied in the
"same old way." The Python Ref Manual is clearly the place to go to
read about this stuff, but seeing a bunch of examples also helps clear
it up.

Anyway... IF you really wanted some name hiding, and "TEXTAREA" was
really only significant to folks inside the FORM class, then it seems
pretty strange to force callers to write the name "TEXTAREA" at all
:-). As usual, I have no idea what you are really doing (it's always
kinda' hard to tell when looking at a fragment), but you *might*
consider hiding the apparent application of the TEXTAREA constructor
*inside* the class (since you said that only the class should know
about it). Hence, instead of my suggested working version of your
assignment:

> form1=FORM('http://localhost/cgi-bin/foo.py','POST, \
> '',[FORM.TEXTAREA('Some text'),FORM.TEXTAREA('Some text') ])

IF you really had to construct these TEXTAREA objects from each
string in a list, you might re-craft the constructor for FORM to
accept a call like:

> form1=FORM('http://localhost/cgi-bin/foo.py','POST, \
> '',['Some text', 'Some text'])

Which would be a lot easier to write ;-), and would preserve the
modularity you suggested (folks outside don't know about TEXTAREA).
Your constructor for FORM would then have to apply the TEXTAREA
constructor to the list of strings it was given. It would probably
look like (I'm not really running the code through python, 'cause I'm
lazy ;-) ):

class FORM(BaseEntTag):
def __init__(self,owner,action,method,enctype,value):
self.owner=owner
self.action=action
self.method=method
self.enctype=enctype
self.value = map(FORM.TEXTAREA, value)

class TEXTAREA:
...

And just to make clear what I was saying, you could equally well (at
least from a correctness point of view) have defined the __init__
function for FORM as:

class FORM(BaseEntTag):
def __init__(self,owner,action,method,enctype,value):
self.owner=owner
self.action=action
self.method=method
self.enctype=enctype
self.value = map(self.TEXTAREA, value)

class TEXTAREA:
...

Note that in this case (the first lines of code to touch a virgin
instance of FORM) I *know* that "self" does not have any slots named
"TEXTAREA," and hence I'm assured that "self.TEXTAREA" will evaluate
to the same class as "FORM.TEXTAREA".

Jim

Jim Roskind
voice: 408.982.4469
fax: 408.986.1889
jar@infoseek.com