Python Tips & Tricks: 3 hacks om een Tesla-fabriek te starten

Python Tips & Tricks: 3 hacks om een Tesla-fabriek te starten

In deze blogpost wil ik je 3 Python-trucs laten zien die bewijzen dat Python geweldig is. Stel je voor dat je de baas bent van een coole autofabriek, zoals Tesla. Om je reputatie hoog te houden wil je auto’s van maximale kwaliteit produceren, maar tegelijkertijd je efficiëntie zo veel mogelijk verbeteren. Zo bespaar je allemaal tijd die je aan andere dingen kunt besteden, zoals een ei bakken .

Natuurlijk is dit alleen maar onze verbeelding, en we hebben geen autofabriek, maar niemand kan ons tegenhouden om te dromen. Voor nu stellen we onze auto’s voor als Python-klassen.

Ik vertel je hoe je dit op de professionele manier doet in 3 hacks…

Hack #1: Verspil geen tijd, gebruik Dataclasses

Vanaf Python 3.7 hebben we de dataclass decorator tot onze beschikking. Met dataclasses kun je veel boilerplate-code automatisch voor je laten doen, vooral voor het instantiëren en als string weergeven van je objecten. Precies wat we nodig hebben om onze auto’s massaal te produceren met minimale overhead!

Stel je nu voor dat je de Tesla-fabriek hebt en een klasse Car wilt maken met 4 parameters die je auto’s definiëren. Sommige met een standaardwaarde en andere niet:


class Car:
brand: str
model: str
self_driving: bool
wheels: int # I want this one with default value 4

def __init__(self, brand: str, model: str, self_driving: bool, wheels: int = 4):
self.brand = brand
self.model = model
self.self_driving = self_driving
self.wheels = wheels

Ik weet wat je denkt…. Dat is inderdaad saai. Ik wil niet eens beginnen met het schrijven van de repr method om de objecten van deze klasse als string weer te geven. Wat een gedoe!

Gelukkig is Python de perfecte tool voor de luie developer. Het maakt de __init__ en repr methods voor mij. Laten we kijken hoe je dat doet:


from dataclasses import dataclass

@dataclass
class Car:
brand: str
model: str
self_driving: bool
wheels: int = 4

We kunnen het nu zo gebruiken:

>>> my_car = Car("Tesla", "Model S", True)
>>> print(my_car)
Car(brand='Tesla', model='Model S', self_driving=True, wheels=4)

Was dat niet makkelijk? Met de tijd die je hebt bespaard door geen repetitieve code te schrijven, kun je een kop koffie gaan halen. Je hebt het verdiend!

Hack #2: Geef je klasse een aangepast type

Nu vraag je je af hoe je kunt garanderen dat al je geproduceerde auto’s voldoen aan dezelfde strenge kwaliteitseisen die je mag verwachten van een geweldig bedrijf als Tesla. Ik wil bijvoorbeeld dat al mijn auto’s een werkende batterij hebben!

Zo zou een van je waardeloze concurrenten het doen:


from dataclasses import dataclass

@dataclass
class Car:
brand: str
model: str
self_driving: bool
wheels: int = 4

def charge_battery(self):
raise NotImplementedError


class MyCar(Car):
def charge_battery(self):
print("battery charged!")

Maar dit is niet netjes. Ten eerste omdat je nog een klasse MyCar moet maken die in feite hetzelfde doet als de oorspronkelijke Car. En ten tweede omdat alle auto’s af fabriek een batterij zouden moeten hebben. In dit geval besteden we de kwaliteitscontrole uit aan de eindgebruiker. Elon Musk zou dat nooit doen!

Daarom brengt de behulpzame Python ons Metaclasses . Een Metaclass is in feite het type van een klasse. Je kunt Car dus van het type Electric maken, wat betekent dat hij een batterij moet hebben om te werken, net zoals een integer per definitie een getal zonder decimaal deel is.


from dataclasses import dataclass


class Electric(type):
def __init__(cls, name, bases, namespace):
obj = super().__init__(name, bases, namespace)

if "charge_battery" not in namespace:
raise RuntimeError(f"{name} has to implement the charge_battery method")


@dataclass
class Car(metaclass=Electric):
brand: str
model: str
self_driving: bool
wheels: int = 4

Dit stuk code is nu onmogelijk: een elektrische auto zonder batterij kan niet bestaan, en Python laat je dat weten voordat je überhaupt een object kunt instantiëren!

RuntimeError: Car has to implement the charge_battery method

Net als deze auto zal de code niet wegrijden. De developer wordt nu gedwongen om de charge_battery method te implementeren, nog voordat hij probeert de auto te instantiëren! Maak je dus geen zorgen: je Tesla-fabriek zal geen auto’s hebben zonder een of andere vorm van batterij, en de klant zal tevreden zijn!

Hack #3: Houd je productieaantallen bij met WeakSets!

Nu wil je als fabrieksbaas weten hoeveel auto’s je hebt geproduceerd. Maar je wilt alles netjes en automatisch, omdat je weet dat mensen dingen vaak vergeten en je geen cent wilt verliezen!

De naïeve manier, die developers gegarandeerd meer werk en hoofdpijn oplevert, zou zijn om ergens een lijst bij te houden en eraan te denken elke auto die je produceert te tellen:

>>> cars_list = []
>>> car_one = Car("Tesla", "Model S", True)
>>> cars_list.append(car_one)
>>> car_two = Car("Tesla", "Model 3", True)
>>> cars_list.append(car_two)
...

Vervelend, hè? Je hebt iemand nodig die altijd oplet welke auto’s zijn geproduceerd en ze aan een lijst toevoegt. Ook wordt het lastig om auto’s uit die lijst te verwijderen als je hun instanties verwijdert. En wat als we de tel kwijtraken? Laten we het beter doen door gebruik te maken van wat we in Hack 2 hebben geleerd met onze Electric Metaclass :


from dataclasses import dataclass
from weakref import Weakset


class Electric(type):
instances = WeakSet()

def __init__(cls, name, bases, namespace):
obj = super().__init__(name, bases, namespace)

if "charge_battery" not in namespace:
raise RuntimeError(f"{name} has to implement the charge_battery method")

def __call__(self, *args, **kwargs):
obj = super().__call__(*args, **kwargs)
self.instances.add(obj)
return obj


@dataclass
class Car(metaclass=Electric):
brand: str
model: str
self_driving: bool
wheels: int = 4

Kijk naar het instances-attribuut dat we aan de Metaclass hebben toegevoegd. Een WeakSet is in feite een lijst die verwijzingen naar objecten bijhoudt. Je kunt zulke pointers aan de lijst toevoegen en ze worden “automagisch” verwijderd als de verwijzing uiteindelijk naar niets meer wijst.

Zoals je ziet overschrijven we de _ _call __ method om een verwijzing naar het object dat we net hebben gemaakt toe te voegen aan onze instances-lijst. Deze method wordt aangeroepen wanneer je een nieuwe klasse instantieert.

Laten we het in actie zien!

>>> car_one = Car("Tesla", "Model S", True)
>>> car_two = Car("Tesla", "Model 3", True)
>>> for car in Electric.instances:
       print(car)
Car(brand='Tesla', model='Model S', self_driving=True, wheels=4)
Car(brand='Tesla', model='Model 3', self_driving=True, wheels=4)>>> del car_one  # Destroy one of the cars
>>> print(len(Electric.instances))
1

Zoals je kunt zien, kunnen we nu itereren over alle auto’s die we hebben gemaakt en ze bijhouden, zonder dat een developer extra uren hoeft te maken. Geweldig!

Ga jij je eigen Tesla-fabriek beginnen?

Dus als je ooit een autofabriek begint, onthoud dan deze 3 hacks. En als je terugkomt in de realiteit en veel objecten moet produceren terwijl je zeker wilt weten dat ze een gemeenschappelijke interface hebben, kun je deze hacks in veel situaties gebruiken. Ze besparen je altijd tijd.

Maar wat doe je met die tijd? Je zou je droom kunnen waarmaken en een echte autofabriek beginnen, maar eerst raad ik je aan om te lezen over hoe je een code-ei van goede kwaliteit bakt .

Blijf ons volgen voor meer Python Tips & Tricks!

Python Tips & Tricks: 3 hacks om een Tesla-fabriek te starten