Woody1193
Woody1193

Reputation: 7960

Defining python classes with enums

Recently I defined one of my Python classes as shown below.

from datetime import datetime, date, time
import enums


class ExampleClass:

    defaults = (-1, "", "", datetime.today(), "", -1, [], "", -1, "", "", [], "")

    def __init__(self, **kwargs):
        count = 0
        for ex in enums.ExampleEnums:
            setattr(self, ex.name, kwargs.get(ex.value, ExampleClass.defaults[count]))
            count += 1

    def __str__(self):
        return_string = "Example Object with "
        count = 0
        for val in enums.ExampleEnums:
            if (getattr(self, val.name) != ExampleClass.defaults[count]):
                return_string += str("%s: %s, " % (val.name, getattr(self, val.name)))
            count += 1
        return return_string[:-2]

    def __repr__(self):
        return_string = ""
        count = 0
        for val in enums.ExampleEnums:
            if (getattr(self, val.name) != ExampleClass.defaults[count]):
                return_string += str("%s=%s, " % (val.value, getattr(self, val.name)))
            count += 1
        return return_string[:-2]

    def __eq__(self, other):
        for val in enums.ExampleEnums:
            if (getattr(self, val.name) != getattr(other, val.name)):
                return False
        return True

    def __ne__(self, other):
        for val in enums.ExampleEnums:
            if (getattr(self, val.name) == getattr(other, val.name)):
                return False
        return True

Anyway, I'm wondering: is this a good way to write a class definition for a data class? Are there any ways I could improve this? I don't need any code, just generalities are fine as I'm only posting this as a way to see how I can improve my own coding abilities in Python.

Thanks

Upvotes: 2

Views: 509

Answers (3)

Will
Will

Reputation: 842

You can call self._eq__(other) in function __ne__.

Upvotes: 1

mkrieger1
mkrieger1

Reputation: 23123

You use this pattern several times (shown here is __init__, it applies to __str__ and __repr__ as well):

count = 0
for ex in enums.ExampleEnums:
    setattr(self, ex.name, kwargs.get(ex.value, ExampleClass.defaults[count]))
    count += 1

It would be better to iterate directly over the items in ExampleClass.defaults instead of manually counting an index. This can be achieved using zip:

for ex, default in zip(enums.ExampleEnums, ExampleClass.defaults):
    setattr(self, ex.name, kwargs.get(ex.value, default))

The __eq__ method can be simplified using all:

def __eq__(self, other):
    return all(getattr(self, val.name) == getattr(other, val.name)
               for val in enums.ExampleEnums)

Then, as others have already said, you can express __ne__ in terms of __eq__, or even using the == operator:

def __ne__(self, other):
    return not self == other

Upvotes: 2

CodingPenguins
CodingPenguins

Reputation: 191

The best way to write a data class will vary on use case. But on what you've presented, you shouldn't repeat code. Once you've defined the __eq__ operator, you should be using that elsewhere. (What if your definition of __eq__ changes?) Also, you don't have to define every magic method under the sun... just the things that are valuable to you.

Check out this guide to Python's magic methods: http://www.rafekettler.com/magicmethods.html

Also see this answer on __ne__ vs __eq__ and how to define them: Python implementing ne operator based on eq.

You should also look into decorators (and @property, specifically).

Upvotes: 0

Related Questions