Write Better Python Code
This repository contains the code examples used in my Write Better Python Code series published on YouTube:
https://www.youtube.com/playlist?list=PLC0nd42SBTaNuP4iB4L6SJlMaHE71FG6N
This repository contains the code examples used in my Write Better Python Code series published on YouTube:
https://www.youtube.com/playlist?list=PLC0nd42SBTaNuP4iB4L6SJlMaHE71FG6N
Saw your posts on reddit and watched your first video, the one on coupling. Before watching the walk-through, I had a try at improving the "before" code alone. I thought it could be fun to discuss that here, if you or someone else is up to it (btw, thanks for putting this up in a repo, super convenient!). Maybe it's silly. In any case, it's hard to find the right kind of feedback on these kinds of exercises (when you're self-learning and it's not just Hello World with a SyntaxError anymore) ;). And maybe you get something out of it by seeing how viewers "interpret" your content.
import random
import string
from dataclasses import dataclass, field
from enum import Enum
from typing import Union
class VehicleRegistry:
def __init__(self, id_length) -> None:
self.id_length = id_length
def random_id(self):
length = self.id_length
id = "".join(random.choices(string.ascii_uppercase, k=length))
license = f"{id[:2]}-{''.join(random.choices(string.digits, k=2))}-{''.join(random.choices(string.ascii_uppercase, k=2))}"
return id, license
class PropulsionTax(Enum):
ELECTRIC = 0.02
COMBUSTION = 0.05
@dataclass
class Vehicle:
make: str
model: str
price: int
tax_bracket: PropulsionTax
# Include in class data (repr, ...), but do not init it, calculate it later:
tax: float = field(init=False)
# Straight from the factory, doesn't have any of these yet:
id: Union[str, None] = None
license: Union[str, None] = None
def __post_init__(self):
self.tax = self.price * self.tax_bracket.value
class Application:
def __init__(self, vehicle: Vehicle):
self.vehicle = vehicle
self.registry = VehicleRegistry(12)
def register_vehicle(self):
self.vehicle.id, self.vehicle.license = self.registry.random_id()
print("Registration complete. Vehicle information:")
print(self.vehicle)
vehicle = Vehicle(
make="Volkswagen",
model="ID3",
price=35000,
tax_bracket=PropulsionTax.ELECTRIC,
)
app = Application(vehicle)
app.register_vehicle()
Comparing to your after code, there are some differences. There are a bunch of assumptions which might be incorrect.
print
methods, implement __str__
(or __repr__
) and call built-in print
on the objects. But wait...dataclass
es in a wild plot twist! That didn't end up happening, yet those bad boys are perfect for this use case. They have built-in repr
esentation for all their member variables, so the previous step is solved automatically.Enum
. Advantages:
VehicleRegistry
was some kind of office that does... vehicle registrations. As such, it probably uses (again, an assumption) IDs of the same length anyway, for all vehicles. Hence, this is now a parameter to the constructor itself.Application
for a vehicle. This makes sense. You hand in a string representing the vehicle, but we can just hand in the vehicle object itself. Makes it much more dynamic and less coupled, in my view.Application
or, rather, its register_vehicle
method creates the vehicle. I thought of the process more like real-life:
vehicle = Vehicle(...)
on the module level). At that point, it doesn't have a registration ID or license plate yet, but it comes with "empty slots" (defaults of None
) for them. This abstraction works especially well for the license plate. Cars literally come with a blank space where that will go later, for which None
is the perfect representation.Application
which has a (as opposed to is a/inheritance) vehicle. Makes sense, the application form contains the vehicle data sheet (the Vehicle
dataclass instance object itself).Application
to the registry, where we simply slap on the new ID/license plate onto the new car, replacing None
.I think using dataclass
es is a big improvement and nicely showcases the "batteries included" aspect of Python. Lots of boilerplate taken care of for us. Secondly, pulling out the "car creation" process entirely makes things much simpler, too, while being more in line with the metaphore, in my mind. This all leads to very short (cohesive?) functions/methods will quite low coupling.
Would be happy to hear your or someone else's thoughts on this! Loving the series so far, finally good content that fills the huge gap between Hello World (for which approx. 484092 guides exist) and actually working in the industry.
https://github.com/ArjanCodes/betterpython/blob/4151e184748856cbb3ea32ff8ef1bcca448e6a68/1%20-%20coupling%20and%20cohesion/coupling-cohesion-after.py#L60
$ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
./betterpython/7 - dealing with errors/monadic-error-handling/example.py:22:35: F821 undefined name 'Blog'
def fetch_blog(blog_id) -> Result['Blog', Exception]:
^
./betterpython/7 - dealing with errors/monadic-error-handling/example.py:41:27: F821 undefined name 'Blog'
def blog_to_dict(item) -> 'Blog':
^
./betterpython/7 - dealing with errors/monadic-error-handling/example.py:52:28: F821 undefined name 'Blog'
def verify_access(blog) -> 'Blog':
^
3 F821 undefined name 'Blog'
3
Hi Arjan,
thanks a lot for your videos on YouTube, it's super helpful for me to learn more about Python. You are doing a great work to the community, really appreciating.
Here is just my simple idea how to (possibly) use composition instead of inheritance in the dependency-inversion-after.py
.
Please if you have some time, could you check this code and comment what would you change (if anything) and if you think it make sense we could even merge it.
Thanks again.
Hi there.
I like your examples, so I'd like to propose some minor changes in the SOLID examples. The proposed changes are spacing and naming changes so the code is more consistent with PEP8. I hope this helps out your project!
The functionality of both dictionaries and defualtdict are almost same except for the fact that defualtdict never raises a KeyError.
When key is not present it will return --> [] (empty list)
This is how it improves the code
Before
if event_type not in subscribers:
subscribers[event_type] = []
subscribers[event_type].append(fn)
subscribers[event_type].append(fn)
If you find yourself creating a class just to call a function, you probably just needed a function... Also, Enums are better than dictionaries for holding an immutable table as in this demo, and dataclasses make the init declaration for you.
UrduPython Write simple Python in Urdu. How to Use Write Urdu code in سامپل۔پے The mappings are as following: "۔": ".", "،":
The-Next-Gen-AI-Eye-Writer The Eye tracking Technique has become one of the most popular techniques within the human and computer interaction era, thi
Sentance Parser Executing the Program Make sure Python 3.6+ is installed. Install requirements $ pip install requirements.txt Run the program:
Task-Informed Meta-Learning This repository contains examples of Task-Informed Meta-Learning (paper). We consider two tasks: Crop Type Classification
Reddit text to speech generator A basic reddit tts video generator Current functionality Generate videos for subs based on comments,(askreddit) so rea
Simple Python script to scrape youtube channles of "Parity Technologies and Web3 Foundation" and translate them to well-known braille language or any
youtube-dl and ffmpeg Windows Explorer Integration Download videos from YouTube/Twitch/Twitter and more (any platform that is supported by youtube-dl)
Metal Gear Solid: HD Textures Higher quality textures for the Metal Gear Solid series. The goal is to maximize the quality of assets that the engine w
7 Python code smells This repository contains the code for the Python code smells video on the ArjanCodes channel (watch the video here). The example
Code AutoComplete code-autocomplete, a code completion plugin for Python.
This codebase is being actively maintained, please create and issue if you have issues using it Basics All data files are included under losses and ea
CodeT5: Identifier-aware Unified Pre-trained Encoder-Decoder Models for Code Understanding and Generation This is the official PyTorch implementation
Galois is an auto code completer for code editors (or any text editor) based on OpenAI GPT-2. It is trained (finetuned) on a curated list of approximately 45K Python (~470MB) files gathered from the Github. Currently, it just works properly on Python but not bad at other languages (thanks to GPT-2's power).
Combo List Fixer A simple python code to fix your combo list by removing any text after a separator or removing duplicate combos Removing any text aft
CodeJ A python project made to generate code using either OpenAI's codex or GPT-J (Although not as good as codex) Install requirements pip install -r
Description In this repository you will find the Code to my Chatbots, developed in Python. I'll explain the structure of this Repository later. Requir
Expediting Vision Transformers via Token Reorganizations This repository contain
?? codex_py2cpp ?? OpenAI Codex Python to C++ Code Generator Your Python Code is too slow? ?? You want to speed it up but forgot how to code in C++? ⌨
Ucto for Python This is a Python binding to the tokeniser Ucto. Tokenisation is one of the first step in almost any Natural Language Processing task,