0

I am currently using Python 3.9.1 or 3.8 (depending on what device I’m on)

I was reading an article on Medium.com regarding sorting using multiple keys from a dictionary using the operator module. I had implemented a class that uses the built-in rich comparison operators and I was wondering if there was a way to get that same functionality out a class. I figured out (one way) to get single attribute functionality:

class Person:
"""    The Person class functions as it own representation of a person and base class.

       In this video game simulation it functions as the starting point for the Employee
       and Customer class but can be adapted to another other operation that deals
       with people.

       Attributes
       ----------
       _first_name : str
           The first name of the person
       _middle_name : str
           The middle name of the person
       _last_name : str
           The last name of the person
       _dob : datetime.datetime
           The property for this will accept a string formatted as "mm.dd.yyyy" and convert it to
           a datetime.datetime as well as accepting a datetime.datetime directly
       _age : int
           This is calculated and assigned a value the date of birth is assigned or changed
       _sex : int
           For this class 0 is male and 1 is female will build conversion from string representation
       _married : bool
           Is the person married?
       _hair_color : str
           Really kind of torn here and would like to pick a color as an RGBA value but for this simulation
           sticking with text
       _eye_color: str
           Same as hair_color
       _weight : float
           The weight in pounds
       _height : float
           The height in inches

       Methods
       -------

"""

# noinspection SpellCheckingInspection
def __init__(self,
             fname: str,
             mname: str,
             lname: str,
             dob,
             sex,
             married,
             hair_color,
             eye_color,
             weight,
             height,
             sort_by):
    self._first_name = fname
    self._middle_name = mname
    self._last_name = lname
    self._dob = None
    self._age = 0
    self._sex = sex
    self._married = married
    self._hair_color = hair_color
    self._eye_color = eye_color
    self._weight = weight
    self._height = height
    self.dob = dob
    self._sort_by = sort_by
    self.selection = {
        'lastname': self._last_name,
        'middlename': self._middle_name,
        'firstname': self._first_name,
        'dateofbirth': self._dob,
        'age': self._age,
        'height': self._height,
        'weight': self._weight
    }

@property
def name(self):
    return self._first_name + ' ' + self._last_name

@property
def first_name(self):
    return self._first_name

# noinspection SpellCheckingInspection
@first_name.setter
def first_name(self, fname):
    self._first_name = fname

@property
def middle_name(self):
    return self._middle_name

# noinspection SpellCheckingInspection
@middle_name.setter
def middle_name(self, mname):
    self._middle_name = mname

@property
def last_name(self):
    return self._last_name

# noinspection SpellCheckingInspection
@last_name.setter
def last_name(self, lname):
    self._last_name = lname

@property
def dob(self):
    return self._dob

@dob.setter
def dob(self, birth_date):
    if isinstance(birth_date, dt.datetime):
        self._dob = birth_date
        self.set_age(birth_date)
    elif isinstance(birth_date, str):
        date = re.compile(r'(\d\d).(\d\d).(\d\d\d\d)')
        date_result = date.findall(birth_date)

        try:
            date_tuple = date_result[0]
        except IndexError as e:
            date_tuple = ()
            print(e)

        if len(date_tuple) == 3:
            month, day, year = date_tuple
            self.dob = dt.datetime(int(year), int(month), int(day))
        else:
            raise ValueError('Date string value not valid must be in the '
                             'form MM_DD_YYYY where the underscore _ is any'
                             ' character')

    else:
        raise TypeError(
            f'Expected datetime.datetime or string but got {type(birth_date)}'
        )

def set_age(self, date_of_birth):
    days_delta = dt.datetime.now() - date_of_birth
    self._age = int(days_delta.days / 365)

@property
def age(self):
    return self._age

@property
def sex(self):
    return self._sex

@property
def sort_by(self):
    return self._sort_by

# noinspection SpellCheckingInspection
@sort_by.setter
def sort_by(self, key):
    # TODO: research a way to transform keys automatically in the dictionary
    # by parsing either the docstrings or attribute variables, check out functools
    if key in self.selection:
        self._sort_by = key

def __lt__(self, other):
    if isinstance(other, Person):
        if self._sort_by != other._sort_by:
            other._sort_by = self._sort_by

        if self.selection[self._sort_by] < other.selection[other._sort_by]:
            return True
        else:
            return False
    else:
        raise TypeError(f'Expected class Person got {type(other)}')

def __le__(self, other):
    if isinstance(other, Person):
        if self._sort_by != other._sort_by:
            other.sort_by = self.sort_by

        if self.selection[self._sort_by] <= other.selection[other._sort_by]:
            return True
        else:
            return False
    else:
        raise TypeError(f'Expected class Person got {type(other)}')

def __eq__(self, other):
    if isinstance(other, Person):
        if self._sort_by != other._sort_by:
            other._sort_by = self._sort_by

        if self.selection[self._sort_by] == other.selection[other._sort_by]:
            return True
        else:
            return False
    else:
        raise TypeError(f'Expected class Person got {type(other)}')

def __gt__(self, other):
    if isinstance(other, Person):
        if self._sort_by != other._sort_by:
            other._sort_by = self._sort_by

        if self.selection[self._sort_by] > other.selection[other._sort_by]:
            return True
        else:
            return False
    else:
        raise TypeError(f'Expected class Person got {type(other)}')

def __ge__(self, other):
    if isinstance(other, Person):
        if self._sort_by != other._sort_by:
            other._sort_by = self._sort_by

        if self.selection[self._sort_by] >= other.selection[other._sort_by]:
            return True
        else:
            return False
    else:
        raise TypeError(f'Expected class Person got {type(other)}')

def __repr__(self):
    return f'Person({self._first_name}, {self._middle_name}, ' \
           f'{self._last_name}, {self._dob}, {self._age}, ' \
           f'{self._sex}, {self._married}, {self._hair_color}, ' \
           f'{self._eye_color}, {self._weight}, ' \
           f'{self._height}, {self._sort_by})'

def __str__(self):
    return f'Name: {self._first_name} {self._middle_name} ' \
           f'{self._last_name}\nDate of Birth: {self._dob}\n' \
           f'Age: {self._age}\nSex: {self._sex}\nMarried: {self._married}\n' \
           f'Hair Color: {self._hair_color}\n' \
           f'Eye Color: {self._eye_color}\nWeight: {self._weight}\n' \
           f'Height: {self._height}\n)'
epsilonv
  • 1
  • 3
  • User-defined objects *are like any other* in this regard. You would use the exact same approach, pass a key-function to the `sorted` built-in – juanpa.arrivillaga Mar 31 '21 at 00:11
  • As an aside, you have a bunch of pointless `property`s in your class definition. Don't use a `property` if your getter/setters don't *do anything useful*. Also, why in the world are you defining a dictionary that simply has the same exact data as the instances themselves, and then assigning that dictionary to `self.selection`?? Why? – juanpa.arrivillaga Mar 31 '21 at 00:12
  • As another aside, your implementation of the rich comparison operators isn't entirely correct. Don't `raise TypeError(f'Expected class Person got {type(other)}')` instead, `return NotImplemented` would be the normal part of that protocol – juanpa.arrivillaga Mar 31 '21 at 00:15

0 Answers0