Who's minister of propaganda this week?

Alex Martelli aleaxit at yahoo.com
Fri Mar 16 09:33:08 EST 2001


"Neelakantan Krishnaswami" <neelk at alum.mit.edu> wrote in message
news:slrn9b2u0r.j74.neelk at alum.mit.edu...
    [snip]
> > Keying a dict on class has the unfortunate side-effect of
> > not allowing polymorphism by inheritance -- objects of classes
> > _derived from_ the one used as the key will not match.
> >
> > You can preserve this basic idea by using as key, instead of the
> > class, some ad-hoc attribute which will be inherited (if it IS
    [snip]
> I actually have a function that walks the class tree checking it
> against the dictionary, which solves this problem.  You don't need to
> add a special attribute in Python since __class__ gives you what you
> need for free.

...except it doesn't, because it's _not_ inherited -- you have
to 'manually' walk the directed acyclic graph (tree? what tree?
we have _multiple_ inheritance:-) or iterate through the dictionary's
keys (assumed to be types) using isinstance for each on your
object.

> I only added it to my toolkit recently, though, sine I tend to use
> classes like algebraic data types in ML or Haskell -- as tagged
> variants rather than designed for user-extension. I find subclassing
> friendly designs are a lot harder to design in a way that doesn't
> reveal too much internal structure.

Inheritance (of implementation) is strong coupling, yes.  But,
it IS a very handy implementation technique -- just as, in
abstract algebra, you DON'T have to prove again for groups
all the theorems you've just proved for semigroups (they get
inherited, because so do the axioms), similarly you don't
have to redo any code that already works for the baseclass
(you do have to re-*test* if you do any overriding, but that
is another issue, and doesn't affect 'pure inheritance with
no overriding').

Here's a sketch of a general-by-type dispatcher module to
ensure one can dispatch on either type OR class (and in
the latter case gets inheritance by default, unless it's
explicitly overridden):


dispatch_keys = {}
next_key = 1

def type_or_class_of(anobj):
    try:
        return anobj.__class__
    except AttributeError:
        return type(anobj)

def get_dispatch_key_for_type(atype):
    try:
        return atype._dispatch_key_
    except AttributeError:
        return dispatch_keys.get(atype)

def set_dispatch_key_for_type(atype):
    global next_key
    try:
        atype._dispatch_key_ = next_key
    except AttributeError:
        dispatch_keys.setdefault(atype,next_key)
    next_key += 1

def ensure_type_has_dispatch_key(atype):
    if get_dispatch_key_for_type(atype) is not None:
        return
    set_dispatch_key_for_type(atype)


def get_dispatch_key_for_obj(anobj):
    atype = type_or_class_of(anobj)
    return get_dispatch_key_for_type(atype)

def set_dispatch_key_for_obj(anobj):
    atype = type_or_class_of(anobj)
    set_dispatch_key_for_type(atype)

def ensure_obj_has_dispatch_key(anobj):
    atype = type_or_class_of(anobj)
    ensure_type_has_dispatch_key(atype)


Alex






More information about the Python-list mailing list