[Python-Dev] ABCs and MRO

P.J. Eby pje at telecommunity.com
Mon Mar 2 16:52:57 CET 2009


At 10:41 AM 3/2/2009 +0000, Paul Moore wrote:
>2009/3/2 Benjamin Peterson <benjamin at python.org>:
> > 2009/3/1 Paul Moore <p.f.moore at gmail.com>:
> >>
> >> Is it worth getting simplegeneric exposed in 3.1
> >> (http://bugs.python.org/issue5135)? If it's going to be in 2.7, I'd
> >> like to see it hit 3.1. The patch is against trunk (for 2.7) at the
> >> moment, I'm not sure what the process would be for forward-porting it
> >> (do I generate a new patch against the py3k branch, or should it be
> >> applied to trunk and merged in?)

By the way guys, are you aware of:

   http://pypi.python.org/pypi/simplegeneric

There might be a bit of name confusion by exposing pkgutils' internal 
simplegeneric there.  Perhaps it should be called "trivialgeneric", 
as it's even tinier than simplegeneric.  ;-)


>The key problem with the patch is that ABCs do not play well with the
>type of introspection required to implement a generic function -
>namely enumeration of the superclasses of a class. The MRO of the
>class is fine for normal inheritance, but for ABCs it is possible to
>register classes which don't inherit from the ABC, so that you have a
>situation where issubclass (C, MyABC) can be true without MyABC being
>in C.__mro__:
>
> >>> import abc
> >>> class MyABC(object):
>...     __metaclass__ = abc.ABCMeta
>...
> >>> class C(object):
>...     pass
>...
> >>> MyABC.register(C)
> >>> issubclass(C, MyABC)
>True
> >>> C.__mro__
>(<class '__main__.C'>, <type 'object'>)
> >>>
>
>More generally, there is NO WAY to determine the list of classes for
>which issubclass(C, x) is true.
>
>This could be considered a limitation of, or a bug in, ABCs, I don't
>have a particular opinion on that, but it does mean that no code which
>relies on being able to traverse the class inheritance graph will see
>ABCs. One particular case of this is (any implementation I can think
>of, of) generic functions.
>
>In my view, this implies one of the following:
>
>1) It should be a documented limitation of such code that it doesn't
>work with ABCs (and conversely, this limitation of ABCs should be
>documented in the ABC documentation)
>2) Generic functions, and any other code requiring this type of
>introspection, is essentially useless unless it can support ABCs, and
>should not be used in the light of this limitation.
>3) This is a bug in ABCs and should be fixed.
>4) Something else I didn't think of :-)
>
>In my view, (2) is an unreasonable position to take, given the fact
>that (as I understand it) ABCs are supposed to be largely optional and
>shouldn't affect code that doesn't care about them...
>
>It's not clear to me how (3) should be addressed. Adding a slot to all
>classes to hold a list of ABCs they are registered against seems to be
>a large overhead for a relatively rarely used feature. I guess having
>a global registry of ABC registrations could work, but it seems
>clumsy. Any other suggestions?

This isn't really a new problem; if you base your generic function 
methods off of interfaces implemented by a type or instance, you have 
the same basic issues.

For systems that use a cache based on object type (like Guido's 
tuple-dispatch prototype, and my enhanced version in PEAK-Rules), the 
actual lookup is not a big deal.  You have a type-based test and you 
cache the result for the type.

PEAK-Rules' predicate dispatching is a bit more complex, because you 
need a rather more complex type test; the tree generator has to look 
at whether a type test is an ABC, and effectively translate it to 
"oldstyleisinstance(arg, ABC) or not oldstyleisinstance(arg, ABC) and 
ABC.__instancecheck__(arg)".  (Where oldstyleisinstance represents an 
__instancecheck__-free version of isinstance.)

This isn't a major problem either, just a bit of a bore/pain to implement.

The hairier issue for these types of systems is method precedence, 
though.  Since __mro__'s have to be consistently ordered, you can 
straightforwardly determine whether one class is "more specific" than 
another in a static way.  But with dynamic registration, the question 
could be more complex.

Personally, I'd like to see some way to subscribe to changes in ABC 
registration, so that generic functions or other tools can update 
their caches.  With that feature, you might even be able to implement 
full ABC support for simplegeneric, by treating ABC registrations as 
equivalent to mass registration of the ABC's registrants.

That is, if "AnABC.register(X)" and "afunc.register(AnABC, meth)" 
then "afunc.register(X, meth)".  So each time AnABC gets a new 
registrant, you automatically register the ABC method for the new 
registrant, as long as there's not already a method registered for 
that specific type.  That would probably be sufficient for what 
simplegeneric is doing.



More information about the Python-Dev mailing list