1

I'm learning Python after many years away from coding and like efficeint code. To me this class seems to create a dictionary every time str is used. Am I correct? Can the dict be made a class var or static so that it's neater memory wise?

Currently this does return the correct response for str(Suit.Clubs) -> 'c'

Many thanks, Simon

class Suit(Enum):
  Clubs, Diamonds, Hearts, Spades = range(1, 5)
    
  def __str__(self): # Hmmm. shortsuit should be a Class var
    _dshortsuit = {
    Suit.Clubs: 'c', Suit.Diamonds: 'd', Suit.Hearts: 'h', Suit.Spades: 's'
    }
    return _dshortsuit[self]
Simon
  • 23
  • 2

3 Answers3

1

The Enum class is rather special since it turns every attribute of the derived class into an enum value, including any dictionary that you would define at the class level.

But defining it at the module level is possible; let's use double underscore and all-caps to indicate that it's a private constant:

class Suit(Enum):
  Clubs, Diamonds, Hearts, Spades = range(1, 5)
    
  def __str__(self):
    return __DSHORTSUIT[self]

__DSHORTSUIT = {Suit.Clubs: 'c', Suit.Diamonds: 'd', Suit.Hearts: 'h', Suit.Spades: 's'}

Note that __DSHORTSUIT must be defined after Suit, otherwise it won't be able to access its members yet.


An alternative (which you may or may not like, depending on your use case) is to use the strings as enum values directly:

class Suit(Enum):
  Clubs = 'c'
  Diamonds = 'd'
  Hearts = 'h'
  Spades = 's'

  def __str__(self):
      return self.value

If you want to keep the values as integers but add the string version as an additional property on those objects, you can use some higher-level enum voodoo using a custom __new__:

class Suit(Enum):
  Clubs = 'c'
  Diamonds = 'd'
  Hearts = 'h'
  Spades = 's'

  def __new__(cls, short_str):
      obj = object.__new__(cls)
      obj._value_ = len(cls.__members__) + 1
      obj.short_str = short_str
      return obj

  def __str__(self):
      return self.short_str
Thomas
  • 174,939
  • 50
  • 355
  • 478
0

Previous answers have already iterated how Enum classes work... However, you can emulate the behaviour of a class variable by:

class Suit(Enum):
    Clubs, Diamonds, Hearts, Spades = range(1, 5)

    _dshortsuit = {Clubs: 'c', Diamonds: 'd', Hearts: 'h', Spades: 's'}

    def __str__(self):
        return self.__class__._dshortsuit.value[self.value]
simonp2207
  • 183
  • 6
  • This works in isolation and looks like what I shoudl be doing but breaks my CardDeck class later on since self.cards = [Card(rank, suit, False) for suit in Suit for rank in Rank] now wants to include _dshortrank and _dshortsuit when creating a pack.... – Simon Sep 23 '22 at 17:00
-3

As long as I know, variable names can't start with numbers and symbols like underscore like you wrote. Try "dshortsuit_"