Forum: PC-Programmierung Python: Ist Element in Liste?


von Karlo (Gast)


Lesenswert?

Moin,

in Python kann man sehr einfach überprüfen ob ein gesuchtes Element sich 
in einer Liste befindet:
1
liste = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
2
if "Di" in liste:
3
    tuwas()

Das klappt soweit ich weiß aber nur mit "primitiven Datentypen" (falls 
die in Python auch so genannt werden).
Ich habe aber eine Liste die keine primitiven Typen beinhaltet sondern 
Klassen mit Attributen.
1
class Wochentag:
2
    name = "Mo"

Die C-like Lösung wäre, händisch über die Liste zu iterieren und bei 
Erfolg ein Flag zu setzen:
1
istInListe = False
2
for elem in liste:
3
    if elem.name = "Di":
4
        istInListe = True
5
        break
6
7
if istInListe:
8
    tuwas()

Ich bin mir aber sicher dass Python für sowas syntaktischen Zucker 
mitbringt.
Ich weiß nur grad nicht unter welchen Begriffen ich suchen soll.

Versteht ihr mein Anliegen?
Hat jemand eine schöne Lösung?

:
von wangnick (Gast)


Lesenswert?

Ich meine das geht wenn die Klasse Gleichheit definiert (_eq_).

LG, Sebastian

von Minimalist (Gast)


Lesenswert?

wangnick schrieb:
> Ich meine das geht wenn die Klasse Gleichheit definiert (eq).

Das schränkt aber ein, wenn andere Eigenschaften geprüft werden sollen.

Ich würde die naheliegende Lösung (Schleife) pythonisch als list 
comprehension formulieren

if "Di" in [x.name for x in liste]:

Allerdings kriegt man so kein handle auf das Element, nützt also nur, 
wenn man wirklich nur wissen will, ob das Element in der Liste vorkommt.

Ob das reicht weiß nur der TO.

von Karl (Gast)


Lesenswert?

Statt in eine Liste musst du deine Instanzen in einen Klasse packen und 
in der Klasse die Magic Methods _contains_ definieren.

class WochentagListe():
   ...
   def add(self,obj)
      self.list.add(obj)
   def  __contains__(self,val):
      for elem in self.liste:
         if elem.name = val:
            return True
      return False #bin mir nicht sicher ob das genau so geht

WochentagListe1 = WochentagListe()

if "Di" in WochentagListe1:
    tuwas()

https://stackoverflow.com/questions/1964934/what-does-contains-do-what-can-call-contains-function

von Minimalist (Gast)


Lesenswert?

Dann hat er Code, der umständlicher ist, und trotzdem die klassische von 
ihm erwähnte for Schleife hat.

Wenn es schnell auf Kosten von leserlich sein soll, dann eher noch ein 
map()

if any(map(lambda x: x.name=="Di",list)):

Wenn nicht zeitkritisch, bin ich immer noch für die List comprehension. 
Recht schnell, und gut verständlich.

P. S. :
Karl schrieb:
> for elem in self.liste:
>          if elem.name = val:

Der Vergleichsoperator ist ==

von MaWin (Gast)


Lesenswert?

Minimalist schrieb:
> if "Di" in [x.name for x in liste]:

Mit Generator statt list comprehension ist es schneller und braucht 
weniger RAM:

if "Di" in (x.name for x in liste):

von Minimalist (Gast)


Lesenswert?

> Mit Generator statt list comprehension ist es schneller und braucht
> weniger RAM:
>
> if "Di" in (x.name for x in liste):

Jup. Thx.

von Karl (Gast)


Lesenswert?

Minimalist schrieb:
> Dann hat er Code, der umständlicher ist, und trotzdem die klassische von
> ihm erwähnte for Schleife hat.

Kommt darauf an wie und wo man es braucht. Bei einem
1
import Wochenliste
2
3
...
4
5
if ... in Wochenliste:
6
   pass

ist das sicher übersichtlicher, als die Schleife.

Minimalist schrieb:
> Der Vergleichsoperator ist ==
Hast du fein gemacht.

MaWin schrieb:
> Mit Generator statt list comprehension ist es schneller

Ja aber mit der Klassenvariante geht es noch schneller:
1
import time
2
import string
3
import random
4
5
class Wochentag():
6
    def __init__(self,str):
7
        self.name = str
8
class Wochenliste():
9
    def __init__(self):
10
        self.liste=[]
11
    def Add(self,Tag):
12
        self.liste.append(Tag)
13
    def  __contains__(self,val):
14
        for elem in self.liste:
15
            if elem.name == val:
16
                return True
17
        return False
18
19
liste=[]
20
Wochenliste1 = Wochenliste()
21
source = string.ascii_letters + "1234567890"
22
for j in range(10000000):
23
    randstr = ""
24
    for i in range(3):
25
        randstr += random.choice(source)
26
    Tag = Wochentag(randstr)
27
    liste.append(Tag)
28
    Wochenliste1.Add(Tag)
29
30
start = time.time()
31
if "abc" in (x.name for x in liste):
32
    pass
33
mid1 = time.time()
34
if "abc" in [x.name for x in liste]:
35
    pass
36
mid2 = time.time()
37
if "abc" in Wochenliste1:
38
    pass
39
end = time.time()
40
41
print('{:6.4f}s'.format(mid1-start), end='  ')
42
print('{:6.4f}s'.format(mid2-mid1), end='  ')
43
print('{:6.4f}s'.format(end-mid2), end='  ')

Ausgabe: 0.0142s  0.7429s  0.0069s


Denkt mal drüber nach!

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Denkt mal drüber nach!

Ja gerne.

Generator vs. List comprehension: Laufzeitfaktor 1,9%
Klasse vs. List comprehension: Laufzeitfaktor 0,9%

Die Klasse ist deutlich aufwändiger und komplizierter zu verstehen.
Der Generator ist vom Aufwand praktisch kostenlos. Man muss nur zwei 
Klammern austauschen.
Jetzt muss man halt abwägen, ob dieser zusätzliche Vorteil es einem wert 
ist.

von Sven B. (scummos)


Lesenswert?

Fragliches Benchmark. Ich glaube nicht, dass das für Listen mit 
irgendeiner relevanten Anzahl an Elementen Bestand hat. Hast du das 
ausprobiert?

Wie lange es dauert, eine Liste mit 5 Elementen zu durchsuchen, 
interessiert eh keinen. Wenn sich diese Frage stellt, ist Python völlig 
die falsche Sprache.

von Karlo (Gast)


Lesenswert?

Moin, danke für die Rückmeldungen.
Ich muss das alles erst mal sacken lassen :-)

Die list-comprehension-Syntax gefällt mir.
Die kannte ich auch schon, leider mach ich nicht oft was mit Python 
weswegen ich solche Features immer wieder vergesse.

Leider habe ich nicht dran gedacht dass ich nach erfolgreicher Suche 
eine Referenz auf das Objekt brauche. Das kann die list-comprehension 
wohl nicht.
Also läufts wohl doch auf die c-Style-Schleife mit flag hinaus.
Wenn das gesuchte Objekt bereits in der Liste ist wird es zurückgegeben.
Wenn nicht wird es mittels append hinzugefügt und dann zurückgegeben.

Schön versteckt in einer Datenbank-Klasse.
Der User braucht sich also beim Zugriff nie drum kümmern ob es das 
Element bereits gibt, läuft alles im Hintergrund.

von MaWin (Gast)


Lesenswert?

Karlo schrieb:
> Leider habe ich nicht dran gedacht dass ich nach erfolgreicher Suche
> eine Referenz auf das Objekt brauche. Das kann die list-comprehension
> wohl nicht.

Doch, natürlich.
Hier eine Möglichkeit:

>>> liste = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
>>> selection = [x for x in liste if x == "Di"]
>>> if selection:
...     print(selection[0])
...
Di


Das geht natürlich auch mit anderen Objekten. If-Abfrage dann 
entsprechend anpassen, wie in den Beispielen vorher.

von Minimalist (Gast)


Lesenswert?

Ich habs mir fast gedacht, das das Objekt noch gebraucht wird.
Dann macht es schon Sinn, die  _eq_  Methode anzulegen, und wie oben 
erklärt vorzugehen. Ggf die vorhandene Klasse erweitern.
Da du ja scheinbar eine Liste ohne Duplikate haben möchtest, würde ich 
die Objekte dann aber in einem "set" speichern, und mit .add() 
hinzufügen. Dann kümmert sich python darum, es nur hinzuzufügen, wenn es 
noch nicht drin ist. Schau dir den Datentyp Set einfach mal an.

von MaWin (Gast)


Lesenswert?

Minimalist schrieb:
> würde ich die Objekte dann aber in einem "set" speichern

Dazu muss das Objekt aber immutable sein.
Geht auch mit eigenen Objekten, muss man aber beachten.

von MaWin (Gast)


Lesenswert?

MaWin schrieb:
> Dazu muss das Objekt aber immutable sein.

immutable und hashbar meinte ich

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Generator vs. List comprehension: Laufzeitfaktor 1,9%
> Klasse vs. List comprehension: Laufzeitfaktor 0,9%

Prozentrechnung ist nicht deine Stärke.

MaWin schrieb:
> Die Klasse ist deutlich aufwändiger und komplizierter zu verstehen.

Nur wenn man nicht OO denkt.

Sven B. schrieb:
> Fragliches Benchmark. Ich glaube nicht, dass das für Listen mit
> irgendeiner relevanten Anzahl an Elementen Bestand hat. Hast du das
> ausprobiert?

Ich habe nicht damit angefangen über Schnelligkeit zu faseln. Das war 
MaWin.
Zur Frage: Je kürzer die Liste, je gleicher die Laufzeit.

Wenn es um Leserlichkeit und Wiederverwendbarkeit geht sind die Magic 
Methods klar im Vorteil. Und das war die Ausgangsfrage.

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> MaWin schrieb:
>> Generator vs. List comprehension: Laufzeitfaktor 1,9%
>> Klasse vs. List comprehension: Laufzeitfaktor 0,9%
>
> Prozentrechnung ist nicht deine Stärke.

Ja dann. Was ist denn das richtige Ergebnis?

>>> 0.0142/0.7429*100
1.911428186835375
>>> 0.0069/0.7429*100
0.9287925696594427

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Wenn es um Leserlichkeit und Wiederverwendbarkeit geht sind die Magic
> Methods klar im Vorteil.

Nein sind sie nicht. Der generator ist trivial zu lesen. Es ist eine 
Zeile, die man praktisch wie einen Satz lesen kann.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Ja dann. Was ist denn das richtige Ergebnis?
>
>>>> 0.0142/0.7429*100
> 1.911428186835375

Also braucht man nur 1,9 % der ursprünglichen Laufzeit könnte sich also 
bei großen Sachen schon lohnen.

MaWin schrieb:
> Nein sind sie nicht. Der generator ist trivial zu lesen. Es ist eine
> Zeile, die man praktisch wie einen Satz lesen kann.

Nein

if ... in ...
ist deutlich besser zu lesen, als dein verschachteltes gefrickel.

von Michi (Gast)


Lesenswert?

Karl schrieb:
>> Generator vs. List comprehension: Laufzeitfaktor 1,9%
>> Klasse vs. List comprehension: Laufzeitfaktor 0,9%
>
> Prozentrechnung ist nicht deine Stärke.

Die Version mit der Klasse ist also doppelt so schnell!

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> if ... in ...
> ist deutlich besser zu lesen, als dein verschachteltes gefrickel.

Danke für die Bestätigung, dass der Generatorausdruck besser lesbar ist, 
als eine Klasse, die _contains_ implementiert. Hier nochmal der 
Generator:

> if "abc" in (x.name for x in liste):

von MaWin (Gast)


Lesenswert?

Michi schrieb:
> Karl schrieb:
>>> Generator vs. List comprehension: Laufzeitfaktor 1,9%
>>> Klasse vs. List comprehension: Laufzeitfaktor 0,9%
>>
>> Prozentrechnung ist nicht deine Stärke.
>
> Die Version mit der Klasse ist also doppelt so schnell!

Korrekt. Die Klasse ist doppelt so schnell, wie der Generator. Und der 
Generator hat nur zwei Prozent der Laufzeit der List comprehension.

Merkste selbst?
Nein?

Der Schritt von Comprehension -> Generator ist trivial (Klammern 
austauschen) und bringt bereits 98% des Geschwindigkeitsvorteils.
Die komplizierte Klassenlösung bringt einen weiteren Prozentpunkt.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Karl schrieb:
>> if ... in ...
>> ist deutlich besser zu lesen, als dein verschachteltes gefrickel.
>
> Danke für die Bestätigung, dass der Generatorausdruck besser lesbar ist,
> als eine Klasse, die contains implementiert. Hier nochmal der
> Generator:
>
>> if "abc" in (x.name for x in liste):

Oh da habe ich wohl zuweit abstrahiert.

if Objekt in ListOfObject:

vs

if Gefrickel in (x.name for x in listeOfGefrickel):

Ist es jetzt klarer?

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Ist es jetzt klarer?

Nein. Du blendest weiterhin das zu implementierende und zu verstehende 
__contains__-Protokoll aus.
Troll.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Die komplizierte Klassenlösung bringt einen weiteren Prozentpunkt.

Nein, bringt 100% Geschwindigkeitszuwachs (Verdoppelung).

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Nein, bringt 100% Geschwindigkeitszuwachs (Verdoppelung).

Richtig. Im Vergleich mit der Lösung, die bereits nur noch 2% der 
ursprünglichen Laufzeit benötigt.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Nein. Du blendest weiterhin das zu implementierende und zu verstehende
> __contains__-Protokoll aus.

1. ist die __contains__-Method für jeden Depp zu verstehen, im Gegensatz 
zu deinem Generator
2. Spätestens wenn man es mehrmals braucht, spart es Zeichen.
3. Ist meine Lösung Python-Style und deine C-Style.
4. Es wurde nach einer Phyton-Style-Lösung gefragt.

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> 3. Ist meine Lösung Python-Style und deine C-Style.

>Generator ist C-Style.

Na jetzt hast du mich aber getrollt.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Richtig. Im Vergleich mit der Lösung, die bereits nur noch 2% der
> ursprünglichen Laufzeit benötigt.

Soll das ein Argument sein?
Weil Eine Glühbirne nur 2 % der Energie eines Feuers braucht, kann man 
auf LEDs verzichten!

von Karl (Gast)


Lesenswert?

MaWin schrieb:
>>Generator ist C-Style.
>
> Na jetzt hast du mich aber getrollt.

Nicht der Generator sondern dein verschachteltes Aneinanderreihen von 
"Funktionen" ist C-Style. Verstehst du überhaupt was die Leute von dir 
wollen?

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Verstehst du überhaupt was die Leute von dir wollen?

Nö. Ich weiß beim besten Willen nicht, was du von mir willst.

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Soll das ein Argument sein?

Ja.

> Weil Eine Glühbirne nur 2 % der Energie eines Feuers braucht, kann man
> auf LEDs verzichten!

Warum sollte eine Glühbirne nur 2% der Energie eines Feuers brauchen?
Die Glühbirne verbraucht ziemlich sicher mehr Energie, für die gleiche 
Helligkeit, wie ein Feuer. Vor allem wegen der Umwandlungsverluste von 
der Primärenergiequelle zum Licht.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Nö. Ich weiß beim besten Willen nicht, was du von mir willst.

Ich dachte das war ironisch.

MaWin schrieb:
> Warum sollte eine Glühbirne nur 2%

Das beweißt das Gegenteil. Ich bin raus.

von Anfänger (Gast)


Lesenswert?

Karlo schrieb:
> "primitiven Datentypen"

Was sind denn für dich primitive Datentypen? In Python gibt es doch 
nicht speziell Datentypendeklarationen wie z.B. in C.

von MaWin (Gast)


Lesenswert?

Anfänger schrieb:
> In Python gibt es doch
> nicht speziell Datentypendeklarationen wie z.B. in C.

Trotzdem ist Python streng typisiert und jedes Objekt hat einen 
eindeutigen Typ.

Was in Python primitive Typen sein sollen, ist mir allerdings auch nicht 
ganz klar.

von mh (Gast)


Lesenswert?

Karl schrieb:
> if Objekt in ListOfObject:

Ich erwarte als Leser an dieser Stelle, dass ListOfObject eine echte 
Liste ist.

von Anfänger (Gast)


Lesenswert?

MaWin schrieb:
> Trotzdem ist Python streng typisiert und jedes Objekt hat einen
> eindeutigen Typ.

Aber ich habe bisher immer gedacht, dass das der Interpreter 
entscheidet, welchen Datentyp er dann nimmt. Bei einem Text würde ich 
einen String nehmen und bei einer 100 ein Integer, bei einer 0,443 vlt 
ein double-Datentyp. Also ich habe in Python bisher noch nie speziell 
einen Datentypen hergestellt wie z.B. in C:

int i; double k;

Und wenn das geht, wüsste ich garnicht, wie die genauen Befehle dazu 
heißen.

von Karl (Gast)


Lesenswert?

mh schrieb:
> Ich erwarte als Leser an dieser Stelle, dass ListOfObject eine echte
> Liste ist.

Was soll eine "echte Liste" sein? Und warum erwartest du das?

von MaWin (Gast)


Lesenswert?

Anfänger schrieb:
> Aber ich habe bisher immer gedacht, dass das der Interpreter
> entscheidet, welchen Datentyp er dann nimmt.

Der Programmierer entscheidet, welchen Datentyp ein Objekt hat.

a = 1 # int
b = 1.0 # float
c = "foo" # str
d = Bar() # Bar

von Anfänger (Gast)


Lesenswert?

MaWin schrieb:
> d = Bar() # Bar

was ist denn "Bar" für ein Datentyp

MaWin schrieb:
> "foo"

Ist mit "foo" einfach nur ein Text gemeint oder hat "foo" auch eine 
Bedeutung?

von MaWin (Gast)


Lesenswert?

Anfänger schrieb:
> was ist denn "Bar" für ein Datentyp

Ein selbstdefinierter. z.B.

class Bar(object): pass

von MaWin (Gast)


Lesenswert?

Anfänger schrieb:
> Ist mit "foo" einfach nur ein Text gemeint oder hat "foo" auch eine
> Bedeutung?

Es ist ein Beispieltext.

von Karl (Gast)


Lesenswert?

Anfänger schrieb:
> int i; double k;
>
> Und wenn das geht, wüsste ich garnicht, wie die genauen Befehle dazu
> heißen.

Das macht Python für dich:

i = 5 -> Python legt für dich eine Instanz der Klasse Integer mit dem 
Wert 5 an.

i = 5.0 -> Python legt für dich eine Instanz der Klasse Float mit dem 
Wert 5 an.

https://docs.python.org/3/library/stdtypes.html

von mh (Gast)


Lesenswert?

Karl schrieb:
> mh schrieb:
>> Ich erwarte als Leser an dieser Stelle, dass ListOfObject eine echte
>> Liste ist.
>
> Was soll eine "echte Liste" sein?

Halt eine built-in list:
https://docs.python.org/3/library/stdtypes.html#lists

Und nicht etwas, das nur auf den ersten Blick wie eine Liste aussieht.

Karl schrieb:
> Und warum erwartest du das?

Weil es im Namen steht.

von MaWin (Gast)


Lesenswert?

mh schrieb:
> Karl schrieb:
>> Und warum erwartest du das?
>
> Weil es im Namen steht.

Ja genau das ist auch mein Problem mit diesem Ansatz. Die Klasse 
implementiert einen klitzekleinen Teil des Protokolls einer list-Klasse. 
Wenn man das macht, sollte man das wenigstens im Namen deutlich machen, 
dass es eben keine Liste im herkömmlichen Sinne ist. Es sei denn, die 
Klasse implementiert wirklich das komplette list-Protokoll oder ist von 
list abgeleitet.

von Karl (Gast)


Lesenswert?

mh schrieb:
> Und nicht etwas, das nur auf den ersten Blick wie eine Liste aussieht.

Wenn du es brauchst, kannst du auch mit Vererbung deine Klasse aus der 
Originalklasse ableiten.

mh schrieb:
> Weil es im Namen steht.

if Objekt in MyDefListOfObject:

So besser? Du solltest halt schon wissen, was es für eine Liste ist und 
was in der Liste ist. Weil

if "Di" in [x.name for x in liste]:

funktioniert auch nur wenn x.name
type(x.name) == str

Irgendwo muss man halt mal denken.

von mh (Gast)


Lesenswert?

MaWin schrieb:
> Es sei denn, die
> Klasse implementiert wirklich das komplette list-Protokoll oder ist von
> list abgeleitet.

Dass nur ein Teil implementiert wird ist weniger das Problem. Es ist das 
andere Verhalten der implementierten Teile. Immerhin ist es so 
"einfach", dass es einem direkt um die Ohren fliegt, sollte man etwas 
"falsch" machen.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
> Es sei denn, die
> Klasse implementiert wirklich das komplette list-Protokoll oder ist von
> list abgeleitet.

Du stellst dich manchmal wirklich blöder an, als du bist, nur um recht 
zu haben. Hier zeigst du, dass du genau weißt wie es geht.

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Weil
>
> if "Di" in [x.name for x in liste]:
>
> funktioniert auch nur wenn x.name
> type(x.name) == str

Nö, falsch.
Die beteiligten Typen müssen nur das __eq__-Protokoll so implementieren, 
dass der exakte Typ keine Rolle spielt. Das ist best practice.

von Karl (Gast)


Lesenswert?

mh schrieb:
> dass es einem direkt um die Ohren fliegt, sollte man etwas
> "falsch" machen.

Was soll man sich da vorstellen? Wir reden Hier über ein paar 
Codeschnipsel, nicht über eine hoch professionelle Implementierung.
Kannst du mal Beispiele liefern, was einem um die Ohren fliegen soll? 
Belegen, dass es mit:
if "Di" in [x.name for x in liste]
einem nicht um die Ohren fliegen kann? Nach deiner Auffassung müsste 
dann x ein Float sein, dass es einem nicht um die Ohren fliegt, weil x 
ist ja eine Zahl?
Der normale Mensch denkt halt nach was x ist und genauso kann man drüber 
nachdenken, was MyDefListOfObject ist.

von mh (Gast)


Lesenswert?

Karl schrieb:
> Wenn du es brauchst, kannst du auch mit Vererbung deine Klasse aus der
> Originalklasse ableiten.

Das macht es nicht besser. Mit der _contains_ Methode ist es einfach 
keine Liste mehr.

> mh schrieb:
>> Weil es im Namen steht.
>
> if Objekt in MyDefListOfObject:
>
> So besser?

Ernsthaft?

Karl schrieb:
> Du solltest halt schon wissen, was es für eine Liste ist und
> was in der Liste ist.

Dafür ist der Name da. Wenn wir eh immer wissen was der Typ und Wert 
ist, können wir alles a0, a1, a2, ... nennen.

Karl schrieb:
> if "Di" in [x.name for x in liste]:
>
> funktioniert auch nur wenn x.name
> type(x.name) == str
Nein! Bedingung ist, dass x.name existiert.

Karl schrieb:
> Irgendwo muss man halt mal denken.

Besser beim Namen auswählen etwas mehr denken, als beim Lesen der Namen.

von Karl (Gast)


Lesenswert?

MaWin schrieb:
>> funktioniert auch nur wenn x.name
>> type(x.name) == str
>
> Nö, falsch.
> Die beteiligten Typen müssen nur das __eq__-Protokoll so implementieren,
> dass der exakte Typ keine Rolle spielt. Das ist best practice.

funktioniert war hier im Sinne von "erfüllt seine angedachte Funktion" 
gemein, nicht im Sinne von "liefert keine Fehlermeldung".

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> funktioniert war hier im Sinne von "erfüllt seine angedachte Funktion"
> gemein

Warum sollte es das nicht tun, wenn name ein von mir definierter Typ 
ist, der vergleichbar mit str ist?

von Karl (Gast)


Lesenswert?

mh schrieb:
> Nein! Bedingung ist, dass x.name existiert.
>

Und wo wird das bei euch sichergestellt? Oh dein Beispiel wird bestimmt 
explodieren.

> Karl schrieb:
>> Irgendwo muss man halt mal denken.
>
> Besser beim Namen auswählen etwas mehr denken, als beim Lesen der Namen.

mh schrieb:
>> if Objekt in MyDefListOfObject:
>>
>> So besser?
>
> Ernsthaft?

Ja!

Wie würdest du es machen?

von Karl (Gast)


Lesenswert?

Karl schrieb:
>>> funktioniert auch nur wenn x.name
>>> type(x.name) == str


MaWin schrieb:
> Warum sollte es das nicht tun, wenn name ein von mir definierter Typ
> ist, der vergleichbar mit str ist?

Du definierst doch gar keinen Typ selbst, weil das nicht übersichtlich 
ist. War das nicht vor 10 Posts deine Aussage? Oder du definierst 
eingene Klasse nicht wenn du nur so recht hast und du definierst eigene 
Klassen, wenn nur nur so recht hast. Du verdrehst absichtlich die 
Aussagen anderer, nur um recht zu haben. Bist du damit zufrieden 
(rhetorische Frage):

type(x.name) like str

von mh (Gast)


Lesenswert?

Karl schrieb:
> Wie würdest du es machen?

Was genau?

-Einen alternativen Namen für dein ListOfObject auswählen? Kann ich 
nicht. Und das zeigt mir, dass es eine schlechte Idee ist, es so zu 
lösen.

-Das ursprüngliche Problem lösen? Dafür bräuchte man eine bessere 
Beschreibung des Problems. Vermutlich mit
1
for wochentag in filter(lambda x: x.name == 'Mo', wochentagListe):
2
    tuwas(wochentag)
oder ähnlich.

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> Du definierst doch gar keinen Typ selbst, weil das nicht übersichtlich
> ist.

Ach bitte. Was ist das denn jetzt für ein Kinderkram. Hab ich dir den 
Lolli weggenommen?

von MaWin (Gast)


Lesenswert?

mh schrieb:
> for wochentag in filter(lambda x: x.name == 'Mo', wochentagListe):
>     tuwas(wochentag)

filter und map kann man so gut wie immer durch comprehension/generator 
ersetzen.
1
for wochentag in (for x in wochentagListe if x.name == 'Mo'):
2
    tuwas(wochentag)

In diesem speziellen Fall ist aber sicher die triviale Variante besser:
1
for x in wochentagListe:
2
    if x.name == 'Mo':
3
        tuwas(wochentag)

von Minimalist (Gast)


Lesenswert?

MaWin schrieb:
> In diesem speziellen Fall ist aber sicher die triviale Variante besser:
> for x in wochentagListe:
>     if x.name == 'Mo':
>         tuwas(wochentag)

Full Ack!
Einfach, verständlich, und sehr wahrscheinlich spielt Tempo hier eh 
keine Rolle. Wenn doch wird sich das dann rausstellen.
premature optimization is the root of all evil

von mh (Gast)


Lesenswert?

MaWin schrieb:
> filter und map kann man so gut wie immer durch comprehension/generator
> ersetzen.

Klar kann man das.

MaWin schrieb:
> In diesem speziellen Fall ist aber sicher die triviale Variante besser:

Da müssen wir zum Glück nicht einer Meinung sein.

von Karl (Gast)


Lesenswert?

mh schrieb:
> -Einen alternativen Namen für dein ListOfObject auswählen? Kann ich
> nicht. Und das zeigt mir, dass es eine schlechte Idee ist, es so zu
> lösen.

Du hält also eine objektorientierten Lösung für eine schlechte Idee, 
weil bei Python ein stdtype list definiert ist und du keinen 
Variablennamen findest, der nicht Liste enthält? Eigenwillige Logik.

mh schrieb:
> -Das ursprüngliche Problem lösen? Dafür bräuchte man eine bessere
> Beschreibung des Problems. Vermutlich mit
> for wochentag in filter(lambda
> x: x.name == 'Mo', wochentagListe):
>     tuwas(wochentag)
> oder ähnlich.

Das ursprüngliche Problem war bereits gelöst. Der TO hat nach
Python-Stylischen Lösung mit "syntaktischem Zucker" gesucht und du 
präsentierst eine dreifach verschachtelte Lösung mit einer 
Lambdafunktion. Respekt!
https://treyhunner.com/2018/09/stop-writing-lambda-expressions/

von MaWin (Gast)


Lesenswert?

Karl schrieb:
> und du
> präsentierst eine dreifach verschachtelte Lösung mit einer
> Lambdafunktion.

Ich weiß nicht, was das überhaupt für ein Argument sein soll.
Das ist nicht mehr oder weniger verschachtelt, als deine 
__contains__-Methode. Die wird auch verschachtelt aufgerufen, vom 
in-Operator. Mit dem Nachteil, dass das eben nicht offensichtlich ist.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

M.E. wäre die beste Lösung Wochentag als Enum zu definieren, dann ist es 
Hashable und man kann „in“ verwenden. Aber bei solchen künstlichen 
Problemen macht es wirklich wenig Sinn sich über Details die Köpfe 
einzuschlagen, im realen Leben gibt es wohl für jede der hier 
vorgeschlagenen Lösungen Situationen in denen sie angebracht sind.

Beitrag #6248410 wurde von einem Moderator gelöscht.
Beitrag #6248417 wurde von einem Moderator gelöscht.
von Sheeva P. (sheevaplug)


Lesenswert?

Karlo schrieb:
> Hat jemand eine schöne Lösung?

pydoc filter

;-)

von Sheeva P. (sheevaplug)


Lesenswert?

Karl schrieb:
> Ja aber mit der Klassenvariante geht es noch schneller:
> [...]
> Denkt mal drüber nach!

Also ich habe jetzt mal sehr intensiv darüber nachgedacht. Dabei bin ich 
leider zu einigen Ergebnissen gekommen, die Dich vermutlich nicht 
erfreuen werden...

1. "Premature Optimization is the root of all evil." (Donald E. Knuth)

Das ist der erste Hauptsatz der Performanceoptimierung. Die Aussage ist: 
winzige Teilaspekte eines Programms zu optimieren, ist total bescheuert. 
Es kommt darauf an, das gesamte Programm mit den gesamten Realdaten zu 
betrachten. Erst dann kann man irgendeine seriöse und valide Aussage 
über dessen Performance treffen und dieselbe exakt an den Stellen 
optimieren, wo es hakt. Alles andere macht den Code höchstens 
komplizierter, und ob er auf einer Liste mit 5 Millionen Einträgen 
ähnlich performt wie auf einer mit 50 Einträgen, ist... fraglich, 
vorsichtig gesagt. (Die Aussage ist von 1973 und heute nicht weniger 
wahr oder wichtig...)


2. "Measure, don't guess." (Kirk Pepperdine)

Dieser zweite Hauptsatz der Performanceoptimierung sagt, daß es völlig 
sinnlos ist, irgendetwas optimieren zu wollen, daß man nicht unter 
realen Bedingungen gemessen hat. Am Ende sind nämlich Deine Annahmen 
falsch und Du investierst Deine Arbeit in einen Teil Deines Code, der 
0.001 Prozent seiner Laufzeit ausmacht, anstatt daß Du Dich auf jenen 
Teil Deines Code konzentrierst, der 90% Deiner Laufzeit kostet.


3. "Make it work, make it right, make it fast." (Kent Beck)

Dies ist ein eher grundsätzliches Prinzip abseits der 
Performanceoptimierung, aber es spielt im Zusammenhand mit den 
vorherigen Sätzen eine wichtige Rolle. Wir werden daran erinnert, daß 
Software erst einmal laufen muß, dann korrekt laufen (also das Richtige 
(tm) tun muß), bevor man sich daran geben kann, sie schnell zu machen... 
mithin: ihre Performance zu optimieren.


Nach diesen Grundsätzen sind da aber dann auch noch die Python-Dinge...

Also, zunächst folgt Python dem Grundsatz "batteries included". Das 
heißt, es gibt einen riesigen Haufen von Modulen. Wenn es etwa um 
Wochentage geht, bieten sich das Standardmodul "datetime" und die 
Erweiterung "dateutils" an. Mit "localization" und 
"internationalization" ("l10n" und "i18n") gibt es fertige Module für 
genau dieses: Wochentage mit Abkürzungen und solches neisse Zeugs. Wenn 
es nicht nur um dieses winzige Array (besser wäre ein Tupel, nebenbei) 
mit den Wochentagen geht, sondern größere Arrays iteriert werden müssen, 
gibt es für Python ein paar Erweiterungen, welche sowas wunderbar 
parallelisieren können, nämlich numpy, scipy und pandas.

Ach ja, lieber TO: IMHO gehört solch ein Datenarray, bei dem die Daten 
sich nicht wiederholen (können), nicht in eine list() und nichtmal in 
ein tuple(), sondern in ein set(). Ich kenne Deine Daten aber nicht, 
daher: YMMV. ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

Anfänger schrieb:
> MaWin schrieb:
>> Trotzdem ist Python streng typisiert und jedes Objekt hat einen
>> eindeutigen Typ.
>
> Aber ich habe bisher immer gedacht, dass das der Interpreter
> entscheidet, welchen Datentyp er dann nimmt. Bei einem Text würde ich
> einen String nehmen und bei einer 100 ein Integer, bei einer 0,443 vlt
> ein double-Datentyp. Also ich habe in Python bisher noch nie speziell
> einen Datentypen hergestellt wie z.B. in C:
>
> int i; double k;
>
> Und wenn das geht, wüsste ich garnicht, wie die genauen Befehle dazu
> heißen.

Najaaaa... Python ist tatsächlich streng, aber dynamisch typisiert, weil 
der Typ an den Wert gebunden ist, anstatt an den Variablennamen. Du 
kannst ein und derselben Variablen daher unterschiedliche Werte zuweisen 
(das ist jetzt nicht überraschend), aber diese Werte können auch 
unterschiedliche Typen haben:
1
a = 5   # int
2
a = '5' # str

ist daher vollkommen zulässig. Ein Sonderfall ist "'5' * 5": in Python 
kommt dann '55555' heraus, statt -- wie zum Beispiel in PHP -- 25.

von Sheeva P. (sheevaplug)


Lesenswert?

Anfänger schrieb:
> MaWin schrieb:
>> d = Bar() # Bar
>
> was ist denn "Bar" für ein Datentyp

Eine Instanz der Klasse "Bar".

von Sheeva P. (sheevaplug)


Lesenswert?

MaWin schrieb:
> mh schrieb:
>> Karl schrieb:
>>> Und warum erwartest du das?
>> Weil es im Namen steht.
>
> Ja genau das ist auch mein Problem mit diesem Ansatz. Die Klasse
> implementiert einen klitzekleinen Teil des Protokolls einer list-Klasse.
> Wenn man das macht, sollte man das wenigstens im Namen deutlich machen,
> dass es eben keine Liste im herkömmlichen Sinne ist. Es sei denn, die
> Klasse implementiert wirklich das komplette list-Protokoll oder ist von
> list abgeleitet.

Bitte entschuldigt, aber Ihr seid viel zu sehr von Datentypen 
beherrscht. Eine Liste in Python ist eine Liste, also etwas, das die 
ganze List-API (List-Protokoll) kann.

Aber: es gibt viele andere Objekte, die einen Teil der List-API 
implementieren, ohne tatsächlich eine Liste zu sein. Um das zu 
realisieren, besitzt Python sogar eigene Subprotokolle, im Falle einer 
(iterierbaren) Liste zum Beispiel iterable. iterable kann aber auch von 
anderen Objekten implementiert werden, zum Beispiel von solchen, welche 
die Builtin-Datentypen tuple() oder set() implemtentieren.

von Sheeva P. (sheevaplug)


Lesenswert?

Andreas S. schrieb:
> M.E. wäre die beste Lösung Wochentag als Enum zu definieren, [...]

Absolut korrekt, wenn es (nur) um Wochentage geht... ;-)

von Sebastian W. (wangnick)


Lesenswert?

Karlo schrieb:
> in Python kann man sehr einfach überprüfen ob ein gesuchtes Element sich
> in einer Liste befindet:
>
>
1
> liste = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
2
> if "Di" in liste:
3
>     tuwas()
4
>
>
> Das klappt soweit ich weiß aber nur mit "primitiven Datentypen" (falls
> die in Python auch so genannt werden).
> Ich habe aber eine Liste die keine primitiven Typen beinhaltet sondern
> Klassen mit Attributen.
>
>
1
> class Wochentag:
2
>     name = "Mo"
3
>
>
> ...
>
> Ich bin mir aber sicher dass Python für sowas syntaktischen Zucker
> mitbringt.
> Ich weiß nur grad nicht unter welchen Begriffen ich suchen soll.
>
> Versteht ihr mein Anliegen?
> Hat jemand eine schöne Lösung?

wangnick schrieb:
> Ich meine das geht wenn die Klasse Gleichheit definiert (__eq__).

Ok, language reference 6.10.2, Membership test operations: "For 
container types such as list, tuple, set, frozenset, dict, or 
collections.deque, the expression x in y is equivalent to any(x is e or 
x == e for e in y)."

Also geht folgendes:
1
class Wochentag:
2
    def __init__ (self,name):
3
        self.name = name
4
    def __eq__ (self,other):
5
        return type(other)==type(self) and self.name==other.name
6
7
mo = Wochentag("Mo")
8
di = Wochentag("Di")
9
mi = Wochentag("Mi")
10
11
li = (mo,mo,di,1.0,"")
12
print(di in li)
13
print(mi in li)

Für das simple Beispiel der Wochentage wäre Enum tatsächlich besser 
geeignet. Da diese Singletons sind, werden sie bei x in y durch den 
is-operator gefunden.

LG, Sebastian

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.