481 Stimmen

Wie verwende ich einen Punkt "." um auf Elemente eines Wörterbuchs zuzugreifen?

Wie mache ich Python-Wörterbuchmitglieder über einen Punkt "." zugänglich?

Zum Beispiel würde ich gerne statt mydict['val'] mydict.val schreiben.

Außerdem würde ich gerne auf verschachtelte Wörterbücher auf diese Weise zugreifen. Zum Beispiel

mydict.mydict2.val 

würde sich auf

mydict = { 'mydict2': { 'val': ... } }

32 Stimmen

Viele der Situationen, in denen Menschen verschachtelte Dicts verwenden, könnten genauso gut oder sogar besser durch Dicts mit Tupeln als Schlüssel gelöst werden, wobei d[a][b][c] durch d[a, b, c] ersetzt wird.

0 Stimmen

Können Sie bitte näher erläutern, wie d[a][b][c] durch d[a, b, c] ersetzt werden kann? Ich habe noch nicht verstanden, wie das gemacht werden kann.

9 Stimmen

Es ist kein Zauberei: foo={}; foo[1,2,3] = "one, two, three!"; foo.keys() => [(1,2,3)]

0voto

Daniel Punkte 7078

Wenn Sie bereits Pandas verwenden, können Sie eine Pandas-Serie oder ein DataFrame erstellen, auf die Sie über die Punkt-Syntax zugreifen können:

1-Ebene Wörterbuch:

import pandas as pd

my_dictionary = pd.Series({
  'key1': 'value1',
  'key2': 'value2'
})

print(my_dictionary.key1)
# Output: value1

2-Ebenen Wörterbuch:

import pandas as pd

my_dictionary = pd.DataFrame({
  'key1': {
    'inner_key1': 'value1'
  },
  'key2': {
    'inner_key2': 'value2'
  }
})

print(my_dictionary.key1.inner_key1)
# Output: value1

Beachten Sie, dass dies wahrscheinlich besser mit einer normalisierten Datenstruktur funktioniert (bei der jeder Wörterbucheintrag die gleiche Struktur hat). Im obigen zweiten Beispiel ist das resultierende DataFrame:

              key1    key2
inner_key1  value1     NaN
inner_key2     NaN  value2

0voto

Gulzar Punkte 16632

Man könnte dotsi verwenden, für vollständige Listen-, Dictionary- und rekursive Unterstützung sowie einige Erweiterungsmethoden

pip install dotsi

und

>>> import dotsi
>>> 
>>> d = dotsi.Dict({"foo": {"bar": "baz"}})     # Grundlegend
>>> d.foo.bar
'baz'
>>> d.users = [{"id": 0, "name": "Alice"}]   # Liste
>>> d.users[0].name
'Alice'
>>> d.users.append({"id": 1, "name": "Becca"}); # Anhängen
>>> d.users[1].name
'Becca'
>>> d.users += [{"id": 2, "name": "Cathy"}];    # `+=`
>>> d.users[2].name
'Cathy'
>>> d.update({"tasks": [{"id": "a", "text": "Aufgabe A"}]});
>>> d.tasks[0].text
'Aufgabe A'
>>> d.tasks[0].tags = ["rot", "weiß", "blau"];
>>> d.tasks[0].tags[2];
'blau'
>>> d.tasks[0].pop("tags")                      # `.pop()`
['rot', 'weiß', 'blau']
>>> 
>>> import pprint
>>> pprint.pprint(d)
{'foo': {'bar': 'baz'},
 'tasks': [{'id': 'a', 'text': 'Aufgabe A'}],
 'users': [{'id': 0, 'name': 'Alice'},
           {'id': 1, 'name': 'Becca'},
           {'id': 2, 'name': 'Cathy'}]}
>>> 
>>> type(d.users)       # dotsi.Dict (auch bekannt als dotsi.DotsiDict)

>>> type(d.users[0])    # dotsi.List (auch bekannt als dotsi.DotsiList)

>>>

0voto

ted Punkte 11472

Meine 2 Cent: Für meine eigenen Zwecke habe ich minydra entwickelt, einen einfachen Befehlszeilenparser, der eine benutzerdefinierte Klasse MinyDict enthält (inspiriert von addict):

In [1]: from minydra import MinyDict

In [2]: args = MinyDict({"foo": "bar", "yes.no.maybe": "idontknow"}).pretty_print(); args

 foo          : bar           
 yes.no.maybe : idontknow     

Out[2]: {'foo': 'bar', 'yes.no.maybe': 'idontknow'}

In [3]: args.resolve().pretty_print(); args

 foo : bar                
 yes                      
 no                      
  maybe : idontknow     

Out[3]: {'foo': 'bar', 'yes': {'no': {'maybe': 'idontknow'}}}

In [4]: args.yes.no.maybe
Out[4]: "idontknow"

In [5]: "foo" in args
Out[5]: True

In [6]: "rick" in args
Out[6]: False

In [7]: args.morty is None
Out[7]: True

In [8]: args.items()
Out[8]: dict_items([('foo', 'bar'), ('yes', {'no': {'maybe': 'idontknow'}})])

Es geht über addict hinaus, indem es Dumping-/Lade-Methoden zu/aus json, yaml und pickle hinzufügt und auch einen strict-Modus in MinyDict.update() hat, um die Erstellung neuer Schlüssel zu verhindern (dies ist nützlich, um Tippfehler in der Befehlszeile zu verhindern)

0voto

CaffeinatedMike Punkte 1397

Ich habe das gerade aus einem Projekt ausgegraben, an dem ich vor langer Zeit gearbeitet habe. Es könnte wahrscheinlich etwas optimiert werden, aber hier ist es.

class DotNotation(dict):

    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __init__(self, data):
        if isinstance(data, str):
            data = json.loads(data)

        for name, value in data.items():
            setattr(self, name, self._wrap(value))

    def __getattr__(self, attr):
        def _traverse(obj, attr):
            if self._is_indexable(obj):
                try:
                    return obj[int(attr)]
                except:
                    return None
            elif isinstance(obj, dict):
                return obj.get(attr, None)
            else:
                return attr
        if '.' in attr:
            return reduce(_traverse, attr.split('.'), self)
        return self.get(attr, None)

    def _wrap(self, value):
        if self._is_indexable(value):
            # (!) recursive (!)
            return type(value)([self._wrap(v) for v in value])
        elif isinstance(value, dict):
            return DotNotation(value)
        else:
            return value

    @staticmethod
    def _is_indexable(obj):
        return isinstance(obj, (tuple, list, set, frozenset))

if __name__ == "__main__":
    test_dict = {
        "dimensions": {
            "length": "112",
            "width": "103",
            "height": "42"
        },
        "meta_data": [
            {
                "id": 11089769,
                "key": "imported_gallery_files",
                "value": [
                    "https://example.com/wp-content/uploads/2019/09/unnamed-3.jpg",
                    "https://example.com/wp-content/uploads/2019/09/unnamed-2.jpg",
                    "https://example.com/wp-content/uploads/2019/09/unnamed-4.jpg"
                ]
            }
        ]
    }
    dotted_dict = DotNotation(test_dict)
    print(dotted_dict.dimensions.length) # => '112'
    print(getattr(dotted_dict, 'dimensions.length')) # => '112'
    print(dotted_dict.meta_data[0].key) # => 'imported_gallery_files'
    print(getattr(dotted_dict, 'meta_data.0.key')) # => 'imported_gallery_files'
    print(dotted_dict.meta_data[0].value) # => ['link1','link2','link2']
    print(getattr(dotted_dict, 'meta_data.0.value')) # => ['link1','link2','link3']
    print(dotted_dict.meta_data[0].value[2]) # => 'link3'
    print(getattr(dotted_dict, 'meta_data.0.value.2')) # => 'link3'

0voto

Karolius Punkte 413

Hier ist meine Version von @derek73 Antwort. Ich verwende dict.__getitem__ als __getattr__, sodass es immer noch KeyError wirft, und benenne die öffentlichen Methoden des Wörterbuchs mit ""-Präfix um (um Konflikte mit speziellen Methodennamen zu vermeiden, wie z.B. __get__, der als Deskriptormethode behandelt werden würde). Wie auch immer, man kann keinen komplett klaren Namensraum für Schlüssel als Attribute haben aufgrund der wichtigen dict-Basismethoden, daher ist die Lösung nicht perfekt, aber man kann Schlüssel - Attribute wie get, pop, items usw. haben.

class DotDictMeta(type):
def new(
cls,
name,
bases,
attrs,
rename_method=lambda n: f'{n}',
custom_methods,
):
d = dict
attrs.update(
cls.get_hidden_or_renamed_methods(rename_method),
getattr=d.getitem,
setattr=d.setitem,
delattr=d.delitem,
**custom_methods,
)
return super().new(cls, name, bases, attrs)

    def __init__(self, name, bases, attrs, **_):                                  
        super().__init__(name, bases, attrs)                                      

    @property                                                                     
    def attribute_error(self):                                                    
        raise AttributeError                                                      

    @classmethod                                                                  
    def get_hidden_or_renamed_methods(cls, rename_method=None):                  
        public_methods = tuple(                                                   
            i for i in dict.__dict__.items() if not i[0].startswith('__')         
        )                                                                         
        error = cls.attribute_error                                               
        hidden_methods = ((k, error) for k, v in public_methods)                  
        yield from hidden_methods                                                 
        if rename_method:                                                       
            renamed_methods = ((rename_method(k), v) for k, v in public_methods) 
            yield from renamed_methods                                             

class DotDict(dict, metaclass=DotDictMeta):                                       
    pass  

Du kannst die Wörterbuchmethoden aus dem DotDict-Namensraum entfernen und weiterhin die Methoden der Wörterbuchklasse verwenden. Dies ist auch nützlich, wenn du auf anderen Wörterbuchinstanzen arbeiten möchtest und die gleichen Methoden ohne zusätzliche Überprüfung verwenden möchtest, ob es sich um ein DotDict handelt oder nicht, z.B.

dct = dict(a=1)
dot_dct = DotDict(b=2)
foo = {c: i for i, c in enumerate('xyz')}
for d in (dct, dot_dct):
    # Du müsstest dct.update und dot_dct.__update Methoden verwenden
    dict.update(d, foo)

assert dict.get(dot, 'foo', 0) is 0**

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