Welcome, guest | Sign In | My Account | Store | Cart
#
# http://code.activestate.com/recipes/577070-bound-inner-classes/
#

class BoundInnerClass(object):
    def __init__(self, cls):
        self.cls = cls

    def __get__(self, outer, outer_class):
        if not outer:
            return self.cls

        name = self.cls.__name__

        if name in outer.__dict__:
            return outer.__dict__[name]

        decorator_self = self
        class Wrapper(decorator_self.cls):
            def __init__(self, *args, **kwargs):
                decorator_self.cls.__init__(self, outer, *args, **kwargs)

            if decorator_self.cls.__repr__ is object.__repr__:
                def __repr__(self):
                    return "".join([
                        "<",
                        self.__module__,
                        ".",
                        self.__class__.__name__,
                        " object bound to ",
                        repr(outer),
                        " at ",
                        hex(id(self)),
                        ">"])

        Wrapper.__name__ = name
        setattr(outer, name, Wrapper)
        return Wrapper

if __name__ == "__main__":
    class Outer(object):
        @BoundInnerClass
        class Inner(object):
            def __init__(self, parent):
                self.parent = parent
        @BoundInnerClass
        class SubclassOfInner(Inner.cls):
            def __init__(self, parent):
                super(Outer.SubclassOfInner, self).__init__(parent)

    outer = Outer()
    inner = outer.Inner()
    assert outer.Inner == outer.Inner
    assert isinstance(inner, outer.Inner)
    assert isinstance(inner, Outer.Inner)

    subclass = outer.SubclassOfInner()
    assert isinstance(subclass, Outer.SubclassOfInner)
    assert isinstance(subclass, outer.SubclassOfInner)
    assert isinstance(subclass, Outer.Inner)

    # Sadly this unexpected behavior must stand.
    # "subclass" is an instance of outer.SubclassOfInner,
    # which is a subclass of Outer.SubclassOfInner,
    # which is a subclass of Outer.Inner.  Meanwhile,
    # outer.Inner is also a subclass of Outer.Inner.
    assert not isinstance(subclass, outer.Inner)

    class InnerChild(outer.Inner):
        pass

    inner_child = InnerChild()

    isinstance(inner_child, Outer.Inner)
    isinstance(inner_child, InnerChild)
    isinstance(inner_child, outer.Inner)

Diff to Previous Revision

--- revision 2 2010-02-26 16:01:00
+++ revision 3 2010-06-19 14:02:24
@@ -1,37 +1,41 @@
+#
+# http://code.activestate.com/recipes/577070-bound-inner-classes/
+#
+
 class BoundInnerClass(object):
-  def __init__(bound_class, cls):
-    bound_class.cls = cls
-    bound_class.cache = {}
+    def __init__(self, cls):
+        self.cls = cls
 
-  def __get__(bound_class, outer_instance, outer_class):
-    if not outer_instance:
-        return bound_class.cls
+    def __get__(self, outer, outer_class):
+        if not outer:
+            return self.cls
 
-    key = id(outer_instance)
-    wrapper = bound_class.cache.get(key)
-    if wrapper:
-        return wrapper
+        name = self.cls.__name__
 
-    class Wrapper(bound_class.cls):
-      def __init__(self, *args, **kwargs):
-          bound_class.cls.__init__(self, outer_instance, *args, **kwargs)
+        if name in outer.__dict__:
+            return outer.__dict__[name]
 
-      if bound_class.cls.__repr__ is object.__repr__:
-          def __repr__(self):
-            return "".join([
-                "<",
-                self.__module__,
-                ".",
-                self.__class__.__name__,
-                " object bound to ",
-                repr(outer_instance),
-                " at ",
-                hex(id(self)),
-                ">"])
+        decorator_self = self
+        class Wrapper(decorator_self.cls):
+            def __init__(self, *args, **kwargs):
+                decorator_self.cls.__init__(self, outer, *args, **kwargs)
 
-    Wrapper.__name__ = bound_class.cls.__name__
-    bound_class.cache[key] = Wrapper
-    return Wrapper
+            if decorator_self.cls.__repr__ is object.__repr__:
+                def __repr__(self):
+                    return "".join([
+                        "<",
+                        self.__module__,
+                        ".",
+                        self.__class__.__name__,
+                        " object bound to ",
+                        repr(outer),
+                        " at ",
+                        hex(id(self)),
+                        ">"])
+
+        Wrapper.__name__ = name
+        setattr(outer, name, Wrapper)
+        return Wrapper
 
 if __name__ == "__main__":
     class Outer(object):
@@ -44,7 +48,6 @@
             def __init__(self, parent):
                 super(Outer.SubclassOfInner, self).__init__(parent)
 
-
     outer = Outer()
     inner = outer.Inner()
     assert outer.Inner == outer.Inner
@@ -54,8 +57,14 @@
     subclass = outer.SubclassOfInner()
     assert isinstance(subclass, Outer.SubclassOfInner)
     assert isinstance(subclass, outer.SubclassOfInner)
-    assert not isinstance(subclass, outer.Inner) # funny boundary case! sorry!
     assert isinstance(subclass, Outer.Inner)
+
+    # Sadly this unexpected behavior must stand.
+    # "subclass" is an instance of outer.SubclassOfInner,
+    # which is a subclass of Outer.SubclassOfInner,
+    # which is a subclass of Outer.Inner.  Meanwhile,
+    # outer.Inner is also a subclass of Outer.Inner.
+    assert not isinstance(subclass, outer.Inner)
 
     class InnerChild(outer.Inner):
         pass

History