417 Stimmen

Zugriff auf Diktatschlüssel wie ein Attribut?

Ich finde es bequemer, auf die Diktatschlüssel als obj.foo anstelle von obj['foo'] also habe ich diesen Ausschnitt geschrieben:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

Ich nehme jedoch an, dass es einen Grund dafür geben muss, dass Python diese Funktionalität nicht von Haus aus bereitstellt. Was wären die Vorbehalte und Fallstricke beim Zugriff auf dict-Schlüssel auf diese Weise?

8voto

tallseth Punkte 3617

Es funktioniert nicht allgemein. Nicht alle gültigen Diktatschlüssel ergeben adressierbare Attribute ("der Schlüssel"). Sie müssen also vorsichtig sein.

Python-Objekte sind im Grunde genommen alle Wörterbücher. Ich bezweifle also, dass es viel Leistung oder andere Strafe ist.

8voto

gonz Punkte 4966

Dies geht zwar nicht auf die ursprüngliche Frage ein, sollte aber für Leute nützlich sein, die, wie ich, hier landen, wenn sie nach einer Lib suchen, die diese Funktionalität bietet.

Süchtig Es ist eine großartige Libelle für diesen Zweck: https://github.com/mewwts/addict Viele der in den vorangegangenen Antworten genannten Probleme werden dadurch ausgeräumt.

Ein Beispiel aus den Dokumentationen:

body = {
    'query': {
        'filtered': {
            'query': {
                'match': {'description': 'addictive'}
            },
            'filter': {
                'term': {'created_by': 'Mats'}
            }
        }
    }
}

Mit Süchtigen:

from addict import Dict
body = Dict()
body.query.filtered.query.match.description = 'addictive'
body.query.filtered.filter.term.created_by = 'Mats'

7voto

user2804865 Punkte 866

Nur um der Antwort etwas Abwechslung zu verleihen, sci-kit lernen hat dies als eine Bunch :

class Bunch(dict):                                                              
    """ Scikit Learn's container object                                         

    Dictionary-like object that exposes its keys as attributes.                 
    >>> b = Bunch(a=1, b=2)                                                     
    >>> b['b']                                                                  
    2                                                                           
    >>> b.b                                                                     
    2                                                                           
    >>> b.c = 6                                                                 
    >>> b['c']                                                                  
    6                                                                           
    """                                                                         

    def __init__(self, **kwargs):                                               
        super(Bunch, self).__init__(kwargs)                                     

    def __setattr__(self, key, value):                                          
        self[key] = value                                                       

    def __dir__(self):                                                          
        return self.keys()                                                      

    def __getattr__(self, key):                                                 
        try:                                                                    
            return self[key]                                                    
        except KeyError:                                                        
            raise AttributeError(key)                                           

    def __setstate__(self, state):                                              
        pass                       

Alles, was Sie brauchen, ist die setattr et getattr Methoden - die getattr prüft nach Diktatschlüsseln und geht dann zur Prüfung der tatsächlichen Attribute über. Die setstaet ist ein Fix für das Beizen/Entbeizen von "Trauben" - bei Interesse prüfen https://github.com/scikit-learn/scikit-learn/issues/6196

6voto

Ben Usman Punkte 7099

Hier ein kurzes Beispiel für unveränderliche Datensätze mit eingebauten collections.namedtuple :

def record(name, d):
    return namedtuple(name, d.keys())(**d)

und ein Anwendungsbeispiel:

rec = record('Model', {
    'train_op': train_op,
    'loss': loss,
})

print rec.loss(..)

6voto

hokage555 Punkte 63

Nachdem ich mit den vorhandenen Optionen aus den folgenden Gründen nicht zufrieden war, entwickelte ich MetaDict . Es verhält sich genau wie dict sondern ermöglicht die Punktnotation und IDE-Autovervollständigung ohne die Unzulänglichkeiten und potenziellen Namespace-Konflikte anderer Lösungen. Alle Funktionen und Anwendungsbeispiele können auf GitHub gefunden werden (siehe Link oben).

Vollständige Offenlegung: Ich bin der Autor von MetaDict .

Unzulänglichkeiten/Einschränkungen, auf die ich beim Ausprobieren anderer Lösungen gestoßen bin:

  • Süchtig
    • Keine automatische Tastenvervollständigung in der IDE
    • Verschachtelte Tastenbelegung kann nicht ausgeschaltet werden
    • Neu zugewiesen dict Objekte werden nicht so umgewandelt, dass sie den Schlüsselzugriff im Attributstil unterstützen
    • Eingebauter Schattentyp Dict
  • Prodikt
    • Keine automatische Schlüsselvervollständigung in der IDE ohne Definition eines statischen Schemas (ähnlich wie bei dataclass )
    • Keine rekursive Umwandlung von dict Objekte, wenn sie eingebettet sind in list oder andere eingebaute Iterabilien
  • AttrDict
    • Keine automatische Tastenvervollständigung in der IDE
    • Konvertiert list Objekte zu tuple hinter den Kulissen
  • Munch
    • Eingebaute Methoden wie items() , update() usw. können überschrieben werden mit obj.items = [1, 2, 3]
    • Keine rekursive Umwandlung von dict Objekte, wenn sie eingebettet sind in list oder andere eingebaute Iterabilien
  • EasyDict
    • Nur Strings sind gültige Schlüssel, aber dict akzeptiert alle hashfähigen Objekte als Schlüssel
    • Eingebaute Methoden wie items() , update() usw. können überschrieben werden mit obj.items = [1, 2, 3]
    • Eingebaute Methoden verhalten sich nicht wie erwartet: obj.pop('unknown_key', None) wirft ein AttributeError

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X