简体   繁体   中英

Enum inheriting from collections.abc.Set

I want to write an Enum that inherits from collections.abc.Set with the sole purpose of implementing the required abstract methods. The documentation suggests 3 ways of doing it and I can get it to work using option 2:

collections.abc — Abstract Base Classes for Containers

  1. Existing classes and built-in classes can be registered as “virtual subclasses” of the ABCs

But I think the Enum would look better in an API using option 1) as having the collections.abc.Set in the class signature is more explicit... So I tried this:

import collections
from enum import Enum


class MyClass(collections.abc.Set, Enum):
    AB = {1}
    CD = {1,2}

    def __iter__(self):
        pass

    def __contains__(self, key):
        pass

    def __len__(self):
        pass

And the expectable error was thrown:

 class MyClass(collections.abc.Set, Enum):

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

How would a solution using option 1) look like? (It's been asked a few times on SO, namely in this question , but not with a minimal canonical example of inheriting from a collections.abc class just to override the abstract methods in the class definition.)

Actually, what you are calling "2", that is, registering your enum as a virtual subclass is not a solution for your problem at all: registering a class as a virtual subclass does not change any of its behaviors - nor adds methods or attributes: it simply will return "True"when queried if its instances are instances of the superclass, or for the corresponding "issubclass" call.

What you have is a classic metaclass conflict - and since both metaclasses are well behaved and built to be used cooperatively - unless they are explicitly conflicting in some part, all you have to do is create a new metaclass that inherits from both metaclasses:

In [29]: from collections.abc import Set

In [30]: from enum import Enum, EnumMeta

In [31]: from abc import ABCMeta

In [33]: class CustomMeta(ABCMeta, EnumMeta): pass

In [34]: class MyClass(Set, Enum, metaclass=CustomMeta):
    ...:     AB = {1}
    ...:     CD = {1,2}
    ...:
    ...:     def __iter__(self):
    ...:         return iter(self.value)
    ...:
    ...:     def __contains__(self, key):
    ...:         key in self.value
    ...:
    ...:     def __len__(self):
    ...:         len(self.value)
    ...:

In [35]: list(MyClass.AB)
Out[35]: [1]

In [36]: list(MyClass.CD)
Out[36]: [1, 2]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM