[Zope-dev] 'issubclass' and 'isinstance' on ExtensionClasses

Greg Ward gward@mems-exchange.org
Wed, 5 Jul 2000 14:39:53 -0400


Hi all --

surely I'm not the first to deal with this: I use 'isinstance()' a lot,
and 'issubclass()' occasionally, for run-time type-checking.  This
breaks when using ZODB Persistent classes, or any other type of
ExtensionClass for that matter.

I see no use of 'issubclass()' in the Zope lib/python directory, and
only a few scattered uses of 'isinstance()'.  (Checked both 2.1.5 and
2.2b2.)  So maybe I *am* the first to worry about this.  I'm surprised
that ExtensionClass doesn't include enhanced versions of 'issubclass()'
and 'isinstance()', though.

So, here are my versions.  Critiques welcome.  In particular, is
"type(X) is not ClassType and hasattr(X, '__bases__')" an adequate
determination that X is indeed an extension class?

If you folks want to include these with ExtensionClass (possibly with
the leading "ec_" trimmed from the names), be my guest.

--snip snip-------------------------------------------------------------
def ec_issubclass (class1, class2):
    """A version of 'issubclass' that works with extension classes
    as well as regular Python classes.
    """

    # Both class objects are regular Python classes, so use the
    # built-in 'issubclass()'.
    if type(class1) is ClassType and type(class2) is ClassType:
        return __builtin__.issubclass(class1, class2)

    # Both so-called class objects have a '__bases__' attribute: ie.,
    # they aren't regular Python classes, but they sure look like them.
    # Assume they are extension classes and reimplement what the builtin
    # 'issubclass()' does behind the scenes.
    elif hasattr(class1, '__bases__') and hasattr(class2, '__bases__'):
        # XXX it appears that "ec.__class__ is type(ec)" for an
        # extension class 'ec': could we/should we use this as an
        # additional check for extension classes?

        # Breadth-first traversal of class1's superclass tree.  Order
        # doesn't matter because we're just looking for a "yes/no"
        # answer from the tree; if we were trying to resolve a name,
        # order would be important!
        stack = [class1]
        while stack:
            if stack[0] is class2:
                return 1
            stack.extend(list(stack[0].__bases__))
            del stack[0]
        else:
            return 0

    # Not a regular class, not an extension class: blow up for consistency
    # with builtin 'issubclass()"
    else:
        raise TypeError, "arguments must be class or ExtensionClass objects"

# ec_issubclass ()


def ec_isinstance (object, klass):
    """A version of 'isinstance' that works with extension classes
    as well as regular Python classes."""

    if type(klass) is ClassType:
        return isinstance(object, klass)
    elif hasattr(object, '__class__'):
        return ec_issubclass(object.__class__, klass)
    else:
        return 0
    
# ec_isinstance ()
--snip snip-------------------------------------------------------------

-- 
Greg Ward - software developer                gward@mems-exchange.org
MEMS Exchange / CNRI                           voice: +1-703-262-5376
Reston, Virginia, USA                            fax: +1-703-262-5367