Reputation: 7960
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
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
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