Wiederholen einer API Abfrage und Darstellung der neuen Daten

Fragen zu Tkinter.
Antworten
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@blabla193: Noch ein paar Anmerkungen zum Quelltext:

Sternchen-Importe sind Böse™. Gerade bei `tkinter` holt man sich da über 100 Namen in das Modul von denen nur ein kleiner Bruchteil benötigt wird. Das macht es schwerer nachzuvollziehen welcher Name wo her kommt. Und es besteht die Gefahr von Namenskollisionen.

`locale`, `os`, und `sys` werden importiert, aber gar nicht verwendet.

`time` wird auch nicht wirklich gebraucht, das Du auch das `datetime`-Modul verwendest, was auch alles kann was Du da machst. Insbesondere ist es total unsinnig für Tag, Monat, und Jahr `time.strftime()` aufzurufen, aus den Zeichenketten ganze Zahlen zu machen, um daraus dann ein `date`-Objekt zu erstellen. Die haben eine `today()`-Methode die das aktuelle Datum als `date`-Objekt zur Verfügung stellen. Abgesehen davon, dass das so wie Du das machst sehr umständlich ist, gilt auch hier, dass die Zeit zwischen den drei Aufrufen ja fortschreitet, und sich deshalb nicht alle drei `time.strftime()`-Aufrufe auf den gleichen Tag beziehen müssen.

Für den Import von `date` und `datetime` aus `datetime` braucht man keine zwei ``import``-Anweisungen, das kann man in einer erledigen.

Konstanten schreibt man in Python KOMPLETT_GROSS.

Zu den Linienkommentaren hat Sirius3 ja schon etwas gesagt – ich würde da gerne noch hinzufügen das diese Zeilen mit 281 Zeichen auch viel zu lang sind. Man muss auch heute noch davon ausgehen, das es Umgebungen gibt die auf die traditionellen 80 Zeichen pro Zeile eingestellt sind.

Kommentare sollten dem Leser einen Mehrwert über den Code geben. Da sollte nicht stehen *was* gemacht wird, denn das steht da ja bereits als Code, sondern *warum* der Code das so macht. Sofern das nicht offensichtlich ist. Vieles wird offensichtlicher wenn man vernünftige Namen verwendet und keine komischen, kryptischen Abkürzungen. Wenn man `temperature` meint, sollte man nicht `temp` schreiben, was ziemlich oft auch für `temporary` steht, und damit für Verwirrung sorgen kann.

Man muss nicht jedes Zwischenergebnis an Namen binden, vor allen nicht wenn das sehr generische und dann auch noch durchnummerierte Namen sind. Überhaupt sollte man Namen nicht nummerieren. Das ist in der Regel ein Zeichen das man sich über die Namen mehr Gedanken machen sollte, oder gar keine einzelnen Namen möchte, sondern eine Datenstruktur. Oft eine Liste.

Bei den Bildern für Sonnenauf- und Untergang wird zum erstellen der Label mit dem jeweiligen Bild das gleiche gemacht. Solche Wiederholungen verletzen das DRY-Prinzip („Don't Repeat Yourself“). Hier würde sich eine Funktion anbieten.

Datei- und Schriftartnamen, sowie die URL der API würde ich als Konstanten definieren, damit da leicht Änderungen dran vornehmen kann ohne durch den gesamten Code gehen zu müssen.

Die Abfrage der Wetterdaten aus dem Internet und die Darstellung sollte man trennen, damit man die Abfrage einzeln testen kann, und auch leichter austauschen kann, wenn man den Anbieter für die Daten wechseln möchte oder muss.

Das Python-Listen von der Tk-Anbindung auf Tcl-Listen mit jeweils einem Leerzeichen zwischen jedem Element abgebildet werden, und die im Kontext von Zeichenketten den Inhalt dann als eine Zeichenkette darstellen, ist aus Python-Sicht ein wenig sehr ”magisch”, weil man da etwas über Tcl wissen muss um das zu verstehen, was man auch normal in Python durch Zeichenkettenformatierung ausdrücken kann, was dann Python-Programmierer besser/leichter verstehen.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from collections import namedtuple
from datetime import datetime as DateTime

import requests
from addict import Dict
from PIL import Image, ImageTk

OPEN_WEATHER_MAP_API_URL = (
    'http://api.openweathermap.org/data/2.5/weather'
    '?appid=...&q=tuebingen'
)
OPEN_WEATHER_MAP_DELAY = 30  # minutes.

SUNRISE_IMAGE_FILENAME = 'SAUFGANG.png'
SUNSET_IMAGE_FILENAME = 'SUNTERGANG.png'
BACKGROUND_COLOR = 'black'
FONT_NAME = 'Verdana'
WEEKDAY_NAMES = [
    'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag',
    'Freitag', 'Samstag', 'Sonntag'
]


Weather = namedtuple(
    'Weather', 'sunrise sunset temperature min_temperature max_temperature'
)


def convert_kelvin_to_celsius(value):
    return value - 273


def get_weather(url):
    data = Dict(requests.get(url).json())
    return Weather(
        DateTime.fromtimestamp(data.sys.sunrise),
        DateTime.fromtimestamp(data.sys.sunset),
        convert_kelvin_to_celsius(data.main.temp),
        convert_kelvin_to_celsius(data.main.temp_min),
        convert_kelvin_to_celsius(data.main.temp_max),
    )


def update_weather(
    sunrise_label,
    sunset_label,
    temperature_label,
    min_temperature_label,
    max_temperature_label,
):
    weather = get_weather(OPEN_WEATHER_MAP_API_URL)
    sunrise_label['text'] = format(weather.sunrise, '%H:%M Uhr')
    sunset_label['text'] = format(weather.sunset, '%H:%M Uhr')
    temperature_label['text'] = f'{weather.temperature:.1f} °C'
    min_temperature_label['text'] = f'min.: {weather.min_temperature:.1f} °C'
    max_temperature_label['text'] = f'max.: {weather.max_temperature:.1f} °C'
    sunrise_label.after(
        OPEN_WEATHER_MAP_DELAY * 60 * 1000,
        update_weather,
        sunrise_label,
        sunset_label,
        temperature_label,
        min_temperature_label,
        max_temperature_label,
    )


def create_image_label(master, filename):
    image = ImageTk.PhotoImage(
        Image.open(filename).resize((70, 70), Image.ANTIALIAS)
    )
    label = tk.Label(master, image=image, borderwidth=0)
    label.image = image
    return label


def update_date_and_time(time_label, seconds_label, weekday_label, date_label):
    now = DateTime.now()
    time_label['text'] = format(now, '%H:%M')
    seconds_label['text'] = format(now, '%S')
    weekday_label['text'] = WEEKDAY_NAMES[now.weekday()]
    date_label['text'] = format(now, '%d.%m.%Y')
    time_label.after(
        500,
        update_date_and_time,
        time_label,
        seconds_label,
        weekday_label,
        date_label
    )


def main():
    root = tk.Tk()
    root.attributes('-fullscreen', True)
    root.config(background=BACKGROUND_COLOR)

    create_image_label(root, SUNRISE_IMAGE_FILENAME).place(x=830, y=670)
    create_image_label(root, SUNSET_IMAGE_FILENAME).place(x=830, y=740)

    time_label = tk.Label(
        root, font=(FONT_NAME, 100), bg=BACKGROUND_COLOR, fg='white'
    )
    time_label.place(x=550, y=63)
    seconds_label = tk.Label(
        root, font=(FONT_NAME, 60), bg=BACKGROUND_COLOR, fg='grey'
    )
    seconds_label.place(x=980, y=71)
    weekday_label = tk.Label(
        root, font=(FONT_NAME, 40), bg=BACKGROUND_COLOR, fg='white'
    )
    weekday_label.place(x=0, y=650)
    date_label = tk.Label(
        root, font=(FONT_NAME, 50), bg=BACKGROUND_COLOR, fg='white'
    )
    date_label.place(x=0, y=740)

    update_date_and_time(time_label, seconds_label, weekday_label, date_label)


    sunrise_label = tk.Label(
        root, font=(FONT_NAME, 30), bg=BACKGROUND_COLOR, fg='white'
    )
    sunrise_label.place(x=900, y=680)
    sunset_label = tk.Label(
        root, font=(FONT_NAME, 30), bg=BACKGROUND_COLOR, fg='white'
    )
    sunset_label.place(x=900, y=750)
    temperature_label = tk.Label(
        root, font=(FONT_NAME, 80), bg=BACKGROUND_COLOR, fg='white'
    )
    temperature_label.place(x=890, y=500)
    min_temperature_label = tk.Label(
        root, font=(FONT_NAME, 30), bg=BACKGROUND_COLOR, fg='white'
    )
    min_temperature_label.place(x=1200, y=680)
    max_temperature_label = tk.Label(
        root, font=(FONT_NAME, 30), bg=BACKGROUND_COLOR, fg='white'
    )
    max_temperature_label.place(x=1200, y=750)
    
    update_weather(
        sunrise_label,
        sunset_label,
        temperature_label,
        min_temperature_label,
        max_temperature_label,
    )
    root.mainloop()


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten