Seite 1 von 1

Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 00:10
von mutetella

Code: Alles auswählen

s = 'a'
if s == 'a':
    print s
else:
    print 'b'
lässt sich ja seit Python 2.5 auch so notieren:

Code: Alles auswählen

print 'a' if s == 'a' else 'b'
Gibt es auch eine Möglichkeit,

Code: Alles auswählen

if s == 'a':
    print s
elif s == 'b':
    print 'b'
else:
    print 'c'
in gleicher Form zu schreiben? Die Documentation bzw. PEP 8 geben keine Auskunft darüber. Darum vermute ich, dass ich mit conditional expressions auf dem Holzweg bin. Vielleicht eher was mit 'or' bzw. 'and', aber irgendwie bin ich doch noch ein Anfänger... :(

mutetella

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 00:14
von mutetella
Oh Mann, sorry....

Code: Alles auswählen

print 'a' if s == 'a' else None or 'b' if s == 'b' else None or 'c' if s == 'c' else None
Oder geht's noch anderst?

mutetella

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 00:46
von BlackJack
@mutetella: Es geht auf jeden Fall mit "normalen" ``if``/``else`` *lesbar*. Ich verstehe den Ausdruck da jedenfalls nicht auf Anhieb weil ich mir erst einmal darüber klar werden müsste wo das per Default die Klammern stehen müssten.

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 01:01
von mutetella
@BlackJack:
Irgendwann und irgendwo hier im Forum wurde mir gesagt, dass 'return'-statements innerhalb von 'if'/'elif'/'else' nicht so schön seien. Und da ich in der Regel das tue, was man mir sagt :P , hab' ich eben versucht, das einzuhalten:

Code: Alles auswählen

    def date_is(self, date):
        return 'b' if self.is_base(date) else None or \
            'd' if self.is_duration(date) else None or \
            'r' if self.is_recurrence(date) else None
Ok, mein Beispiel war mit 'print'... sorry. Wie hältst Du das mit 'return'? Möglichst komplex oder auch mal verteilt über mehrere Abfragen?
Hmm..., zufällig bin ich gerade über

Simple is better than complex.
Complex is better than complicated.

aus dem 'Zen of Python' gestolpert. Passt in diesem Zusammenhang. Das sind halt auch immer so Sachen, die jeder ein wenig anderst sieht...

mutetella

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 02:00
von BlackJack
@mutetella: Das ist für mich einfach total unleserlich. Mittlerweile glaube ich zwar verstanden zu haben wie es funktioniert, bin mir aber nicht 100% sicher. Bei einem einfachen ``if``/``elif``/``else``-Konstrukt würde dagegen sogar ein Anfänger verstehen was da genau vorgeht.

Ich denke es sind implizite Klammern um die bedingten Ausdrücke und dadurch greift wegen der Semantik von ``or`` der Erste bei dem nicht `None` zurückgegeben wird. Was IMHO unsauber ist und auch fehleranfällig, weil man vor dem ``if`` nur "wahre" Ausdrücke stehen haben darf.

Ohne die ``or``\s könnte man das so schreiben:

Code: Alles auswählen

    def date_is(self, date):
        return 'b' if self.is_base(date) else (
            'd' if self.is_duration(date) else (
                'r' if self.is_recurrence(date) else None))
Aber wie gesagt, finde ich das verschachteln von bedingten Ausdrücken nur sehr bedingt lesbar. :-)

Ich würde vielleicht so etwas schreiben:

Code: Alles auswählen

    def date_is(self, date):
        for result, test_func in [('b', self.is_base),
                                  ('d', self.is_duration),
                                  ('r', self.is_recurrence)]:
            if test_func(date):
                return result
        return None
Ist IMHO einfacher zu lesen, einfacher erweiterbar, und erfüllt "flat is better than nested" aus dem Zen besser.

Aus OOP-Sicht könnte man sich auch fragen, ob so ein `date` nicht eventuell "seinen Buchstaben" kennen könnte.

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 09:33
von Xynon1
@BlackJack
Muss bei dir ja auch schon spät gewesen sein, ich erwähne nur mal ein Dictionary.
Und dann einfach "return dates.get(date, None)", oder liege ich da falsch?

Edit: Oha, ich hatte übersehen das du die Funktionen in deinem Beispiel schon rufst, aber hier mal ein Beispiel, wie ich mir das ungefähr vorstellen könnte:

Code: Alles auswählen

class Date(object):

    def __init__(self):
        self.dates = {"b" : self.is_base,
                      "d" : self.is_duration,
                      "r" : self.is_recurrence,
                      }

    def is_base(self):
        return 1

    def is_duration(self):
        return 2

    def is_recurrence(self):
        return 3

    def type_not_exist(self):
        raise TypeError("Dieser Datumstyp is unbekannt.")
    
    def date_is(self, date):
        return self.dates.get(date, self.type_not_exist)()


if __name__ == "__main__":
    d = Date()
    print(d.date_is("d"))
Natürlich müsste es bei den "is_"-Funktionen Booleans zurückgegeben werden, aber das soll das ganze nur deutlich machen.

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 10:27
von mutetella
BlackJack hat geschrieben:Aus OOP-Sicht könnte man sich auch fragen, ob so ein `date` nicht eventuell "seinen Buchstaben" kennen könnte.
Eben das möchte ich mit dieser Methode erreichen. 'date_is' ist eine Methode von Entry() und soll zurückgeben, um was es sich bei einem date innerhalb des entrys handelt. Dem Entry()-Exemplar ist ja lediglich sein Beginn, seine Dauer und ein eventuelles Recurrence()-Exemplar bekannt.
Ein date-Objekt, das unter anderem seine Position ('b', 'd' oder 'r') kennt, kann es IMHO so nicht geben, da zu einem Datum mehrere entries existieren können.
Um ein Datum darzustellen, habe ich eine DaySheet()-Klasse gemacht, deren Exemplare alle zu einem Datum gehörenden entries sammeln.
Aber wie immer ich das alles strukturiere... irgendwo muss die Position ermittelt werden. Ich dachte auch schon daran, den entries ein Attribut 'position' zu spendieren, das bei einer 'is_match'-Abfrage, die ja base, duration und recurrence untersucht, auf das jeweilige Ergebnis gesetzt wird. Hat halt den 'Haken', dass dieses Attribut erst nach einer 'is_match'-Abfrage verlässliche Informationen liefert. 'is_match' müsste also sowohl bei der Erstellung wie auch jeder Attributänderung aufgerufen werden. Nicht so schön, oder?
Xynon1 hat geschrieben:... hier mal ein Beispiel, wie ich mir das ungefähr vorstellen könnte
Letztlich das gleiche mit einem dict. Da kommt mir, bevor ich das Problem überhaupt abgeschlossen habe, schon gleich wieder die Frage in den Sinn: Welche von beiden Möglichkeiten wird wohl die Schnellere sein... :mrgreen:

mutetella


EDIT: Das mit dem 'position'-Argument ist totaler Schwachsinn... Dadurch hätte das Entry()-Exemplar eine Information, die sich lediglich auf die letzte durchgeführte 'is_match'-Abfrage bezieht. "Wo" sich ein Entry()-Exemplar befindet, kann das Entry aus genannten Gründen erstmal nicht wissen, außer es würde im voraus alle date's ermitteln, an denen es auftritt. Und das ist IMHO nicht praktikabel.

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 10:33
von BlackJack
@Xynon1: Das macht aber was anderes. Und was mir insgesamt nicht so gut gefällt bei allen Lösungen, ist das bei der API immer mehr `is_*()`-Methoden dazu kommen wenn mehr Typen dazukommen. Und bei Dir müsste man das alles auf dem `Date`-Basistyp machen. Also wenn ich einen neuen Typ hinzufügen will, müsste ich den Basistyp auch anfassen. Irgendwie unschön.

Und `is_*()`-Methoden sollten `True`/`False` zurückgeben und keine Zahlen oder sie sollten anders heissen.

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 10:40
von mutetella
BlackJack hat geschrieben:Das macht aber was anderes.
Warum?
BlackJack hat geschrieben:... oder sie sollten anders heissen.
'date_is' hätte es auch nicht länger als unbedingt nötigt überlebt. Ich tendiere zu 'position'.

mutetella

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 10:43
von Xynon1
@BlackJack
Das mit den Booleans hatte ich doch noch unten mit hingeschrieben.
Und :oops:, stimmt macht was anderes, ich dachte es ging darum mit einem Kürzel zu prüfen, ob es ein bestimmter Typ ist, du machst es ja genau anders herum. Bei dir wird ja der Kürzel zurückgegeben.

Edit: Lag natürlich an der verwirrenden Bezeichnung "date_is" :) , hieß ja nicht "get_datetype".

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Sonntag 6. Februar 2011, 11:25
von mutetella
Xynon1 hat geschrieben:... ich dachte es ging darum mit einem Kürzel zu prüfen, ob es ein bestimmter Typ ist, du machst es ja genau anders herum. Bei dir wird ja der Kürzel zurückgegeben.
Ok, versteh' ich jetzt auch. Fiel mir beim 'Überfliegen' gar nicht auf... :oops: Liegt auch am IMHO unglücklich gewählten 'date' als Argumentname... :wink:

Ok, ich werde dann mal BlackJacks Vorschlag übernehmen...

Vielen Dank an Euch...

mutetella

Re: Conditional expression um 3. Abfrage erweitern...?

Verfasst: Montag 7. Februar 2011, 05:59
von snafu
mutetella hat geschrieben:

Code: Alles auswählen

if s == 'a':
    print s
elif s == 'b':
    print 'b'
else:
    print 'c'
Daraus kann man als Conditional Expression sowas schreiben:

Code: Alles auswählen

print s if s in 'abc' else None
Oder ohne CE (weil hier unnötig):

Code: Alles auswählen

if s in 'abc': print s
Und mit Funktionen (ungetestet):

Code: Alles auswählen

DATE_STYLE_BASE, DATE_STYLE_DURATION, DATE_STYLE_RECURRENCE = range(3)

def get_date_style(self, date):
    style_checks = (self.is_base, self.is_duration, self.is_recurrence)
    for (style, style_check) in enumerate(style_checks):
        if style_check(date):
            return style
Letzteres hat den Nachteil, dass man auf die Reihenfolge der Checks achten muss, um die Werte nicht durcheinander zu bringen. Ich würde die Sachen ja einfach ausschreiben:

Code: Alles auswählen

DATE_STYLE_BASE, DATE_STYLE_DURATION, DATE_STYLE_RECURRENCE = range(3)

def get_date_style(self, date):
    if self.is_base(date):
        return DATE_STYLE_BASE
    elif self.is_duration(date):
        return DATE_STYLE_DURATION
    elif self.is_recurrence(date):
        return DATE_STYLE_RECURRENCE
    else:
        #return None
        raise ValueError('Unable to detect date style')
Da kann IMHO keiner sagen, dies sei unlesbar.