The Python Class Checklist

Thomas J. Kennedy

Contents:

1 Overview

The class checklist can be though of as a set of emergent properties (or, if you think as the table as a single entity, an emergent property). Let us start with a comparison of C++, Java, Python, and Rust. There is quite a bit of information in the table. Focus on the Python column.

C++ Java Python 3 Rust
Default Constructor Default Constructor __init__ new() or Default trait
Copy Constructor clone and/or Copy Constructor __deepcopy__ Clone trait
Destructor
finalize (deprecated/discouraged) __del__ Drop trait
Assignment Operator (=)
Accessors (Getters) Accessors (Getters) Accessors (@property) Accessors (Getters)
Mutators (Setters) Mutators (Setters) Setters (@attribute.setter) Mutators (setters)
Swap
Logical Equivalence Operator (==) equals __eq__ std::cmp::PartialEq trait
Less-Than / Comes-Before Operator (<) hashCode __hash__ std::cmp::PartialOrd trait
std::hash (actual hashing) hashCode __hash__ std::hash::Hash trait
Stream Insertion Operator (<<) toString __str__ std::fmt::Display trait
__repr__ std::fmt::Debug trait
begin() and end() iterator __iter__ iter() and iter_mut()

For this discussion… we will focus on the Python column (since our focus is on learning Python). However, the Python Class Checklist emerges out of how object-oriented code is written (e.g., needing to compare two user-defined objects).

2 Reducing Scope

Let is extract the Python column from the table…

Python 3
__init__
__deepcopy__
 
__del__
 
Accessors (@property)
Setters (@attribute.setter)
 
__eq__
__hash__
__hash__
__str__
__repr__
__iter__

Let us also remove the empty rows (along with the duplicated __hash__)…

Python 3
__init__
__deepcopy__
__del__
Accessors (@property)
Setters (@attribute.setter)
__eq__
__hash__
__str__
__repr__
__iter__

That is a bit more manageable… even if it is still as clear as mud.

3 Adding Some Clarity

Let us add a brief description column.

Description Python 3
Create a “default” or “empty” object __init__
Create an identical (yet distinct) copy of an object __deepcopy__
Define resources that need to be “closed” before deallocation __del__
Access a pseudo-private data member Accessors (@property)
Update a pseudo-private data member Setters (@attribute.setter)
Compare two objects __eq__
Compute a number that can be used to store an object in a dict or set __hash__
Generate a human readable string for output __str__
Generate a string for debugging output __repr__
Allow access to entries in a collection __iter__

The biggest mistake one can make is to say… I must include all of these in my class. This is a checklist… every item must be considered based on the nature of the class to be implemented.

Note that __init__ defines how to initialize an object after __new__ has actually created the object. In this course (at least for now)… we will ignore __new__. It is one of those functions that you usually should not define.

4 Private, Public, and Dunder

While there is no true private in Python, name mangling through dunder names is constantly abused to fake it, e.g.,

class Point:
    def __init__():

        self.__x = 0
        self.__y = 0

def main():

    pnt = Point()

    print(pnt.x)
    pnt._Point__x = 1

 
if __name__ == "__main__":
    main()

Note that the reason for name mangling is to avoid naming collisions (e.g., between base and derived classes, especially when multiple inheritance is involved).