Anzahl bzw. vorhandensein von keys in Dictionary ermitteln

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.
Antworten
hirnwunde
User
Beiträge: 15
Registriert: Mittwoch 3. September 2014, 09:41

Hallo Leute,

mache ich das so richtig, um das Vorkommen eines keys in einem Dictionary zu ermitteln
oder funktioniert der Weg zwar ist aber nicht zu empfehlen?

Code: Alles auswählen

d_parities = {"none" : "PARITY_NONE",
              "even" : "PARITY_EVEN",
              "space" : "PARITY_SPACE",
              "mark" : "PARITY_MARK",
              "odd" : "PARITY_ODD"}

par = "noane"
par2 = "none"

if par in d_parities.keys():
    print "1ok"
else:
    print "1nok"

if par2 in d_parities.keys():
    print "2ok"
else:
    print "2nok"

Happy hacking!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Der Weg ist nicht zu empfehlen. Fuer den Test auf, ob ein Key enthalten ist, kannst du `keys` weglassen:

Code: Alles auswählen

if par in d_parities:
    ...
Und auch bei der Laenge, brauchst du nicht erst die Liste der Keys zu erzeugen:

Code: Alles auswählen

len(d_parities)
Nebenbei, wenn der `d_` Praefix dafuer stehen sollte, dass es ein Dictionary ist: Hungarian Notation ist in Python absolut unueblich und da der Typ am Objekt haengt und nicht am Namen, kann dieser "Hinweis" sogar falsch sein.
hirnwunde
User
Beiträge: 15
Registriert: Mittwoch 3. September 2014, 09:41

Ok.

Nachdem ich den Beitrag lass, habe ich mal noch ein wenig rumgespielt ...

Code: Alles auswählen

d_parities = {"none" : "PARITY_NONE",
              "even" : "PARITY_EVEN",
              "space" : "PARITY_SPACE",
              "mark" : "PARITY_MARK",
              "odd" : "PARITY_ODD",
              "key1" : "key1",
              "key2": "key3"}

par = "noane"
par2 = "key2"

print d_parities.__class__
print d_parities

if par2 in d_parities:
    print par2, "gefunden (ohne keys())"
else:
    print par2, "nicht gefunden (ohne keys())"
    
print "----------------------"

print d_parities.keys().__class__
print d_parities.keys()
if par2 in d_parities.keys():
    print par2, "gefunden (mit keys())"
else:
    print par2, "nicht gefunden (mit keys())"
ergibt:

Code: Alles auswählen

<type 'dict'>
{'even': 'PARITY_EVEN', 'none': 'PARITY_NONE', 'space': 'PARITY_SPACE', 'key2': 'key3', 'key1': 'key1', 'mark': 'PARITY_MARK', 'odd': 'PARITY_ODD'}
key3 nicht gefunden (ohne keys())
----------------------
<type 'list'>
['even', 'none', 'space', 'key2', 'key1', 'mark', 'odd']
key3 nicht gefunden (mit keys())
Das bedeutet also, dass ich mit keys() ein Abgleich auf eine Liste
(aus allen Keys des dicts) mache und ohne keys() ein Abgleich auf das komplette dict.

Nun haette ich erwartet, dass ich (bzw. Python) ohne .keys() dann auch die Werte der keys abfragt.
Das ist aber nicht der Fall.

Des weiteren fiel mir auf, dass sich die Reihenfolge der keys aendert.
Nicht das das interessieren wuerde, da das ja bei einem dict egal ist.
Komisch finde ich das dennoch, da ich da kein System hinter sehe.
(weder nach Zeichenlaenge des keys/value oder der Buchstabenposition im Alphabet)


Ja ... das "d_" am Anfang stand fuer mich als Hinweis auf ein Dictionary.
Wie kann ich es denn "ueblich" als dict kennzeichnen?
Oder sollte ich das im Namen generell unterlassen und lieber ein comment mit dem Hinweis darauf einfuegen?
Denn spaetestens nach 60 "Variablen" weiss ich nicht mehr, was fuer ein Typ die einzelnen haben.

Happy hacking!
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

hirnwunde hat geschrieben:Das bedeutet also, dass ich mit keys() ein Abgleich auf eine Liste
(aus allen Keys des dicts) mache und ohne keys() ein Abgleich auf das komplette dict.
Nein. Das bedeutet, dass du mit keys() zusätzlich den Overhead für die Listenerstellung und die lineare Suche hast, während ohne keys() der Schlüssel intern im Directory nur mit Laufzeit O(1) gesucht wird.
Zuletzt geändert von /me am Freitag 5. September 2014, 11:06, insgesamt 1-mal geändert.
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

Anstatt "__class__" könntest du auch "type()" verwenden.
Du frägst in beiden Fällen lediglich ab, ob sich der jeweilige Wert in der dict oder list befindet. Um den Wert des jeweiligen Eintrags zu bekommen musst du es etwas anders machen.

Code: Alles auswählen

Abfrage:
print(type(d_parities))
Überprüfung um welchen Dateityp es sich handelt:
if isinstance(d_parities, dict):
    print("It's a dict")

Keys:
print(d_parities.keys())

Values:
print(d_parities.values())

Ausgabe der Paare:
for i in d_parities.keys():
    print("{}: {}".format(i, d_parities[i]))

Key Suche:
par = "odd"
for i in d_parities.keys():
    if i == par:
        print("{}: {}".format(i, d_parities[i]))

Einfacher:
if par in d_parities.keys():
    print("{}: {}".format(par, d_parities[par]))
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

hirnwunde hat geschrieben:Oder sollte ich das im Namen generell unterlassen und lieber ein comment mit dem Hinweis darauf einfuegen?
Denn spaetestens nach 60 "Variablen" weiss ich nicht mehr, was fuer ein Typ die einzelnen haben.
Diese ungarische Notation aus der dann Namen wie lpszName resultierten, ist von ihrem Erfinder anders gedacht gewesen als sie dann perverserweise eingesetzt wurde. Abgesehen davon ist es auch nicht schön und resultiert in viel Änderungsaufwand wenn der Typ einer Variablen beispielsweise durch Refactoring geändert wird. Was für einen Präfix sollte man übrigens einem Parameter geben, der ein beliebiges Iterable akzeptiert?

Der Punkt ist ganz einfach. Wenn du so viele Variablen hast, dass du den Überblick verlierst, dann machst du etwas falsch. Strukturiere deine Programme besser. Verwende Funktionen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Dami123: Die Paare der Einträge erhältst du mit ``dict.items()``, den Umweg über den Schlüssel kannst du dir sparen.

Zeilen 19 bis 21 und Zeilen 24 und 25 machen nicht das selbe.
Das Leben ist wie ein Tennisball.
BlackJack

@hirnwunde: Das System hinter der Reihenfolge bei Wörterbucheinträgen wird letztlich durch die Implementierung der Hashtabelle erzeugt die als Datenstruktur intern verwendet wird. Und da wird naturgemäss möglichst gut ”vermischt” um eine möglichst gute Zugriffszeit auf einzelne Schlüssel zu erhalten, also im Regelfall O(1).

Generell ist bei Namen üblich zu beschreiben was der Wert dahinter *bedeutet* und nicht was für ein konkreter Typ es ist. Bei Containertypen wird in der Regel die Mehrzahl verwendet. Und bei Wörterbücher (und anderen Abbildungen) auch oft ein zusammengesetzter Name aus der Bedeutung der Schlüssel und der Werte, also zum Beispiel `typename2bitlength` für ein Wörterbuch welches so aussieht: ``{'byte': 8, 'word': 16, 'integer': 16, 'longword': 32, 'quadword': 64}``.

60 Variablen hat man nirgends auf einen Haufen, oder zumindest nur in ganz seltenen Ausnahmefällen. Da sollte man auf jeden Fall gründlich über Refaktorisierung nachdenken und beispielsweise einzelne Werte sinnvoll zu Datenstrukturen zusammenfassen.

Was mir bei der Auflistung der Möglichkeiten bei dem Beitrag von Dami123 noch fehlt ist `items()` um die Paare zu bekommen, das man auch einfach zugreifen kann ohne vorher zu prüfen und sich dann gegebenfalls um einen `KeyError` kümmern muss, und die `get()`-Methode. Und ab Zeile 9 in dem Quelltext ist jeder Aufruf von `keys()` unsinnig und sollte ersatzlos wegfallen.

Code: Alles auswählen

for key, value in a_dict.items():  # `iteritems()` in Python 2
    print('{0}: {1}'.format(key, value))

try:
    print('{0}: {1}'.format(key, a_dict[key]))
except KeyError:
    pass  # Intentionally ignored.
hirnwunde
User
Beiträge: 15
Registriert: Mittwoch 3. September 2014, 09:41

Danke fuer die ausfuerlichen Erlaeuterungen!


@/me
Gut. Ich gewoehne es mir wieder ab :)
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

EyDu hat geschrieben:@Dami123: Die Paare der Einträge erhältst du mit ``dict.items()``, den Umweg über den Schlüssel kannst du dir sparen.

Zeilen 19 bis 21 und Zeilen 24 und 25 machen nicht das selbe.
Stimmt.

Code: Alles auswählen

for key, value in d_parities.items():
    print("{}: {}".format(key, value))
Klar machen die nicht das selbe.
Antworten