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

Emin.shopper Martinian.shopper emin.shopper at gmail.com
Thu Apr 26 04:37:41 CEST 2007


References to __call__ in my post should have been to __init__. Apologies
for the error.

-Emin


On 4/25/07, Emin.shopper Martinian.shopper <emin.shopper at gmail.com> wrote:
>
> 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/01dfd8a3/attachment-0001.html 


More information about the Python-3000 mailing list