Author class, with constructor validations and rich comparisons 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 &lt; 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()) &lt; (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()) &lt;= (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()) &gt;= (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()) &gt; (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()))
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 &lt; 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)