andie39‘s Fragen Thread

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Zwecks Unterscheidung von verliehen und verfügbaren Filmen habe ich mir folgende Lösung überlegt:

Ein Dictionary das zwei Keys kennt: Verliehen und verfügbar. Die Werte sind die Filme die dann in einer Liste diesen Keys zugeordnet werden.

Macht das Sinn?
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Eigentlich ist das eine Eigenschaft, die ich beim Film erwarten würde. Verliehen oder nicht. Oder ein Status der nicht nur 2 Werte haben kann: Verliehen/Verloren/Aussortiert.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

sparrow hat geschrieben: Mittwoch 19. Januar 2022, 06:17 Eigentlich ist das eine Eigenschaft, die ich beim Film erwarten würde. Verliehen oder nicht. Oder ein Status der nicht nur 2 Werte haben kann: Verliehen/Verloren/Aussortiert.

Eigenschaft? Also per Dictionary?
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Versuch es doch?
Ich sehe nicht, wo ein dict weiterhelfen könnte. Kann der Film gleichzeitig verfügbar und verliehen sein? Oder eher nicht? Wenn nicht, warum braucht es dann zwei Eigentschaften und nicht nur eine, die entwder oder ist?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@andie39,

es hängt davon ab welche Daten du über die Filme speichern möchtest.
Ein Dictionary, dazu passt gut eine json-Datei, kann beliebig verschachtelte Daten aufnehmen und ist in seiner Struktur sehr flexibel.

Code: Alles auswählen

movies = {
    "Rambo": {
        "verfügbar": True,
        "Spielzeit": 120,
        "Hauptdarsteller": {
            "Vorname": "Sylvester",
            "Nachname": "Stallone"
        },
    },
    "Rambo 2": {
        "verfügbar": False,
        "Spielzeit": 121,
        "Hauptdarsteller": {
            "Vorname": "Sylvester",
            "Nachname": "Stallone"
        },
    }
}
Listen von Listen oder Tupeln können nur tabellarische Daten aufnehmen. Dazu passen csv-Dateien oder Excel-Tabellen.

Code: Alles auswählen

movies = [
    ("Rambo", True, 120, "Sylvester Stalone"),
    ("Rambo 2", False, 121, "Sylvester Stalone")
]
Dictionaries können in Teilen auch Listen enthalten.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Darum frage ich.
Jetzt sollen die ja nur verfügbar oder verliehen kennen.
Was ist denn die beste Lösung nach den Profis hier?
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

sparrow hat geschrieben: Mittwoch 19. Januar 2022, 06:17 Eigentlich ist das eine Eigenschaft, die ich beim Film erwarten würde. Verliehen oder nicht. Oder ein Status der nicht nur 2 Werte haben kann: Verliehen/Verloren/Aussortiert.
Du meinst Eigenschaft aus der Objektorientietung?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@andie39,

verfügbar / verliehen ist *ein* Attribut, so wie an / aus. Man hat ja auch keine Anschalter und separate Ausschalter für's Licht. Ein Schalter kann beide Zustände darstellen. So ist das auch bei dem Attribut "verfügbar" / "verliehen" das ist ein boolscher Wahrheitswert.

verfügbar == True -> kann ausgeliehen werden
verfügbar == False -> kann nicht ausgeliehen werden.

Attribut, Eigenschaft, Property ist hier im weiteren Sinne das gleiche und hat erstmal nichts mit Objektorientierung zu tun.
Erst wenn es an die technische Umsetzung geht, kann es sein, dass das Attribut "verfügbar" auch ein Attribut in einer Klasse ist. Es kann aber auch einer Spalte in einer csv-Tabelle oder einem Schlüssel in einem Dictionary entsprechen.

Aktuell hast du ja nur das Attribut "Name" und das Attribut "verliehen" .
Das kann dann also eine csv-Datei sein, in der jeder Film ein Zeile mit seinen Attributen belegt.
In der Spalte "Name" steht halt "Rambo" oder "Escaperoom" und in der Spalte "verliehen" steht entweder True oder False.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Das war meine Frage, weil ich gerade das neue Thema Klassen begonnen habe.

Ob das gemeint war oder eine einfachere Lösung
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

NEUE FRAGE

Aktuell bin ich dabei list comprehensions zu verstehen, grundsätzlich tue ich das.
Aber doch stolpere ich etwas wenn es komplexer wird auch im Hinblick der Schleifen, sprich genauer wenn zwei Schleifen zum Einsatz kommen.
Bei einer einzelnen ist das nicht das Problem.

Beispiel:

numbers_times_2 = [x*2 for x in numbers]

Code: Alles auswählen

numbers = [1,2,3,4,5,6]
numbers_times_2 = [x*2 for x in numbers]
Das das gleiche wie:

Code: Alles auswählen

numbers_times_2 = []
    for x in numbers:
        numbers_times_2.append(x*2)
Das verstehe ich auch.

Aber bei einem größeren Beispiel:

Siehe hier:
https://einfachpython.de/python-list-co ... erstellen/

Code: Alles auswählen


weekday_temperatures = [
{'day': 'Monday',    'date': '2019-07-15', 'temperature': 31},
{'day': 'Tuesday',   'date': '2019-07-16', 'temperature': 33},
{'day': 'Wednesday', 'date': '2019-07-17', 'temperature': 27},
{'day': 'Thursday',  'date': '2019-07-18', 'temperature': 25},
{'day': 'Friday',    'date': '2019-07-19', 'temperature': 30},
{'day': 'Saturday',  'date': '2019-07-20', 'temperature': 31},
{'day': 'Sunday',    'date': '2019-07-21', 'temperature': 29},
{'day': 'Monday',    'date': '2019-07-22', 'temperature': 25},
{'day': 'Tuesday',   'date': '2019-07-23', 'temperature': 31},
{'day': 'Wednesday', 'date': '2019-07-24', 'temperature': 26},
{'day': 'Thursday',  'date': '2019-07-25', 'temperature': 23},
{'day': 'Friday',    'date': '2019-07-26', 'temperature': 22},
{'day': 'Saturday',  'date': '2019-07-27', 'temperature': 23},
{'day': 'Sunday',    'date': '2019-07-28', 'temperature': 32}
]
hot_work_days = [(hot_day['date'], hot_day['temperature']) for hot_day in[workday for workday in weekday_temperatures if workday['day'] not in ['Saturday', 'Sunday']] if hot_day['temperature'] >= 30]


Ich verstehe hier folgendes:

hot_work_days = [(hot_day['date'], hot_day['temperature']) for hot_day in[workday for workday in weekday_temperatures if workday['day'] not in ['Saturday', 'Sunday']] if hot_day['temperature'] >= 30]
Es ist in eine ecke Klammer gesetzt weil die Variabel ja eine Liste sein soll.
(hot_day['date'], hot_day['temperature']) ist am Anfang und ja wenn man so will das, was in der Liste ausgegeben werden soll.
Es soll der Wert von date und temperatur ausgegeben werden Zeile für Zeile also für jede Zeile hot_day und später dann eben unter der Bedningung das die Temperatur größer oder gleich 30 ist:
if hot_day['temperature'] >= 30]
Auch wird nach dem Tag durchsucht und auch hier gibt es eine Bedingung.

Was mir hier nicht ganz klar ist, hot_day iterierung läuft ja auch über die Liste: weekday_temperatures.
Das wird aber nicht direkt so benannt sonder:
for hot_day in und dann kommt in einer eigenen Klammer/Liste die Suche nach dem Tag, diese Suche/Schleife verweißt ja erst explizit auf die weekday_temperatures.
Ist für mich sehr schwierig zu verstehen.
Und die alternative Form ist mir auch nicht klar wie die ausgeschrieben werden würde.

Wie kann man diese verschachtelten Listen genau verstehen?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Solch ein Konstrukt kann man gar nicht verstehen. Es sagt nur "schaut wie cool ich bin, dass ich so viel in eine Zeile stopfen kann.
Also als erstes das sinnvoll umgebrochen:

Code: Alles auswählen

hot_work_days = [
    (hot_day['date'], hot_day['temperature'])
    for hot_day in [
        workday for workday in weekday_temperatures
        if workday['day'] not in ['Saturday', 'Sunday']
    ]
    if hot_day['temperature'] >= 30
]
Dann muß man die innere Liste herausnehmen, und den Variablen sinnvolle Namen geben.
Ein Datensatz mit day, date und temperature ist kein `workday`. Und auch kein `hot_day`. Da mir gerade kein wirklich sinnvoller Name für diese Kombination an Daten einfällt, nenne ich es einfach `entry`.

Code: Alles auswählen

workday_temperatures = [
    entry for entry in weekday_temperatures
    if entry['day'] not in ['Saturday', 'Sunday']
]

hot_work_day_temperatures = [
    (entry['date'], entry['temperature'])
    for entry in workday_temperatures
    if entry['temperature'] >= 30
]
Damit wird klar, dass wir die Inputdaten `weekday_temperatures` in zwei Schritten filtern.
Könnte man auch in einem Schritt machen:

Code: Alles auswählen

hot_work_day_temperatures = [
    (entry['date'], entry['temperature'])
    for entry in weekday_temperatures
    if entry['day'] not in ['Saturday', 'Sunday'] and entry['temperature'] >= 30
]
Zuletzt geändert von Sirius3 am Donnerstag 20. Januar 2022, 19:16, insgesamt 1-mal geändert.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Dein zweiter Code der ist für mich nachvollziehbar.
Heißt das, du nutzt keine list_comprehension?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@andie39,

(in der zwischenzeit hatte Sirius3 etwas ähnliches geschrieben, ich poste meine Antwort trotzdem mal)

ich denke nicht, dass ich eine bessere Erklärung finde als in der verlinkten Erklärung.
Der Hinweis die Listcomprehension umzuformatieren, so dass sie über mehrere Zeilen geht, ist schonmal sehr gut.

Code: Alles auswählen

hot_work_days1 = [
    (hot_day["date"], hot_day["temperature"])
    for hot_day in [workday for workday in weekday_temperatures if workday["day"] not in ["Saturday", "Sunday"]]
    if hot_day["temperature"] >= 30
]
In diesem Fall erkennt man aber, dass es eine innere Listcomprehension gibt, die erstmal eine Wochentage-Liste erstellt. Diese ist umschlossen von einer äußeren, die dann wieder über diese iteriert und alle ausgibt für die die Temperatur größer 30 ist.

Also etwas auseinandergezogen würde das so aussehen:

Code: Alles auswählen

workdays = [workday for workday in weekday_temperatures if workday["day"] not in ["Saturday", "Sunday"]
hot_work_days = [(hot_day["date"], hot_day["temperature"]) for hot_day in workdays]
Es ist aber eigentlich ein etwas spezieller Fall, da über eine einfache Liste aus Dictionaries iteriert wird. Eine verschachtelte Listcomprehension wäre nicht nötig um auf die Ergebnisse zu kommen.
Man kann einfach über die Ergebnisse iterieren und alle Tage mit ihren Temperaturwerten ausgeben für die gilt: Kein Samstag oder Sonntag *UND* Temperatur über 30

Code: Alles auswählen

hot_work_days2 = [
    (hot_day["date"], hot_day["temperature"])
    for hot_day in weekday_temperatures
    if hot_day["day"] not in ["Saturday", "Sunday"] and hot_day["temperature"] >= 30
]
Das ist ein kaum erkennbarer Unterschied zu oben.

Fazit: Selbst wenn man selbst versteht, was diese verschachtelte Listcomprehension tut, fällt es anderen sicher schwerer, da sie den Code nicht geschrieben haben.
Man sollte so etwas nicht tun und statt dessen eine einfache for-Schleife verwenden:

Code: Alles auswählen

hot_work_days = []
for day in weekday_temperatures:
    if day["day"] not in ["Saturday", "Sunday"] and day["temperature"] >= 30:
            hot_work_days.append((day["date"], day["temperature"]))
Wenn ich mich nicht vertan habe, machen alle Beispiele das gleiche, aber lesbarer ist meiner Meinung nach das letzte.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Danke. Also wird hier von euch eine listcomprehe sion selten genutzt?
Zumindest bei derart verschachtelten Liste /Dictonaries?

Ach ja.
Das hier ist ja ein Tulpel weches aus einen Dictionary generiert ist:

(entry["date"], entry["temperature"])
In den eckigen Klammern wird ja definiert was in die Tupel geschrieben wird. Es wird dort der Wert zum dem Schlüssel aus dem Dictionary eingefügt richtig?

Wenn man nun aber den Schlüssel selbst dort haben wollen würde.
Das macht hier keinen Sinn ich weiß, es geht mir nur um das Prinzip:
Was müsste man schreiben damit der Schlüssel ausgegeben wird?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

andie39 hat geschrieben: Donnerstag 20. Januar 2022, 20:49 Wenn man nun aber den Schlüssel selbst dort haben wollen würde.
Eigentlich braucht man das nur wenn man über ein Dictionary iterieren will. Dazu gibt es verschiedene Möglichkeiten.
Betrachten wir mal nur das Dictionary für den ersten Tag:

Code: Alles auswählen

first_day = weekday_temperatures[0]

# iterieren über die keys
for key in first_day:
    print(key)

"""
day
date
temperature
"""

# iterieren über die values
for value in first_day.values():
    print(value)

"""
Monday
2019-07-15
31
"""

# iterieren über beides
for key, value in first_day.items():
    print(f"{key:15}: {value}")

"""
day            : Monday
date           : 2019-07-15
temperature    : 31
"""
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Ahh ok.

Also ich muss sagen;
Das ist alles nicht ohne.

Da wird dann ein Dictionary zu einer Liste mit Tupeln…..

Nebenbei in der Eingangsfrage mit dem Link zur Aufgabe dort steht:

Angenommen wir haben einen Datensatz mit Temperaturen an verschiedenen Wochentagen. Die Liste besteht aus Tupeln (Wochentag, Datum, Temperarur). Wir möchten jetzt alle Arbeitstage finden, an denen über 30°C erreicht wurden, Wochenenden interessieren uns nicht.

weekday_temperatures = [
{'day': 'Monday', 'date': '2019-07-15', 'temperature': 31},
{'day': 'Tuesday', 'date': '2019-07-16', 'temperature': 33},

Aber das ist doch eine Liste von Dictionarys oder irre ich mich?
Tupel sind ()
Dictionary {}
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ja, gute gesehen. Da hat vielleicht jemand erst den Text geschrieben und sich dann später beim Programmieren gedacht, dass ein Dictionary besser wäre, dann aber vergessen den Text zu ändern.
Sowas kommt manchmal vor, wenn Kommentare im Code stehen, die keiner liest. Da wird dann aus irgendeinem Grund der Code geändert und die Kommentare ergeben Jahre später keinen Sinn mehr.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Ein Glück. Ich dachte schon ich wäre jetzt komplett daneben.

Also ich muss sagen:
Respekt vor jedem der so programmieren kann.
Das ist echt herausfordernd und viel.

Ich merke das ich immer wieder das entscheidende nicht sehe.

Gerade habe ich das Thema Klassen und Methoden durchgenommen.
Da war ich schon gespannt da mir immer wieder bei echten Code Beispielen das Class und self untergekommen ist.
Also etwad das wichtig ist, ich aber nicht kannte.

Jedenfalls gab es am Ende eine kleine Aufgabe nichts besonderes eigentlich aber ich kam nicht auf die Lösung.

Als ich dann die Lösung abgespielt hatte habe ich das schon verstanden. Aber zuvor…..wie ein Brett vor dem Kopf…..
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@andie39: Also ich benutze „comprehensions“ (gibt ja mehr als nur die für Listen) und Generatorausdrücke recht häufig. Auch mal verschachtelt. Eher nicht mehr als zwei Ebenen tief. Es muss einfach genug bleiben, dass man es noch verstehen kann, wo auch, wie man IMHO am Beispiel sehen kann, die Formatierung eine grosse Rolle spielt. Also Beispielsweise wenn man ein 2D-Feld mit True/False-Werten als Zeichenkette haben möchte mit "#" für True und "." für False, dann ist das hier IMHO vertretbar:

Code: Alles auswählen

    def __str__(self):
        return "\n".join(
            "".join("#" if cell else "." for cell in row) for row in self.rows
        )
Eine Möglichkeit solche Ausdrücke einfacher zu halten ist eventuell auch Teilausdrücke in sinnvoll benannte Funktionen heraus zu ziehen. Und/oder im konkreten Beispiel aus den Wörterbüchern Werte mit einem `collections.namedtupel`-Typ oder einer eigenen Klasse zu machen. Kommt halt auch so ein bisschen darauf an wo die Daten her kommen und wo sie hin sollen. Und in diesem Fall auch wie sehr man denen vertraut. Ist jetzt ein ganz anderes Thema, aber in den Wörterbüchern sind redundante Informationen drin. Da habe ich gleich mal den Reflex testen zu wollen ob "day" und "date" denn tatsächlich überall zusammen passen.

Code: Alles auswählen

#!/usr/bin/env python3
from datetime import datetime as DateTime
from pprint import pprint

from attr import attrib, attrs

DAYNAMES = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
]


@attrs(frozen=True)
class DayTemperature:
    date = attrib()
    temperature = attrib()

    @property
    def day_name(self):
        return DAYNAMES[self.date.isoweekday() - 1]

    def is_work_day(self):
        return self.date.isoweekday() < 6

    @classmethod
    def from_mapping(cls, mapping):
        result = cls(
            DateTime.strptime(mapping["date"], "%Y-%m-%d").date(),
            mapping["temperature"],
        )
        if result.day_name != mapping["day"]:
            raise ValueError(
                f"date is a {result.day_name},"
                f" mapping says it is a {mapping['day']}"
            )
        return result


def main():
    days = list(
        map(
            DayTemperature.from_mapping,
            [
                {"day": "Monday", "date": "2019-07-15", "temperature": 31},
                {"day": "Tuesday", "date": "2019-07-16", "temperature": 33},
                {"day": "Wednesday", "date": "2019-07-17", "temperature": 27},
                {"day": "Thursday", "date": "2019-07-18", "temperature": 25},
                {"day": "Friday", "date": "2019-07-19", "temperature": 30},
                {"day": "Saturday", "date": "2019-07-20", "temperature": 31},
                {"day": "Sunday", "date": "2019-07-21", "temperature": 29},
                {"day": "Monday", "date": "2019-07-22", "temperature": 25},
                {"day": "Tuesday", "date": "2019-07-23", "temperature": 31},
                {"day": "Wednesday", "date": "2019-07-24", "temperature": 26},
                {"day": "Thursday", "date": "2019-07-25", "temperature": 23},
                {"day": "Friday", "date": "2019-07-26", "temperature": 22},
                {"day": "Saturday", "date": "2019-07-27", "temperature": 23},
                {"day": "Sunday", "date": "2019-07-28", "temperature": 32},
            ],
        )
    )

    hot_work_days = [
        day for day in days if day.is_work_day() and day.temperature >= 30
    ]

    pprint(hot_work_days)


if __name__ == "__main__":
    main()
Subtile Falle: Tupel sind nicht ``()``, beziehungsweise sind die leeren Klammern tatsächlich das einzige Tupel das so entstehen muss (wenn man es literal schreibt). Man hat oft Klammern um es deutlicher zu machen oder weil es syntaktisch notwendig ist um Mehrdeutigkeiten zu vermeiden/aufzulösen, aber Tupel mit Werten entstehen durch Komma(s).
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Ich sag ja wirklich komplex und herausfordernd.
Ich habe mir auch nun gedacht das ich den Kurs erst einmal durchgehe und damit alles mal gesehen habe.

Feinheiten und Details lassen sich dann später ja auch wieder nachschlagen.

Ich hoffe mal das ist eine gute Idee.
Antworten