[Python-ideas] Abstract metaclasses?

Erik Bray erik.m.bray at gmail.com
Thu Sep 11 01:00:07 CEST 2014


On Wed, Sep 10, 2014 at 6:29 PM, Ethan Furman <ethan at stoneleaf.us> wrote:
> On 09/10/2014 03:15 PM, Erik Bray wrote:
>>
>> On Wed, Sep 10, 2014 at 5:41 PM, Ethan Furman <ethan at stoneleaf.us> wrote:
>>>
>>> On 09/10/2014 01:59 PM, Erik Bray wrote:
>>>>
>>>>
>>>>
>>>> --> import abc
>>>> --> class Meta(type, metaclass=abc.ABCMeta):
>>>> ...     @abc.abstractmethod
>>>> ...     def foo(cls): pass
>>>> ...
>>>> --> class A(metaclass=Meta): pass
>>>> ...
>>>> --> A
>>>> <class '__main__.A'>
>>>
>>>
>>>
>>> I think this is a bug.  However, if the class were:
>>>
>>>    --> class A(metaclass=Meta):
>>>    ...     def foo(self):
>>>    ...          pass
>>>    ...
>>>
>>> Then this should succeed, and I don't think your Abstractable type allows
>>> it.
>>
>>
>> I don't necessarily agree that that should succeed.  The use of an
>> abstract meta-class is basically requiring there to be a concrete
>> *classmethod* of the name "foo", (an unbound instancemethod wouldn't
>> suffice).
>
>
> If that is what you want you should use `abstractclassmethod`.


That would be fine if the classmethods were being defined in a normal
class.  And with a little rearchitecting maybe that would be a simpler
workaround for my own issues.  But I still think this should work
properly for methods belonging to a metaclass.

For that matter, I feel like this is a bug too:

>>> class Foo(metaclass=abc.ABCMeta):
...     @classmethod
...     @abc.abstractmethod
...     def my_classmethod(cls): pass
...
>>> class FooSub(Foo):
...     def my_classmethod(self):
...         pass  # Not actually a classmethod
...
>>> FooSub()
<__main__.FooSub object at 0x7f5d8b8a6dd8>

Basically, FooSub does not really implement the interface expected by
the Foo ABC.

This is especially deceptive considering that the way
classmethod.__get__ works gives the impression (to the unwary) that
the classmethod is actually a method defined on the class's metaclass:

>>> Foo.my_classmethod
<bound method ABCMeta.my_classmethod of <class '__main__.Foo'>>


>> What maybe *should* work, but doesn't with this implementation is:
>>
>> class A(metaclass=Meta):
>>      @classmethod
>>      def foo(cls):
>>          pass
>
>
> Well, take out the 'maybe' and I'm in agreement.  ;)
>
>
>> Alternatively it could just be required that an abstract metaclass
>> simply can't be used as a metaclass unless a concrete subclass is
>> made.
>
>
> -1
>
>> But using @classmethod to override abstract class methods does
>> make some intuitive sense.
>
>
> +1

That's fine.  I think that can be done.

Thanks,
Erik


More information about the Python-ideas mailing list