Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
c16595e5
Kaydet (Commit)
c16595e5
authored
Eyl 11, 2016
tarafından
Ethan Furman
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
issue23591: add auto() for auto-generating Enum member values
üst
944368e1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
195 additions
and
31 deletions
+195
-31
enum.rst
Doc/library/enum.rst
+83
-16
enum.py
Lib/enum.py
+37
-13
test_enum.py
Lib/test/test_enum.py
+75
-2
No files found.
Doc/library/enum.rst
Dosyayı görüntüle @
c16595e5
...
...
@@ -25,7 +25,8 @@ Module Contents
This module defines four enumeration classes that can be used to define unique
sets of names and values: :class:`Enum`, :class:`IntEnum`, and
:class:`IntFlags`. It also defines one decorator, :func:`unique`.
:class:`IntFlags`. It also defines one decorator, :func:`unique`, and one
helper, :class:`auto`.
.. class:: Enum
...
...
@@ -52,7 +53,11 @@ sets of names and values: :class:`Enum`, :class:`IntEnum`, and
Enum class decorator that ensures only one name is bound to any one value.
.. versionadded:: 3.6 ``Flag``, ``IntFlag``
.. class:: auto
Instances are replaced with an appropriate value for Enum members.
.. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto``
Creating an Enum
...
...
@@ -70,6 +75,13 @@ follows::
... blue = 3
...
.. note:: Enum member values
Member values can be anything: :class:`int`, :class:`str`, etc.. If
the exact value is unimportant you may use :class:`auto` instances and an
appropriate value will be chosen for you. Care must be taken if you mix
:class:`auto` with other values.
.. note:: Nomenclature
- The class :class:`Color` is an *enumeration* (or *enum*)
...
...
@@ -225,6 +237,42 @@ found :exc:`ValueError` is raised with the details::
ValueError: duplicate values found in <enum 'Mistake'>: four -> three
Using automatic values
----------------------
If the exact value is unimportant you can use :class:`auto`::
>>> from enum import Enum, auto
>>> class Color(Enum):
... red = auto()
... blue = auto()
... green = auto()
...
>>> list(Color)
[<Color.red: 1>, <Color.blue: 2>, <Color.green: 3>]
The values are chosen by :func:`_generate_next_value_`, which can be
overridden::
>>> class AutoName(Enum):
... def _generate_next_value_(name, start, count, last_values):
... return name
...
>>> class Ordinal(AutoName):
... north = auto()
... south = auto()
... east = auto()
... west = auto()
...
>>> list(Ordinal)
[<Ordinal.north: 'north'>, <Ordinal.south: 'south'>, <Ordinal.east: 'east'>, <Ordinal.west: 'west'>]
.. note::
The goal of the default :meth:`_generate_next_value_` methods is to provide
the next :class:`int` in sequence with the last :class:`int` provided, but
the way it does this is an implementation detail and may change.
Iteration
---------
...
...
@@ -597,7 +645,9 @@ Flag
The last variation is :class:`Flag`. Like :class:`IntFlag`, :class:`Flag`
members can be combined using the bitwise operators (&, \|, ^, ~). Unlike
:class:`IntFlag`, they cannot be combined with, nor compared against, any
other :class:`Flag` enumeration, nor :class:`int`.
other :class:`Flag` enumeration, nor :class:`int`. While it is possible to
specify the values directly it is recommended to use :class:`auto` as the
value and let :class:`Flag` select an appropriate value.
.. versionadded:: 3.6
...
...
@@ -606,9 +656,9 @@ flags being set, the boolean evaluation is :data:`False`::
>>> from enum import Flag
>>> class Color(Flag):
... red =
1
... blue =
2
... green =
4
... red =
auto()
... blue =
auto()
... green =
auto()
...
>>> Color.red & Color.green
<Color.0: 0>
...
...
@@ -619,21 +669,20 @@ Individual flags should have values that are powers of two (1, 2, 4, 8, ...),
while combinations of flags won't::
>>> class Color(Flag):
... red = 1
... blue = 2
... green = 4
... white = 7
... # or
... # white = red | blue | green
... red = auto()
... blue = auto()
... green = auto()
... white = red | blue | green
...
Giving a name to the "no flags set" condition does not change its boolean
value::
>>> class Color(Flag):
... black = 0
... red =
1
... blue =
2
... green =
4
... red =
auto()
... blue =
auto()
... green =
auto()
...
>>> Color.black
<Color.black: 0>
...
...
@@ -700,6 +749,7 @@ Omitting values
In many use-cases one doesn't care what the actual value of an enumeration
is. There are several ways to define this type of simple enumeration:
- use instances of :class:`auto` for the value
- use instances of :class:`object` as the value
- use a descriptive string as the value
- use a tuple as the value and a custom :meth:`__new__` to replace the
...
...
@@ -718,6 +768,20 @@ the (unimportant) value::
...
Using :class:`auto`
"""""""""""""""""""
Using :class:`object` would look like::
>>> class Color(NoValue):
... red = auto()
... blue = auto()
... green = auto()
...
>>> Color.green
<Color.green>
Using :class:`object`
"""""""""""""""""""""
...
...
@@ -930,8 +994,11 @@ Supported ``_sunder_`` names
overridden
- ``_order_`` -- used in Python 2/3 code to ensure member order is consistent
(class attribute, removed during class creation)
- ``_generate_next_value_`` -- used by the `Functional API`_ and by
:class:`auto` to get an appropriate value for an enum member; may be
overridden
.. versionadded:: 3.6 ``_missing_``, ``_order_``
.. versionadded:: 3.6 ``_missing_``, ``_order_``
, ``_generate_next_value_``
To help keep Python 2 / Python 3 code in sync an :attr:`_order_` attribute can
be provided. It will be checked against the actual order of the enumeration
...
...
Lib/enum.py
Dosyayı görüntüle @
c16595e5
...
...
@@ -10,7 +10,11 @@ except ImportError:
from
collections
import
OrderedDict
__all__
=
[
'EnumMeta'
,
'Enum'
,
'IntEnum'
,
'Flag'
,
'IntFlag'
,
'unique'
]
__all__
=
[
'EnumMeta'
,
'Enum'
,
'IntEnum'
,
'Flag'
,
'IntFlag'
,
'auto'
,
'unique'
,
]
def
_is_descriptor
(
obj
):
...
...
@@ -36,7 +40,6 @@ def _is_sunder(name):
name
[
-
2
:
-
1
]
!=
'_'
and
len
(
name
)
>
2
)
def
_make_class_unpicklable
(
cls
):
"""Make the given class un-picklable."""
def
_break_on_call_reduce
(
self
,
proto
):
...
...
@@ -44,6 +47,12 @@ def _make_class_unpicklable(cls):
cls
.
__reduce_ex__
=
_break_on_call_reduce
cls
.
__module__
=
'<unknown>'
class
auto
:
"""
Instances are replaced with an appropriate value in Enum class suites.
"""
pass
class
_EnumDict
(
dict
):
"""Track enum member order and ensure member names are not reused.
...
...
@@ -55,6 +64,7 @@ class _EnumDict(dict):
def
__init__
(
self
):
super
()
.
__init__
()
self
.
_member_names
=
[]
self
.
_last_values
=
[]
def
__setitem__
(
self
,
key
,
value
):
"""Changes anything not dundered or not a descriptor.
...
...
@@ -71,6 +81,8 @@ class _EnumDict(dict):
'_generate_next_value_'
,
'_missing_'
,
):
raise
ValueError
(
'_names_ are reserved for future Enum use'
)
if
key
==
'_generate_next_value_'
:
setattr
(
self
,
'_generate_next_value'
,
value
)
elif
_is_dunder
(
key
):
if
key
==
'__order__'
:
key
=
'_order_'
...
...
@@ -81,11 +93,13 @@ class _EnumDict(dict):
if
key
in
self
:
# enum overwriting a descriptor?
raise
TypeError
(
'
%
r already defined as:
%
r'
%
(
key
,
self
[
key
]))
if
isinstance
(
value
,
auto
):
value
=
self
.
_generate_next_value
(
key
,
1
,
len
(
self
.
_member_names
),
self
.
_last_values
[:])
self
.
_member_names
.
append
(
key
)
self
.
_last_values
.
append
(
value
)
super
()
.
__setitem__
(
key
,
value
)
# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
# until EnumMeta finishes running the first time the Enum class doesn't exist.
# This is also why there are checks in EnumMeta like `if Enum is not None`
...
...
@@ -366,10 +380,11 @@ class EnumMeta(type):
names
=
names
.
replace
(
','
,
' '
)
.
split
()
if
isinstance
(
names
,
(
tuple
,
list
))
and
isinstance
(
names
[
0
],
str
):
original_names
,
names
=
names
,
[]
last_value
=
None
last_value
s
=
[]
for
count
,
name
in
enumerate
(
original_names
):
last_value
=
first_enum
.
_generate_next_value_
(
name
,
start
,
count
,
last_value
)
names
.
append
((
name
,
last_value
))
value
=
first_enum
.
_generate_next_value_
(
name
,
start
,
count
,
last_values
[:])
last_values
.
append
(
value
)
names
.
append
((
name
,
value
))
# Here, names is either an iterable of (name, value) or a mapping.
for
item
in
names
:
...
...
@@ -514,11 +529,15 @@ class Enum(metaclass=EnumMeta):
# still not found -- try _missing_ hook
return
cls
.
_missing_
(
value
)
@staticmethod
def
_generate_next_value_
(
name
,
start
,
count
,
last_value
):
if
not
count
:
def
_generate_next_value_
(
name
,
start
,
count
,
last_values
):
for
last_value
in
reversed
(
last_values
):
try
:
return
last_value
+
1
except
TypeError
:
pass
else
:
return
start
return
last_value
+
1
@classmethod
def
_missing_
(
cls
,
value
):
raise
ValueError
(
"
%
r is not a valid
%
s"
%
(
value
,
cls
.
__name__
))
...
...
@@ -616,8 +635,8 @@ def _reduce_ex_by_name(self, proto):
class
Flag
(
Enum
):
"""Support for flags"""
@staticmethod
def
_generate_next_value_
(
name
,
start
,
count
,
last_value
):
def
_generate_next_value_
(
name
,
start
,
count
,
last_value
s
):
"""
Generate the next value when not given.
...
...
@@ -628,7 +647,12 @@ class Flag(Enum):
"""
if
not
count
:
return
start
if
start
is
not
None
else
1
high_bit
=
_high_bit
(
last_value
)
for
last_value
in
reversed
(
last_values
):
try
:
high_bit
=
_high_bit
(
last_value
)
break
except
TypeError
:
raise
TypeError
(
'Invalid Flag value:
%
r'
%
last_value
)
from
None
return
2
**
(
high_bit
+
1
)
@classmethod
...
...
Lib/test/test_enum.py
Dosyayı görüntüle @
c16595e5
...
...
@@ -3,7 +3,7 @@ import inspect
import
pydoc
import
unittest
from
collections
import
OrderedDict
from
enum
import
Enum
,
IntEnum
,
EnumMeta
,
Flag
,
IntFlag
,
unique
from
enum
import
Enum
,
IntEnum
,
EnumMeta
,
Flag
,
IntFlag
,
unique
,
auto
from
io
import
StringIO
from
pickle
import
dumps
,
loads
,
PicklingError
,
HIGHEST_PROTOCOL
from
test
import
support
...
...
@@ -113,6 +113,7 @@ class TestHelpers(unittest.TestCase):
'__'
,
'___'
,
'____'
,
'_____'
,):
self
.
assertFalse
(
enum
.
_is_dunder
(
s
))
# tests
class
TestEnum
(
unittest
.
TestCase
):
...
...
@@ -1578,6 +1579,61 @@ class TestEnum(unittest.TestCase):
self
.
assertEqual
(
LabelledList
.
unprocessed
,
1
)
self
.
assertEqual
(
LabelledList
(
1
),
LabelledList
.
unprocessed
)
def
test_auto_number
(
self
):
class
Color
(
Enum
):
red
=
auto
()
blue
=
auto
()
green
=
auto
()
self
.
assertEqual
(
list
(
Color
),
[
Color
.
red
,
Color
.
blue
,
Color
.
green
])
self
.
assertEqual
(
Color
.
red
.
value
,
1
)
self
.
assertEqual
(
Color
.
blue
.
value
,
2
)
self
.
assertEqual
(
Color
.
green
.
value
,
3
)
def
test_auto_name
(
self
):
class
Color
(
Enum
):
def
_generate_next_value_
(
name
,
start
,
count
,
last
):
return
name
red
=
auto
()
blue
=
auto
()
green
=
auto
()
self
.
assertEqual
(
list
(
Color
),
[
Color
.
red
,
Color
.
blue
,
Color
.
green
])
self
.
assertEqual
(
Color
.
red
.
value
,
'red'
)
self
.
assertEqual
(
Color
.
blue
.
value
,
'blue'
)
self
.
assertEqual
(
Color
.
green
.
value
,
'green'
)
def
test_auto_name_inherit
(
self
):
class
AutoNameEnum
(
Enum
):
def
_generate_next_value_
(
name
,
start
,
count
,
last
):
return
name
class
Color
(
AutoNameEnum
):
red
=
auto
()
blue
=
auto
()
green
=
auto
()
self
.
assertEqual
(
list
(
Color
),
[
Color
.
red
,
Color
.
blue
,
Color
.
green
])
self
.
assertEqual
(
Color
.
red
.
value
,
'red'
)
self
.
assertEqual
(
Color
.
blue
.
value
,
'blue'
)
self
.
assertEqual
(
Color
.
green
.
value
,
'green'
)
def
test_auto_garbage
(
self
):
class
Color
(
Enum
):
red
=
'red'
blue
=
auto
()
self
.
assertEqual
(
Color
.
blue
.
value
,
1
)
def
test_auto_garbage_corrected
(
self
):
class
Color
(
Enum
):
red
=
'red'
blue
=
2
green
=
auto
()
self
.
assertEqual
(
list
(
Color
),
[
Color
.
red
,
Color
.
blue
,
Color
.
green
])
self
.
assertEqual
(
Color
.
red
.
value
,
'red'
)
self
.
assertEqual
(
Color
.
blue
.
value
,
2
)
self
.
assertEqual
(
Color
.
green
.
value
,
3
)
class
TestOrder
(
unittest
.
TestCase
):
...
...
@@ -1856,7 +1912,6 @@ class TestFlag(unittest.TestCase):
test_pickle_dump_load
(
self
.
assertIs
,
FlagStooges
.
CURLY
|
FlagStooges
.
MOE
)
test_pickle_dump_load
(
self
.
assertIs
,
FlagStooges
)
def
test_containment
(
self
):
Perm
=
self
.
Perm
R
,
W
,
X
=
Perm
...
...
@@ -1877,6 +1932,24 @@ class TestFlag(unittest.TestCase):
self
.
assertFalse
(
W
in
RX
)
self
.
assertFalse
(
X
in
RW
)
def
test_auto_number
(
self
):
class
Color
(
Flag
):
red
=
auto
()
blue
=
auto
()
green
=
auto
()
self
.
assertEqual
(
list
(
Color
),
[
Color
.
red
,
Color
.
blue
,
Color
.
green
])
self
.
assertEqual
(
Color
.
red
.
value
,
1
)
self
.
assertEqual
(
Color
.
blue
.
value
,
2
)
self
.
assertEqual
(
Color
.
green
.
value
,
4
)
def
test_auto_number_garbage
(
self
):
with
self
.
assertRaisesRegex
(
TypeError
,
'Invalid Flag value: .not an int.'
):
class
Color
(
Flag
):
red
=
'not an int'
blue
=
auto
()
class
TestIntFlag
(
unittest
.
TestCase
):
"""Tests of the IntFlags."""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment