Blog

Python Weihnachtsdekoration

Da Halloween nun vorbei ist und der Advent vor der Tür steht, ist es Zeit für die Weihnachtsdekoration. Und wie kann man besser in Stimmung für die Feiertage kommen als mit einem Python-Projekt 🐍?

Das Anbringen von Weihnachtsdekorationen kann eine ziemlich zeitintensive Aufgabe sein. Es ist also am besten, das Dekorieren dem Partner zu überlassen. Da das in der Praxis aber eher zu einem schiefen Haussegen als zu Zeitersparnis führt, ist ein Kompromiss gefragt. Beim gemeinsamen Dekorieren im letzten Jahr wurde mehr Pause gemacht als dekoriert, wodurch ein riesen Chaos entstand. In diesem Jahr werden wir daher alle Pausen timen um zu schauen, ob wir wirklich mehr Pause machen als Dekorieren.

Also timen wir dieses Jahr mithilfe eines Python christmas_break_timer wie viel Zeit wir wirklich verplempern.

import time
def take_a_break():
    time.sleep(1)
break_start = time.time()
take_a_break()
break_end = round((time.time() - break_start))
print("The break took {timing} second(s).".format(timing=break_end))
The break took 1 second(s).

Aber jedes Mal break_start und break_end schreiben, wenn wir eine Pause machen, würde definitiv noch mehr Zeit in Anspruch nehmen. Erstellen wir also einen hilfreichen christmas_break_timer.

from contextlib import contextmanager

@contextmanager
def christmas_break_timer():
    break_start = time.time()
    yield
    break_end = round((time.time() - break_start))
    print("The break took {timing} second(s).".format(timing=break_end))

Jetzt können wir einfach jedes Mal den christmas_break_timer verwenden, wenn wir eine Pause machen!

with christmas_break_timer():
    take_a_break()
The break took 1 second(s).

Toll! Diese with ...: Syntax ist wirklich praktisch. Und der Decorator @contextmanager macht die Implementierung wirklich einfach. Für einen anspruchsvolleren Kontextmanager, zum Beispiel für das Timing des Weihnachtsessens, können wir den Kontextmanager ohne zusätzliche Bibliotheken als Klasse implementieren.

class ChristmasDinnerTiming:
    def __init__(self, persons, course):
        self.persons = persons
        self.course = course
        self.total_meals = self.persons * self.course
        
    def __enter__(self):
        print("Begin preparation of {n_meals} meals for {n_persons} persons.".format(
            n_meals=self.total_meals,
            n_persons=self.persons,
        ))
        self.start_time = time.time() 
        return self

    def __exit__(self, *args):
        prepare_time = round((time.time() - self.start_time),1)
        prepare_time = prepare_time * self.total_meals
        print("The dinner preparation took {timing} hours.".format(timing=prepare_time))
def prepare_one_meal():
    time.sleep(0.5)

def set_the_table(n_persons):
    print("I set the table for {n_persons} persons.".format(n_persons=n_persons))
with ChristmasDinnerTiming(persons=6, course=3) as dinner_prep:
    set_the_table(n_persons=dinner_prep.persons)
    prepare_one_meal()
Begin preparation of 18 meals for 6 persons.
I set the table for 6 persons.
The dinner preparation took 9.0 hours.

Nachdem wir den Timer fertig haben, können wir mit der Dekoration fortfahren. Der @contextmanager Decorator, den wir für unseren christmas_break_timer verwendet haben, ist wirklich hilfreich. Machen wir einen davon!

Aber Moment.. was ist überhaupt ein Decorator?

Ein Decorator übernimmt eine Funktion (und möglicherweise einige Argumente) und gibt diese Funktion sowie die Funktionalität des Decorator selbst zurück.

from decorator import decorator
# eine Decorator-Funktion braucht immer die Argumente func, *args und **kw
@decorator
def decorative_christmas_break_timer(func, *args, **kw):
    break_start = time.time()
    res = func(*args, **kw)
    break_end = round((time.time() - break_start))
    print("The break time was {timing} seconds.".format(timing=break_end))
    return res
# Jetzt können wir unseren decorative_break_timer als schönen Weihnachts-Decorator verwenden!
@decorative_christmas_break_timer
def take_a_break(break_time):
    time.sleep(break_time)
    return break_time
nice_break = take_a_break(1)
@decorative_christmas_break_timer
def take_a_break_nap(nap_time):
    time.sleep(nap_time)
    return nap_time
nap_time = take_a_break_nap(5)
The break time was 5 seconds.

Doch nicht jeder hat die Mittel zu Weihnachten, einfach einen @decorator zu importieren. Aber keine Sorge, mit etwas Einfallsreichtum kann jeder einen decorative_christmas_break_timer haben!

Doch nicht jeder hat die Mittel zu Weihnachten, einfach einen @decorator zu importieren. Aber keine Sorge, mit etwas Einfallsreichtum kann jeder einen decorative_christmas_break_timer haben!

Was für ein schöner Weihnachts-Decorator. Aber da Weihnachten die Zeit der Liebe und der Verbindung ist, kombinieren wir die Funktionalität unseres Kontextmanagers und des Decorators.

from contextlib import ContextDecorator
class DecorativeChristmasBreakTimer(ContextDecorator):
    def __enter__(self):
        self.break_start = time.time()
        return self
    def __exit__(self, *args):
        break_end = round((time.time() - self.break_start))
        print("The break time was {timing} second(s).".format(timing=break_end))
def tv_break():
     time.sleep(2)

with DecorativeChristmasBreakTimer():
    tv_break()

@DecorativeChristmasBreakTimer()
def tv_break(x):
    time.sleep(x)
    return x
tv_time = tv_break(3)
The break time was 2 second(s).
The break time was 3 second(s).

Nun, wenn sich das nicht wie Weihnachten anfühlt, dann weiß ich auch nicht. Vielleicht kann man einen Decorator implementieren, der Last Christmas spielt?