Skip to content

Commit c7ed59a

Browse files
committed
enum.py: Make __iter__, _update, _scan_class_attrs, list a classmethods.
igned-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
1 parent 3e10d5b commit c7ed59a

1 file changed

Lines changed: 56 additions & 34 deletions

File tree

python-stdlib/enum/enum.py

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# enum.py
2-
# version="1.2.3"
2+
# version="1.2.4"
33

44

55
class EnumValue:
@@ -11,9 +11,6 @@ def __init__(self, value, name):
1111
def __repr__(self):
1212
return f"{self.name}: {self.value}"
1313

14-
# def __str__(self):
15-
# return str(self.value)
16-
1714
def __call__(self):
1815
return self.value
1916

@@ -22,9 +19,6 @@ def __eq__(self, other):
2219
return self.value == other.value
2320
return self.value == other
2421

25-
# def __int__(self):
26-
# return self.value
27-
2822
def __setattr__(self, key, value):
2923
raise AttributeError("EnumValue is immutable")
3024

@@ -40,6 +34,9 @@ def __new__(cls, name=None, names=None):
4034
return super(Enum, cls).__new__(cls)
4135

4236
def __init__(self, name=None, names=None):
37+
if hasattr(self, '_initialized'):
38+
return
39+
4340
# 1. Convert class-level attributes (constants) to EnumValue objects
4441
self._scan_class_attrs()
4542

@@ -64,29 +61,49 @@ def _lookup(cls, value):
6461
if not callable(attr) and attr == value:
6562
# Wrap static numbers found in class definition
6663
return EnumValue(attr, key)
67-
6864
raise AttributeError(f"{value} is not in {cls.__name__}")
6965

70-
def list(self):
66+
@classmethod
67+
def __iter__(cls):
68+
if '_initialized' not in cls.__dict__:
69+
cls._scan_class_attrs()
70+
setattr(cls, '_initialized', True)
71+
72+
for key in dir(cls):
73+
if key.startswith('_'):
74+
continue
75+
attr = getattr(cls, key)
76+
if isinstance(attr, EnumValue):
77+
yield attr
78+
79+
@classmethod
80+
def list(cls):
81+
if '_initialized' not in cls.__dict__:
82+
cls._scan_class_attrs()
83+
setattr(cls, '_initialized', True)
84+
7185
# Returns a list of all members
72-
return [member for member in self]
86+
return [getattr(cls, key) for key in dir(cls)
87+
if isinstance(getattr(cls, key), EnumValue)]
7388

74-
def _update(self, key, value):
75-
setattr(self.__class__, key, EnumValue(value, key))
89+
@classmethod
90+
def _update(cls, key, value):
91+
setattr(cls, key, EnumValue(value, key))
7692

77-
def _scan_class_attrs(self):
93+
@classmethod
94+
def _scan_class_attrs(cls):
7895
# Converts static class attributes into EnumValue objects
7996
# List of methods and internal names that should not be converted
8097
ignored = ('is_value', 'list')
81-
for key in dir(self.__class__):
98+
for key in dir(cls):
8299
# Skip internal names and methods
83100
if key.startswith('_') or key in ignored:
84101
continue
85102

86-
value = getattr(self.__class__, key)
103+
value = getattr(cls, key)
87104
# Convert only constants, not methods
88105
if not callable(value) and not isinstance(value, EnumValue):
89-
self._update(key, value)
106+
cls._update(key, value)
90107

91108
def is_value(self, value):
92109
return any(member.value == value for member in self)
@@ -100,8 +117,11 @@ def __repr__(self):
100117
return f"{self.__class__.__name__}(names={members})"
101118

102119
def __call__(self, value):
120+
if '_initialized' not in self.__class__.__dict__:
121+
self._scan_class_attrs()
122+
object.__setattr__(self.__class__, '_initialized', True)
103123
for member in self:
104-
if member.value == value:
124+
if member.value == value or member.name == value:
105125
return member
106126
raise AttributeError(f"{value} is not in {self.__class__.__name__}")
107127

@@ -118,12 +138,6 @@ def __delattr__(self, key):
118138
def __len__(self):
119139
return sum(1 for _ in self)
120140

121-
def __iter__(self):
122-
for key in dir(self.__class__):
123-
attr = getattr(self.__class__, key)
124-
if isinstance(attr, EnumValue):
125-
yield attr
126-
127141
def __eq__(self, other):
128142
if not isinstance(other, Enum):
129143
return False
@@ -134,28 +148,36 @@ def __eq__(self, other):
134148
# --- Usage Example 1 ---
135149
# Standard Class Definition
136150
class Color(Enum):
137-
RED = 'red'
138-
GREEN = 'green'
139-
151+
RED = 1
152+
GREEN = 2
153+
BLUE = 3
154+
155+
print("Color.list():", Color.list())
156+
print("Color().list():", Color().list())
157+
158+
# Iteration
159+
print("Members list:", [member for member in Color()])
160+
print("Names list:", [member.name for member in Color()])
161+
print("Values list:", [member.value for member in Color()])
162+
140163
# Create instance
141164
c = Color()
142165
print(f"Enum c: {c}")
143-
print("c.list():", c.list())
144166

145167
# Basic access
146168
print(f"RED: Name={c.RED.name}, Value={c.RED.value}, EnumValue={c.RED}, Call={c.RED()} ")
147169

148170
# Assertions
149171
assert c.RED.name == 'RED'
150-
assert c.RED.value == 'red'
151-
assert c.RED == 'red'
152-
assert c.RED() == 'red'
172+
assert c.RED.value == 1
173+
assert c.RED == 1
174+
assert c.RED() == 1
153175

154176
# Reverse Lookup via instance call
155-
print(f"c('red') lookup object: {c('red')}, Name={c('red').name}, value={c('red').value}") # RED
156-
assert c('red').name == 'RED'
157-
assert c('red').value == 'red'
158-
assert c('red') == 'red'
177+
#print(f"c(1) lookup object: {c(1)}, Name={c(1).name}, value={c(1).value}") # RED
178+
assert c(1).name == 'RED'
179+
assert c(1).value == 1
180+
assert c(1) == 1
159181

160182
# Iteration
161183
print("Values list:", [member.value for member in c])

0 commit comments

Comments
 (0)