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
- 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.