On Thu, Jun 28, 2018 at 10:06 PM Ben Finney <ben+pyt...@benfinney.id.au> wrote: > > Ethan Furman <et...@stoneleaf.us> writes: > > > On 06/28/2018 05:58 PM, Ben Finney wrote: > > > > > So I remain dumbfounded as to why anyone would want a class to *both* be > > > an enumerated type, *and* have callable attributes in its API. > > > > Perhaps I am using Enum incorrectly, but here is my FederalHoliday > > Enum. […] > > Thanks for the example. Yes, my personal impression is that class > is not a good use of enum.Enum (nor enum.AutoEnum). > > To inherit from enum.Enum (or enum.AutoEnum) signals, to my mind, that > the class is not really intended as a typical Python class, but instead > is intended to be that special beast known as an “enumerated type” which > has little behaviour other than being a namespace for constant values.
That sounds like a C attitude talking. Python enums are heavily inspired by Java enums, which also permit enum members to have attributes and methods. In fact, that planets example that Steven mentioned is ripped straight out of the Java documentation. You may find it weird, but I actually find it really, really useful to be able to attach methods to enums. For example: class Color(Enum): RED = 'red' GREEN = 'green' BLUE = 'blue' def __str__(self): return 'the color %s' % self.value How else is one to override the str() of an enum? Another example: @total_ordering class ChessPiece(Enum): PAWN = 1, 'P' KNIGHT = 2, 'N' BISHOP = 3, 'B' ROOK = 4, 'R' # ... @property def label(self): return self.value[1] def __lt__(self, other): assert isinstance(other, ChessPiece) return self.value < other.value This enum type defines its own ordering based on the relative values of the chess pieces. To be fair, Java does this a bit better than Python does. For example, Java allows enum methods to be overridden by individual enum members. This makes it easy to, e.g., implement a Strategy pattern where the Strategy of choice depends upon an enum value. If you want to do that in Python, you're pretty much stuck with passing either lambdas or functions defined elsewhere as part of the enum member's value. But we can do it, which leads us to our next example: def pawn_moves(board, from_square): "Generate all pawn moves possible from the given square." # ... def knight_moves(board, from_square): "Generate all knight moves possible from the given square." # ... def pawn_attacks(board, from_square): "Generate all squares that would be attacked by a pawn a the given square." # ... # ... class ChessPiece(Enum): PAWN = 'P', pawn_moves, pawn_attacks KNIGHT = 'N', knight_moves, knight_attacks BISHOP = 'B', bishop_moves, bishop_attacks ROOK = 'R', rook_moves, rook_attacks # ... def moves(self, board, from_square): return self.value[1](board, from_square) def attacks(self, board, from_square): return self.value[2](board, from_square) Now, elsewhere we can easily do something like: all_moves = [] for square in board: piece = board[square] if piece: all_moves.extend(piece.moves(board, square)) Et voila. ChessPiece is still an enum as it should be, and it also has a useful API on top of that. -- https://mail.python.org/mailman/listinfo/python-list