Welcome, guest | Sign In | My Account | Store | Cart

People used to Java often want Python to have inner classes - that is, classes that can not be instantiated without being associated with an instance of their containing class. There are probably a great many ways to do this. Here's one of them.

Python, 34 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Outer(object):
    class Inner(object):
        def __init__(self, outer):
            self.outer = outer

import new
Outer.Inner = new.instancemethod(Outer.Inner, None, Outer)

# That's it. Now you cannot create an Inner without an Outer.

# For a more self-contained solution using metaclasses:
def hasinnerclasses(classname, bases, d):
    import new, types
    klass = new.classobj(classname, bases, d)
    for name,cls in d.items():
        if isinstance(cls, (type, types.ClassType)):
            setattr(klass, name, new.instancemethod(cls, None, klass))
    return klass

class Outer(object):
    __metaclass__ = hasinnerclasses
    class Inner(object):
        def __init__(self, outer):
            self.outer = outer

    
>>> out = Outer()
>>> inr = out.Inner() # Note that *both* arguments are supplied automatically
>>> inr.outer is out
True

# Trying to cheat doesn't work...
>>> cheat = Outer.Inner() #fails
>>> cheat = Outer.Inner('foo') #also fails

The biggest drawback to this recipe is that your inner classes end up having the type 'instancemethod', instead of 'type' or 'classobj', so introspection of the outer class would be misleading unless you know what's going on.

2 comments

Gonçalo Rodrigues 18 years, 1 month ago  # | flag

Why? Could you explain why a Python programmer would want Java-style inner classes? As far as I remember (admittedly not much) inner classes are used to fake closures, a non-issue in Python. So why would a Python programmer want them?

Actually, I think anonymous classes are what Java uses to fake closures. Named inner classes, as far as I know, are used simply to express a constraint of the object-oriented design - that it makes no sense for an instance of the inner class to exist without an associated instance of the enclosing class.

This recipe is just a way to express and enforce that same constraint in Python.

To be honest, I haven't used this recipe myself - it just occured to me when I noticed in the documentation of new.instancemethod that the first agument can be any callable - it does not specifically have to be a function.

Off the top of my head, I can imagine using it for something like:

file = Menu("&File")
open = file.MenuItem("&Open")
exit = file.MenuItem("E&xit")
Created by Chris Perkins on Wed, 5 Nov 2003 (PSF)
Python recipes (4591)
Chris Perkins's recipes (5)

Required Modules

  • (none specified)

Other Information and Tasks