Module 2: OOP, Code Style, and Reviews
Module Overview
When you're a software engineer, you're not just writing code for your own immediate needs - you're building a system that others will work on, from coworkers and open-source collaborators to future-you. To do this, we must write code based on shared design and style principles.
In this module, we will learn the basic principles of object-oriented programming (OOP), the most common paradigm for designing and building large codebases. We will also learn about standard code style, tooling, and the code review process.
Learning Objectives
- Create a basic Python class with a constructor, methods and fields
- Write stylistic (PEP 8) Python code and use a linter to encourage cleanliness and organization
Objective 01 - Create a basic Python class, with a constructor, methods, and fields
Required Resources
Overview
Python is a pragmatic multi-paradigm language, and object-oriented programming is one of the most important and widely used of its supported paradigms. In this module you'll learn how to make a basic Python class, and some of the common language used to describe elements of code in object-oriented programming.
Classes are the top level organizational structure in OOP. They are the blueprints for the different objects that will exist within our program.
For example, if a developer writes a Player
class, they can then use this blueprint to
create many different copies of Player
objects throughout a program.
Classes contain:
- Fields - also known as attributes or properties. They hold state information about
a specific instance of an object. Examples might include
name
,size
, orimage
. - Methods - functions that belong to a specific class. They represent the behaviors
this object should have. If we continue to think about the
Player
class, it might have methods such asmove()
orjump()
. - Initializer - special method, defined with
__init__()
in Python, used to define how a class instance is to be created (instantiated). - self - a keyword used to refer to class-level variables and methods. These have scope across the entire class. Variables may also be declared normally and will have scope limited to the block of code they are declared within.
Follow Along
Consider the following class as a way to represent complex numbers.
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
x.r, x.i
Execute the above code in a Python repl/environment of your choice (a notebook can work too). Make multiple instances of the class, inspect them, and try to use them interactively to perform basic mathematics (arithmetic).
Challenge
Rewrite the Complex
class with a method add
that takes a complex number as an
argument and returns the sum of it with the complex number it is being called from
(self
).
Stretch goal - implement all basic arithmetic operations (subtract, multiply, divide).
Additional Resources
Objective 02 - Write stylistic PEP 8 Python code, and give and receive a basic code review
Required Resources
Overview
You say potayto, your coworker says potahto - how do you work on the same code? Style and code reviews are about consensus and common understanding - there is no single “right” style, but agreeing and doing things similarly makes the whole codebase more homogeneous and easier to read.
Code style refers to the “look” and formatting of the code - it is orthogonal to the actual logic or results. That is, code with “bad style” can still run and get results.
So why worry about style? Because, though it can run, code that is harder to read is more error prone, and harder to fix the inevitable errors that occur. It's also harder to extend and build on, which is the real long term goal of a production codebase.
In this module we will explore what makes for good style, and tools that help us enforce it. Note that in some contexts this is referred to as “linting”, and the corresponding tools as “linters.”
Follow Along
Consider the following code:
import math, sys;
def example1():
####This is a long comment. This should be wrapped to fit within 72 characters.
some_tuple=( 1,2, 3,'a' );
some_variable={'long':'Long code lines should be wrapped within 79 characters.',
'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
20,300,40000,500000000,60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
class Example3( object ):
def __init__ ( self, bar ):
#Comments should have a space after the hash.
if bar : bar+=1; bar=bar* bar ; return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
Pretty ugly, yes? And it's not just an aesthetic problem - the dense and at times inconsistent way the code is written means, even though it runs, it's hard to read and understand.
Now consider this version of it:
import math
import sys
def example1():
# This is a long comment. This should be wrapped to fit within 72
# characters.
some_tuple = (1, 2, 3, 'a')
some_variable = {
'long': 'Long code lines should be wrapped within 79 characters.',
'other': [
math.pi,
100,
200,
300,
9876543210,
'This is a long string that goes on'],
'more': {
'inner': 'This whole logical line should be wrapped.',
some_tuple: [
1,
20,
300,
40000,
500000000,
60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}
class Example3(object):
def __init__(self, bar):
# Comments should have a space after the hash.
if bar:
bar += 1
bar = bar * bar
return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
Much better! Yes, it's many more lines (a lot of style rules are about breaking things out), but with more whitespace comes more readability. It's also consistent, following a standard that is widely used in the Python world.
We'll also discuss peer code reviews - remember, in your career you will read more code than you write! Consider the following tips for reading and giving feedback on code from other people:
- Can you follow the code flow/layout?
- Can you understand the logic/reasoning for what it is doing?
- Could you build with (import and use) or extend on it (as a developer adding more to the codebase)?
Challenge
The above example was generated automatically by autopep8 - try installing and running it on some of your own code, and see the results!
Additional Resources
Guided Project
In this guided project, we'll apply our knowledge of OOP principles and Python style guidelines to create well-structured, readable code. Open guided-project.md in the GitHub repository below to follow along with the guided project.
Module Assignment
For this assignment, you'll apply object-oriented programming principles and Python style guidelines to create clean, well-structured code that follows industry best practices.
Solution Video
Additional Resources
Object-Oriented Programming
Code Style & Tools
- PEP 8 — the Style Guide for Python Code
- Google Python Style Guide
- Python extension for Visual Studio Code
- autopep8: Python tool