[Python-3000] Generic function PEP won't make it in time

Emin.shopper Martinian.shopper emin.shopper at gmail.com
Thu Apr 26 04:21:43 CEST 2007


On 4/25/07, Guido van Rossum <guido at python.org> wrote:

> I'm confused. Can you show a simple example of something that can be
> checked at definition time?


Sure. Below is a slightly modified example from the doctest:

>>> class AbstractCar(AbstractBaseClass): # inherit from AbstractBaseClass
to make something abstract
...     @Abstract
...     def Drive(self,x): pass

To make a class abstract, you inherit from AbstractBaseClass in order to get
the metaclass set properly and then use a function decorator to declare
methods abstract. This is similar to the proposed implementation in your
abc.py and equally pythonic or unpythonic. The following shows what happens
when you define a class that doesn't override the abstract methods:

>>> try: # illustrate what happens when you don't implement @Abstract
methods
...     class fails(AbstractCar): # an erroneous implementation of
AbstractCar
...             pass
... except AssertionError, e:  # doctest: +ELLIPSIS
...     print e
Class <class '...fails'> must override Drive to implement:
[<class '...AbstractCar'>].

The exception gets raised at definition time because the __call__ method
of the metaclass inherited from AbstractBaseClass checks whether abstract
methods have been implemented. In your implementation, you use the __new__
method of the metaclass to do the check at instantiation. If desired you
could enable/disable checking at definition and instantiation separately.

A slightly tricky point is that if something inherits DIRECTLY from
AbstractBaseClass (e.g., AbstractCar) then it is allowed to have abstract
methods that have not been overridden. This allows you to define a partial
abstraction as shown below:

>>> class AbstractFastCar(AbstractCar,AbstractBaseClass):# inherit from ABC
...     @Abstract                                        # so that
interpreter
...     def DriveFast(self): pass                        # doesn't worry
about
...                                                      # Drive being
abstract

My implementation will consider this a valid definition because
AbstractFastCar inherits DIRECTLY from AbstractBaseClass and is therefore
allowed to have abstract methods that have not been overridden. In an
earlier post you claimed that my implementation forces you to declare a
class abstract redundantly (and therefore unpythonic-ly) when this should be
inferred from the class having abstract methods. I believe you were
referring to the partially abstract class example above. I agree that this
is redundant and unpythonic, but I believe this could be fixed by having the
metaclass __call__ method check whether the class itself defines any
abstract methods so you wouldn't need partial abstractions which define
abstract methods to still inherit from AbstractBaseClass directly.

So far I believe that the main reasonable objection raised to definition
time checks is in how the following example would be handled:

>>> # Define a class that provides a helper function but is still
>>> # abstract in the sense that children must implement Drive.
>>> class AbstractCarHelper(AbstractCar,AbstractBaseClass):
...      def DriveHelper(self):
...            print 'Vroom!'

The example above has no abstract methods, but if you want to make this kind
of partial abstraction a legal definition you need to tell the interpreter
that this is still an abstract class by inheriting directly from
AbstractBaseClass. If we want def time checking, I don't see a way to make
the above definition legal without somehow telling the interpreter to allow
it to be abstract. I don't think this is unpythonic since inheriting from
AbstractBaseClass is non-redundant. In fact, one could argue that it is good
since it lets the programmer that AbstractCarHelper is still an abstract
class even though it does not directly define any abstract methods.

If you ignore the last example, I don't think having def time checks for ABC
enforcement has any disadvantages. You can easily turn off the def time
checking or have it off by default and turn it on if desired. Since def time
checks are done by __call__ and instantiation checks are done by __new__,
this shouldn't interfere with anything in the original ABC PEP. So in my
mind, the only reason to object to def time checks is if it bothers you that
the last example must inherit directly from AbstractBaseClass.



> Using the machinery currently in the PEP,
> any class that inherits an abstract method and doesn't override it is
> automatically an abstract class itself. There's nothing to complain
> about at definition time.


Yes, I see that. What I'm proposing is to have __call__ in the metaclass
complain if a class does not inherit directly from AbstractBaseClass and
does not have any abstract methods.

>From your point of view, if you have def time checks turned off by default
then the difference in using my proposal vs. the original ABC proposal all
comes from the last example. For example, your Iterator class in
abc.pyinherits from Iterable (which is abstract) and declares its own
abstract
method. Under my current implementation this would raise an error unless
Iterator also inherits from AbstractBaseClass. This is easily fixable by
having my implementation allow classes which declare their own abstract
methods to be abstract. The incompatibly I pointed out in my last example is
illustrated by the Set class in your abc.py. I believe that you want Set to
be an ABC which requires children to support the ABC requirements of its
parents while providing useful implementations of __le__, __lt__, and
__eq__. In my implementation you would need to have Set either inherit
directly from AbstractBaseClass or define at least one abstract method to
prevent an error at def time (if def time checks are on at all). Note that I
don't think it would be unpythonic to have Set inherit from
AbstractBaseClass since it provides someone reading the source code with the
useful information that this is an ABC and not a concrete implementation.

In summary, let me try to clarify what I see as the only incompatibility
between the current PEP and an ABC implementation: with def time checks
turned on you would need partial abstractions like Set to somehow indicate
that they are abstract by either inheriting directly from AbstractBaseClass
or defining at least one abstract method. If people don't like that, then I
don't have any response. But if people are worried about B&D and other
things, I think those are non-issues. B&D at runtime is no better than B&D
at def time (I think B&D at runtime is worse).



>
> Your example implementation was a bit too much code for me to read.
> :-)


No problem. Unfortunately, I think I might have made the example usage in
this post a little too long to read (but hopefully not). :)

-Emin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/python-3000/attachments/20070425/761c38c7/attachment.html 


More information about the Python-3000 mailing list