我正在尝试以一种可以很好地使用文档字符串的方式在python中实现枚举。
基本上这就是我正在做/正在尝试做的(由于长度原因,完整的可运行代码将在底部):
class Animals(EnumBase):
_dog = 'Dog'
_cat = 'Cat'
@classproperty
def dog(cls):
"""
A four legged creature that loves humans too much.
"""
return cls._dog
@classproperty
def cat(cls):
"""
Rules over humans.
"""
return cls._cat
print(Animals.dog) # Outputs 'Dog' so programmatically works perfect
我的代码在技术上可以正常工作,但是VS Code Intellisense无法读取枚举的文档字符串。例如,当我将鼠标悬停在dog
中的print(Animals.dog)
上时,将不会输出其文档字符串。我认为这是由于classproperty
装饰器引起的,但是我不知道这样做的更好方法(除非我切换到类方法,但我想避免使用[[unneeded寄生)。
完整的可运行代码如下。请注意,还有许多其他功能与当前问题无关(基本上是允许我将子类视为可迭代的代码)。
class classproperty(property):
"""
Class method property decorator. (Used via @classproperty)
A @classmethod allows us to call stuff from classes like:
Foo.bar()
A @property allows us to call functions like:
Foo().bar
But we want enum functionality with doc strings like:
Foo.bar
Thus the usecase of this decorator.
"""
def __get__(self, cls, owner):
"""
Redefining get.
"""
return classmethod(self.fget).__get__(None, owner)()
class _MetaEnum(type):
"""
Meta class needed to overload the __contains__ method for
EnumBase.
"""
def __contains__(cls, val):
"""
Opertator overload for the `in` operator at a class level.
Will return true if `x` is one of the enum values
stored in the child class of the base class.
"""
return val in cls._get_contents()
def __str__(cls):
"""
String operator overload.
"""
return ', '.join(str(x) for x in cls._get_contents())
def __iter__(cls):
"""
Returns a generator for all elements in a class.
"""
return (x for x in cls._get_contents())
class EnumBase(metaclass=_MetaEnum):
"""
An enum base class that can be inherited by Enum classses.
Allows the `in` operation to be perform as well as auto str formatting.
Example:
class Foo(EnumBase):
a = 2
b = 3
c = 4
print(2 in Foo) # True
print(Foo) # 2, 3, 4
"""
@classmethod
def _get_contents(cls):
"""
Returns a set of all different enum values.
"""
# Get all class attributes that are not methods
attributes = inspect.getmembers(cls, lambda a: not inspect.isroutiane(a))
# Turn all attributes that aren't private (such as __dict__) to a set
# and return it.
return {a[1] for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))}
class Animals(EnumBase):
_dog = 'Dog'
_cat = 'Cat'
@classproperty
def dog(cls):
"""
A four legged creature that loves humans too much.
"""
return cls._dog
@classproperty
def cat(cls):
"""
Rules over humans.
"""
return cls._cat