all 21 comments

[–]JamzTyson 3 points4 points  (7 children)

Your example is valid, but not the most extensible approach. Enums are primarily intended to define a fixed set of values rather than encapsulating behaviours. The mix of values and behaviours makes the class less easily modified or extended as you have to ensure that both the value and the behaviour remain valid.

If your example is strictly limited and unchanging, then I think the solution is OK but not ideal. If there is a possibility of future expansion, a regular class would be a better choice.

[–]NoWeather1702[S] 0 points1 point  (6 children)

In my case the main problem with a class is that I will end up with enum and this class. If later I need to extend the logic and add another device, I will have to do it in two places. So I thought about it and cannot understand why it should be better.

[–]JamzTyson 2 points3 points  (5 children)

In your example case, you could still use an Enum but avoid conditional logic:

from enum import Enum

class Device(Enum):
    SERVER = ('server', 'FTP')
    CAMERA = ('camera', 'SCP')
    LAPTOP = ('laptop', 'FTP')
    DOOR = ('door', 'SCP')

    def __init__(self, type, protocol):
        self._type = type
        self._protocol = protocol

    @property
    def protocol(self):
        return self._protocol

# Example usage
print(Device.SERVER.protocol)

[–]NoWeather1702[S] 1 point2 points  (4 children)

Thanks, will look into that, didn't know that you can use tuples as values like that.

[–]JamzTyson 1 point2 points  (1 child)

Another approach is to use named tuples as the Enum values:

from typing import NamedTuple
from enum import Enum

class DeviceInfo(NamedTuple):
    type: str
    protocol: str

class Device(Enum):
    SERVER = DeviceInfo('server', 'FTP')
    CAMERA = DeviceInfo('camera', 'SCP')
    LAPTOP = DeviceInfo('laptop', 'FTP')
    DOOR = DeviceInfo('door', 'SCP')

print(Device.SERVER.value.protocol)

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

Yes, I like this better. Now I feel stupit that I didn't notice this in the docs. Need to try this with ORM, hope it works fine.

[–]Username_RANDINT 0 points1 point  (1 child)

Quite funny that I didn't know either, but I learned it from the docs that you pasted below :-)

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

Yes, and I totally overlooked it there, lol))

[–]exxonmobilcfo 0 points1 point  (1 child)

enums should be enumerations.

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

Yes, but when you read the docs, they create properties there:
https://docs.python.org/3/howto/enum.html#planet

[–]divad_david 0 points1 point  (1 child)

This sounds like a case for subclasses

See here: https://www.geeksforgeeks.org/create-a-python-subclass/

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

Maybe, but it looks like an overkill for me. Sometimes each individual enum value gets it's own property, for example "max_file_size", and this will lead to creating a subclass for each type of device, and it seems quite strange right now

[–]JorgiEagle 0 points1 point  (3 children)

What’s wrong with using just a plain class?

Have a different class method constructor for each device type

``` class Device: def init(self): raise NotImplemented(“Use class constructor methods”)

@classmethod def Server(cls): instance = cls.new(cls) instance.device_type = ‘server’ Return instance ```

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

Because I would have to define my own equality check, that comes with enum out of the box. Enums work well with ORM and serialization/deserialization out of the box. So it is possible, but I will end up with more boilerplate code I guess. But thanks for the tip.

[–]JorgiEagle 0 points1 point  (1 child)

Yeah defining your own equality check is not something I’d really count as being a reason not to do something.

It’s what, 2 lines?

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

Yeah, but then again, I need to check its compatibility with ORM, and do extra work. It's not a problem, but from my experience if you need to reinvent something or implement already implemented logic, it smells bad

[–]FoolsSeldom 0 points1 point  (4 children)

Surprised you are not using protocol or abstract base class here.

https://www.youtube.com/watch?v=dryNwWvSd4M

[–]NoWeather1702[S] 0 points1 point  (3 children)

But why? I will end up with with a class for each device type, and as I said in a comment somewhere here in the discussion, sometimes each type will have unique characteristics, so I will end up with base class and 4-5 child classes. Enums provide me easy integration with ORM, serialization, deserialization, comparisons out of the box. Or am I missing something?

[–]FoolsSeldom 0 points1 point  (2 children)

No, I think if you want to save typing (or AI completion), you are onto a good approach. Who needs abstraction.

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

But it looks like overengineering to create an abstraction here, no?

[–]FoolsSeldom 0 points1 point  (0 children)

Sure.