I wrote the following Author class in Python for a project I'm working on. I wanted to make sure that the rich comparisons and the methods I used to validate the constructor parameters were done properly.
Author class:
class Author:
def __init__(self, id, firstname, lastname):
self._validateid(id, "ID")
self._validate_author(firstname, "First Name")
self._validate_author(lastname, "Last Name")
self._id = id
self._firstname = firstname
self._lastname = lastname
def _validateid(self, id, error_message):
if id < 1:
raise ValueError(error_message + " is invalid")
def _validate_author(self, parameter, error_message):
if not parameter:
raise TypeError(error_message + " is missing")
@property
def iden(self):
return self._id
@property
def first_name(self):
return self._firstname
@property
def last_name(self):
return self._lastname
Rich Comparisons:
def __lt__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) < (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __le__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) <= (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __eq__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) == (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __ne__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) != (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __ge__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) >= (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __gt__(self, other):
if isinstance(other, Author):
return (self.iden, self.first_name.lower(), self.last_name.lower()) > (other.iden, other.first_name.lower(), other.last_name.lower())
return NotImplemented
def __hash__(self):
return hash((self.iden, self.first_name.lower(), self.last_name.lower()))
1 Answer 1
Personally using a
namedtuple
is the best way to strip most of your code.If you wish to be able to mutate your data, then inheriting from a list, rather than
namedtuple
, could be a better idea.I'm not a fan of
_validateid
or_validate_author
, just write them out in the constructor.
And so I'd personally change your code to:
from collection import namedtuple
class Author(namedtuple('AuthorBase', 'id first_name last_name')):
def __new__(cls, id, first, last):
if id < 1:
raise ValueError('id is not a valid id')
if not first:
raise ValueError('first_name has not been set')
if not last:
raise ValueError('last_name has not been set')
return super().__new__(cls, id, first, last)
-
\$\begingroup\$ Let us continue this discussion in chat. \$\endgroup\$user150904– user1509042017年10月13日 14:40:43 +00:00Commented Oct 13, 2017 at 14:40
-
\$\begingroup\$ I was the OP for this question, thanks for answering it. Quick question, when inheriting and overriding the
__new__
method in this case, are you supposed to usereturn super()
orreturn namedtuple
? Explained here: python.org/download/releases/2.2/descrintro/#__new__ \$\endgroup\$user168710– user1687102018年06月20日 15:19:36 +00:00Commented Jun 20, 2018 at 15:19 -
\$\begingroup\$ @Sveta That document is about Python 2.2 which is very old. In the current documentation it says using
super
is the common way \$\endgroup\$2018年06月20日 15:28:53 +00:00Commented Jun 20, 2018 at 15:28 -
\$\begingroup\$ Inheriting from
namedtuple
is a common way to achieve immutability? \$\endgroup\$user168710– user1687102018年06月20日 15:31:23 +00:00Commented Jun 20, 2018 at 15:31 -
1\$\begingroup\$ @Sveta Depends on usage, here I'd use a
namedtuple
, other places I may not. \$\endgroup\$2018年06月20日 15:34:04 +00:00Commented Jun 20, 2018 at 15:34
__hash__
could just return the id... \$\endgroup\$(lastname, firstname, id)
, instead of(id, lastname, firstname)
, which will always sort byid
first. \$\endgroup\$