diff options
Diffstat (limited to 'Lib/enum.py')
-rw-r--r-- | Lib/enum.py | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/Lib/enum.py b/Lib/enum.py index 7cb9d45b32..b8787d19b8 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -106,12 +106,20 @@ class EnumMeta(type): raise ValueError('Invalid enum member name: {0}'.format( ','.join(invalid_names))) + # create a default docstring if one has not been provided + if '__doc__' not in classdict: + classdict['__doc__'] = 'An enumeration.' + # create our new Enum type enum_class = super().__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = OrderedDict() # name->value map enum_class._member_type_ = member_type + # save attributes from super classes so we know if we can take + # the shortcut of storing members in the class dict + base_attributes = {a for b in enum_class.mro() for a in b.__dict__} + # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} @@ -165,6 +173,11 @@ class EnumMeta(type): else: # Aliases don't appear in member names (only in __members__). enum_class._member_names_.append(member_name) + # performance boost for any member that would not shadow + # a DynamicClassAttribute + if member_name not in base_attributes: + setattr(enum_class, member_name, enum_member) + # now add to _member_map_ enum_class._member_map_[member_name] = enum_member try: # This may fail if value is not hashable. We can't add the value @@ -199,7 +212,7 @@ class EnumMeta(type): """ return True - def __call__(cls, value, names=None, *, module=None, qualname=None, type=None): + def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1): """Either returns an existing member, or creates a new enum class. This method is used both when an enum class is given a value to match @@ -211,7 +224,7 @@ class EnumMeta(type): `value` will be the name of the new class. `names` should be either a string of white-space/comma delimited names - (values will start at 1), or an iterator/mapping of name, value pairs. + (values will start at `start`), or an iterator/mapping of name, value pairs. `module` should be set to the module this class is being created in; if it is not set, an attempt to find that module will be made, but if @@ -227,7 +240,7 @@ class EnumMeta(type): if names is None: # simple value lookup return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type - return cls._create_(value, names, module=module, qualname=qualname, type=type) + return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start) def __contains__(cls, member): return isinstance(member, cls) and member._name_ in cls._member_map_ @@ -298,16 +311,16 @@ class EnumMeta(type): raise AttributeError('Cannot reassign members.') super().__setattr__(name, value) - def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None): + def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None, start=1): """Convenience method to create a new Enum class. `names` can be: * A string containing member names, separated either with spaces or - commas. Values are auto-numbered from 1. - * An iterable of member names. Values are auto-numbered from 1. + commas. Values are incremented by 1 from `start`. + * An iterable of member names. Values are incremented by 1 from `start`. * An iterable of (member name, value) pairs. - * A mapping of member name -> value. + * A mapping of member name -> value pairs. """ metacls = cls.__class__ @@ -318,7 +331,7 @@ class EnumMeta(type): if isinstance(names, str): names = names.replace(',', ' ').split() if isinstance(names, (tuple, list)) and isinstance(names[0], str): - names = [(e, i) for (i, e) in enumerate(names, 1)] + names = [(e, i) for (i, e) in enumerate(names, start)] # Here, names is either an iterable of (name, value) or a mapping. for item in names: @@ -474,10 +487,9 @@ class Enum(metaclass=EnumMeta): m for cls in self.__class__.mro() for m in cls.__dict__ - if m[0] != '_' + if m[0] != '_' and m not in self._member_map_ ] - return (['__class__', '__doc__', '__module__', 'name', 'value'] + - added_behavior) + return (['__class__', '__doc__', '__module__'] + added_behavior) def __format__(self, format_spec): # mixed-in Enums should use the mixed-in type's __format__, otherwise |