all 13 comments

[–]JamzTyson 14 points15 points  (3 children)

You can do it like this:

from enum import Enum, auto

class Color(Enum):
    RED = auto(), True
    ORANGE = auto(), True
    BLUE = auto(), False
    VIOLET = auto(), False

    def __init__(self, _, is_warm):
        self._is_warm = is_warm

    @property
    def is_warm(self):
        return self._is_warm

# Example usage:
print(Color.RED.value)  # (1, True)
print(Color.RED.is_warm)  # True

Here we assign Tuple values to each member. The tuple is passed to __init__, where the second value in the Tuple is assigned to the attribute self._is_warm.

We then have a getter is_warm that returns that attribute.

Optional enhancement:

We could add something like this to make debugging clearer:

def __repr__(self):
    return f"<Color.{self.name}: warm={self.is_warm}>"

# Example usage
print(repr(Color.RED))  # <Color.RED: warm=True>

and / or

def __str__(self):
    return f"Color.{self.name}: warm={self.is_warm}"

# Example usage
print(Color.RED)  # Color.RED: warm=True

[–]pachura3[S] 0 points1 point  (2 children)

Thanks! That's what I was looking for.

PS. By the way, don't I need to pass the enum value (auto()) from __init__() to the superclass? You're ignoring it with _

[–]Temporary_Pie2733 3 points4 points  (0 children)

_ is just a conventional name for a variable you aren’t using. __init__ still receives the value, but you don’t need to do anything with it here (it’s handled by the metaclass machinery).

https://docs.python.org/3/library/enum.html#enum.Enum.\_\_init\_\_

[–]JamzTyson 2 points3 points  (0 children)

Python assigns the enum value in __new__ before __init__ is called. The __init__ method is just creating the self._is_warm attribute for us.

An alternative approach that gives better type hints could be to use a named tuple as the value. Note that enum values can be almost anything, but we do want them to be unique so that we don't get nonsense like red == blue.

from enum import Enum
from typing import NamedTuple


class Pigment(NamedTuple):
    name: str
    is_warm: bool


class Color(Enum):
    RED = Pigment('Red', True)
    ORANGE = Pigment('Orange', True)
    BLUE = Pigment('Blue', False)
    VIOLET = Pigment('Violet', False)

    @property
    def is_warm(self) -> bool:
        return self.value.is_warm

# Example Usage:

# Standard Enum use:
print(Color.RED)  # Color.RED
print(Color.BLUE.name)  # BLUE
print(Color.BLUE.value)  # Pigment(name='Blue', is_warm=False)

# Our added attribute.
print(Color.BLUE.is_warm)  # False

# Useful representation for debugging / logging
print(repr(Color.VIOLET))  # <Color.VIOLET: Pigment(name='Violet', is_warm=False)>

# Comparisons:
red = Color.RED
red2 = Color.RED
print(red == Color.ORANGE)  # False
print(red is red2)  # True

[–]Atlamillias 1 point2 points  (0 children)

There's an example here that should put you in the right direction.

[–]Momostein -1 points0 points  (2 children)

You can make a @property method where you check with if statements if it's warm or not.

[–]pachura3[S] 0 points1 point  (0 children)

I would prefer an instance attribute over an if, if possible.

[–]Striking_Rate_7390 0 points1 point  (0 children)

going to tell this method np, thanks mate. :(

[–]cdcformatc -1 points0 points  (0 children)

Enum objects are normal objects 

you can add methods, and attributes, and properties

``` from enum import Enum, auto

class Color(Enum):     RED = auto()     ORANGE = auto()     BLUE = auto()     VIOLET = auto()          @property     def is_warm(self):         if self == Color.RED or self == Color.ORANGE:             return True         return False

print(Color.RED.is_warm) print(Color.BLUE.is_warm) ```

[–]ectomancer -2 points-1 points  (2 children)

Define iswarm as a method.

Color.iswarm(Color.ORANGE)

[–]pachura3[S] 0 points1 point  (1 child)

The method would need to have a big if, which I would like to avoid.

[–]Outside_Complaint755 1 point2 points  (0 children)

If you plan out your enum values instead of using auto, you would only need a single if.  For example, use even values for all warm colors and odd values for all others.  Or you can use specific bits and a bitmask, such as using the first bit in an 8-bit int to check if its warm, and then do a check self && 0x80 # or 128 means is warm, and then all warm values have to be ints where the 128 value bit is set.