这就是我第一次来自的地方:
class DismRestartType(DismEnum):
DismRestartNo = 0, 'No Restart'
DismRestartPossible = 1, 'Restart Possible'
DismRestartRequired = 2, 'Restart Required'
并使用它:
class DismFeatureInfo(DismStructure):
_pack_ = 4
_fields_ = [
("FeatureName", c_wchar_p),
("RestartRequired", DismRestartType)
]
class DismEnum(Enum):
def __new__(cls, value, description):
obj = object.__new__(cls)
obj._value_ = value
obj.description = description
return obj
请注意说明的附加参数。计划是稍后显示描述而不是价值,所以我不必为每个结构本身做好准备 问题:我收到错误,因为结构需要c类型并获得枚举 我做了一些研究并发现了这个,即: Using an IntEnum as the type in a ctypes.Structure._fields_
所以我试过了:
class CEnumeration(c_int):
def __new__(cls, value, description):
obj = object.__new__(cls)
obj._value_ = value
obj.description = description
print("Will never be executed")
return obj
def __repr__(self):
return self.description
不幸的是,我得到*** AttributeError: 'DismRestartType' object has no attribute 'description'
,新方法也永远不会被执行。有人可以解释一下为什么它没有被执行并帮助我达到目标吗?
EDIT1:
我不明白!为什么__new__
未在TestEnum
中执行,但在从Enum
继承时执行?元类 new 会被执行。
class PointlessMetaClass(type(c_int)):
def __new__(meta, classname, bases, classDict):
cls = type(c_int).__new__(meta, classname, bases, classDict)
pdb.set_trace()
return cls
class TestEnum(metaclass=PointlessMetaClass):
_type_ = "i"
def __new__(cls, value):
print("Why not executed")
pdb.set_trace()
return cls
class DismRestartType(TestEnum):
DismRestartNo = 0, 'No Restart'
DismRestartPossible = 1, 'Restart Possible'
DismRestartRequired = 2, 'Restart Required'
解决方案: 我花了很长时间,但现在我明白了:
from ctypes import c_int
from types import DynamicClassAttribute
class _EnumDict(dict):
"""Track enum member order and ensure member names are not reused.
EnumMeta will use the names found in self._member_names as the
enumeration member names.
"""
def __init__(self):
super().__init__()
self._member_names = []
def __setitem__(self, key, value):
if not isinstance(value, DynamicClassAttribute) and not key.startswith("_"):
self._member_names.append(key)
super().__setitem__(key, value)
class EnumerationType(type(c_int)):
"""Metaclass for Enum."""
@classmethod
def __prepare__(metacls, cls, bases):
edict = _EnumDict()
return edict
def __new__(metacls, classname, bases, classdict):
# save enum items into separate mapping so they don't get baked into
# the new class
enum_members = {k: classdict[k] for k in classdict._member_names}
for name in classdict._member_names:
del classdict[name]
# returns an instance of the new class, i.e. an instance of my enum
enum_class = super().__new__(metacls, classname, bases, classdict)
# Reverse value->name map for hashable values.
enum_class._value2member_map_ = {}
for member_name in classdict._member_names:
value = enum_members[member_name][0]
enum_member = c_int.__new__(enum_class)
enum_member.value = value # overwrites the value attr of c_int class
enum_member._name_ = member_name
enum_member._description_ = enum_members[member_name][1]
enum_member.__objclass__ = enum_class
# i.e DismRestartType.DismRestartNo will return an object instead of the value
setattr(enum_class, member_name, enum_member)
# i.e. {'0': <class DismRestartType:DismRestartNo: 0>}
enum_class._value2member_map_[value] = enum_member
return enum_class
def __repr__(self):
return "<Enumeration %s>" % self.__name__
class CEnumeration(c_int, metaclass=EnumerationType):
"""Generic enumeration.
Derive from this class to define new enumerations.
"""
def __new__(cls, value):
# all enum instances are actually created during class construction
# without calling this method; this method is called by the metaclass'
# __call__ (i.e. Color(3) ), and by pickle
if type(value) is cls:
# For lookups like Color(Color.RED)
return value
# by-value search for a matching enum member
# see if it's in the reverse mapping (for hashable values)
try:
if value in cls._value2member_map_:
return cls._value2member_map_[value]
except TypeError:
pass
return cls._missing_(value)
@classmethod
def _missing_(cls, value):
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
# return only description
def __repr__(self):
return "<%s.%s: %r>" % (
self.__class__.__name__, self.name, self.value)
def __str__(self):
return "%s.%s" % (self.__class__.__name__, self.name)
# DynamicClassAttribute is used to provide access to the `name` and
# `value` properties of enum members while keeping some measure of
# protection from modification, while still allowing for an enumeration
# to have members named `name` and `value`. This works because enumeration
# members are not set directly on the enum class -- __getattr__ is
# used to look them up.
@DynamicClassAttribute
def name(self):
"""The name of the Enum member."""
try:
# get name on instance
return self._name_
except AttributeError:
# get name on class
return self._value2member_map_[self.value]._name_
@DynamicClassAttribute
def description(self):
"""The description of the Enum member."""
try:
# get description on instance
return self._description_
except AttributeError:
# get description on class
return self._value2member_map_[self.value]._description_