Jak sprawić, by członkowie słownika Python byli dostępni przez kropkę „.”?
Na przykład, zamiast pisać mydict['val']
, chciałbym pisać mydict.val
.
Chciałbym również uzyskać dostęp do zagnieżdżonych nagrań w ten sposób. Na przykład
mydict.mydict2.val
odnosi się do
mydict = { 'mydict2': { 'val': ... } }
python
dictionary
syntax
nested
bodacydo
źródło
źródło
d[a][b][c]
są zastępowane przezd[a, b, c]
.{"my.key":"value"}
? Lub gdy kluczem jest słowo kluczowe, na przykład „z”? Rozważyłem to kilka razy i to więcej problemów i rozwiązywania problemów niż spodziewanych korzyści.Odpowiedzi:
Możesz to zrobić, korzystając z klasy, którą właśnie stworzyłem. Dzięki tej klasie możesz używać
Map
obiektu jako innego słownika (w tym serializacji json) lub z notacją kropkową. Mam nadzieję, że ci pomogę:Przykłady użycia:
źródło
.iteritems()
do.items()
AttributeError
jeśli atrybut nie istnieje. Zamiast tego wróciNone
.self.update(*args,**kwargs)
. Możesz także dodać__missing__(self,key): value=self[key]= type(self)(); return value
. Następnie możesz dodać brakujące wpisy za pomocą notacji kropkowej. Jeśli chcesz, aby można go było odebrać, możesz dodać__getstate__
i__setstate__
hasattr(Map, 'anystring') is true. which means the hasattr would always return True due to overriding
__getattr__`Zawsze trzymałem to w pliku użytkownika. Możesz używać go jako miksu na własnych zajęciach.
źródło
d = {'foo': {'bar': 'baz'}}; d = dotdict(d); d.foo.bar
zgłasza błąd atrybutu, aled.foo
działa dobrze.python class DotDict(dict): """dot.notation access to dictionary attributes""" def __getattr__(*args): val = dict.get(*args) return DotDict(val) if type(val) is dict else val __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
get
to naprawdę zły pomysł, ponieważ wróciNone
zamiastZainstaluj
dotmap
przezpip
Robi wszystko, co chcesz, i podklas
dict
, więc działa jak zwykły słownik:Ponadto możesz przekonwertować go na
dict
obiekty:Oznacza to, że jeśli coś, do czego chcesz uzyskać dostęp, jest już w
dict
formie, możesz zmienić je wDotMap
łatwy dostęp:Wreszcie automatycznie tworzy nowe
DotMap
wystąpienia potomne, dzięki czemu możesz wykonywać następujące czynności:Porównanie do Buncha
Pełne ujawnienie: Jestem twórcą DotMap . Stworzyłem go, ponieważ
Bunch
brakowało tych funkcjiDotMap
tworzenie potomków, które oszczędza czas i zapewnia czystszy kod, gdy masz dużo hierarchiidict
i rekurencyjne konwertowanie wszystkichdict
instancji podrzędnych naDotMap
źródło
{"test.foo": "bar"}
można uzyskać dostęp za pośrednictwemmymap.test.foo
To byłoby fantastyczne. Przekształcenie płaskiej mapy w mapę głęboką zajmie pewną regresję, a następnie zastosowanie do niej DotMap, ale warto!DotMap
autouzupełniania działa najlepiej. Używam Sublime Text, który automatycznie uzupełnia wcześniej wpisane słowa kluczowe.**kwargs
lubc = {**a, **b}
. W rzeczywistości zawiesza się cicho, podczas rozpakowywania zachowuje się jak pusty słownik.m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m));
i spełniłem oczekiwania2 3
. Jeśli masz sprawdzoną zepsutą skrzynkę, która działa,dict()
ale nieDotMap()
, prześlij kod na kartę Problemy w GitHub.Wyprowadzić ze słownika i wdrożyć
__getattr__
i__setattr__
.Lub możesz użyć Bunch, który jest bardzo podobny.
Nie sądzę, że można monkeypatch wbudowaną klasę dict.
źródło
Materiał ma naprawdę ładne, minimalne wdrożenie . Rozszerzając to, aby umożliwić zagnieżdżony dostęp, możemy użyć a
defaultdict
, a wynik wygląda mniej więcej tak:Skorzystaj z niego w następujący sposób:
To trochę wyjaśnia odpowiedź Kugela: „czerp z dykta i zaimplementuj
__getattr__
i__setattr__
”. Teraz wiesz jak!źródło
dotdict
która pozwala konwertować istniejącydict
obiekt rekurencyjnie: gist.github.com/miku/…Próbowałem tego:
możesz
__getattribute__
też spróbować .spraw, aby każdy dyktat był typem dotdict, jeśli chcesz zainicjować to z wielowarstwowego dykta, spróbuj
__init__
również wdrożyć .źródło
def docdict(name):
przed nią, a następnie `if isinstance (name, dict): return DotDict (name) returnclass dotdict(dict): def __getattr__(self, name): if name not in self: return None elif type(self[name]) is dict: return JsonDot(self[name]) else: return self[name]
Nie rób Dostęp do atrybutów i indeksowanie to osobne rzeczy w Pythonie i nie powinieneś chcieć, aby działały tak samo. Stwórz klasę (prawdopodobnie stworzoną przez
namedtuple
), jeśli masz coś, co powinno mieć dostępne atrybuty, i użyj[]
notacji, aby uzyskać przedmiot ze słownika.źródło
.
zamiast[]
dostępu do skomplikowanych struktur danych w szablonach Mako.Jeśli chcesz marynować zmodyfikowany słownik, musisz dodać kilka metod stanów do powyższych odpowiedzi:
źródło
__getattr__ = dict.get
Opierając się na odpowiedzi Kugela i biorąc pod uwagę słowa ostrożności Mike'a Grahama, co zrobić, jeśli zrobimy opakowanie?
źródło
Użyj
SimpleNamespace
:źródło
Lubię Muncha i daje on wiele przydatnych opcji poza dostępem do kropki.
źródło
Ostatnio natknąłem się na bibliotekę „ Box ”, która robi to samo.
Polecenie instalacji:
pip install python-box
Przykład:
Przekonałem się, że jest bardziej skuteczny niż inne istniejące biblioteki, takie jak dotmap, które generują błąd rekurencji w Pythonie, gdy masz duże zagnieżdżone nagrania.
link do biblioteki i szczegóły: https://pypi.org/project/python-box/
źródło
Użycie
__getattr__
, bardzo proste, działa w Pythonie 3.4.3Wynik:
źródło
Sam język tego nie obsługuje, ale czasem jest to nadal użyteczny wymóg. Oprócz przepisu Bunch możesz także napisać małą metodę, która może uzyskać dostęp do słownika za pomocą kropkowanego ciągu:
który obsługuje coś takiego:
źródło
Opierając się na odpowiedzi epool, ta wersja umożliwia dostęp do dowolnego nagrania wewnątrz za pomocą operatora kropki:
Na przykład
foo.bar.baz[1].baba
zwraca"loo"
.źródło
iteritems()
zeitems()
ixrange()
zerange()
Jeśli ktoś zdecyduje się na stałe przekonwertować to
dict
na obiekt, powinien to zrobić. Możesz stworzyć obiekt do rzucania tuż przed uzyskaniem dostępu.źródło
Skończyło się na próbowaniu ZARÓWNO AttrDict i Bunchbibliotek i odkryłem, że jest to sposób na spowolnienie dla moich zastosowań. Po przyjrzeniu się temu przyjacielowi stwierdziliśmy, że główna metoda pisania tych bibliotek powoduje, że biblioteka agresywnie rekurencyjnie przeszukuje zagnieżdżony obiekt i tworzy kopie obiektu słownika w całym tekście. Mając to na uwadze, wprowadziliśmy dwie kluczowe zmiany. 1) Stworzyliśmy leniwe atrybuty 2) zamiast tworzyć kopie obiektu słownika, tworzymy kopie lekkiego obiektu proxy. To jest ostateczne wdrożenie. Wzrost wydajności korzystania z tego kodu jest niesamowity. Podczas korzystania z AttrDict lub Bunch te dwie biblioteki same pochłonęły odpowiednio 1/2 i 1/3 mojego czasu żądania (co !?). Ten kod skrócił ten czas prawie do zera (gdzieś w zakresie 0,5 ms). Zależy to oczywiście od twoich potrzeb, ale jeśli używasz tej funkcji całkiem sporo w kodzie,
Zobacz oryginalną implementację tutaj : https://stackoverflow.com/users/704327/michael-merickel .
Inną rzeczą do odnotowania jest to, że ta implementacja jest dość prosta i nie implementuje wszystkich metod, których możesz potrzebować. Musisz zapisać je zgodnie z wymaganiami na obiektach DictProxy lub ListProxy.
źródło
Chciałbym wrzucić własne rozwiązanie do ringu:
https://github.com/skorokithakis/jsane
Pozwala ci parsować JSON w coś, do czego masz dostęp
with.attribute.lookups.like.this.r()
, głównie dlatego, że nie widziałem tej odpowiedzi przed rozpoczęciem pracy nad nią.źródło
KeyError
jest jednym z nich, gdy dostęp do klucza, który nie istnieje, wszystko, co musi zrobić, to powrótNone
podobny do zachowania JS. Jestem wielkim fanem automatyzacji zarówno do czytania, jak i pisania. Twoja biblioteka jest najbliższa ideału.Nie bezpośrednia odpowiedź na pytanie OP, ale zainspirowana i być może przydatna dla niektórych. Stworzyłem rozwiązanie obiektowe przy użyciu wewnętrznego
__dict__
(w żaden sposób zoptymalizowanego kodu)źródło
Jednym prostym sposobem uzyskania dostępu do kropki (ale nie dostępu do tablicy) jest użycie zwykłego obiektu w Pythonie. Lubię to:
... i użyj go w ten sposób:
... aby przekonwertować go na dyktando:
źródło
To rozwiązanie jest udoskonaleniem tego, które oferuje epool, aby spełnić wymaganie OP, aby uzyskać dostęp do zagnieżdżonych nagrań w spójny sposób. Rozwiązanie epool nie pozwalało na dostęp do zagnieżdżonych nagrań.
Z tej klasy można teraz zrobić coś takiego:
A.B.C.D
.źródło
Działa to również w przypadku zagnieżdżonych nagrań i zapewnia, że dołączone później nagrania zachowują się tak samo:
źródło
Odpowiedź @ derek73 jest bardzo zgrabna, ale nie można go marynować ani (głęboko) skopiować i zwraca
None
za brakujące klucze. Poniższy kod to rozwiązuje.Edycja: Nie widziałem powyższej odpowiedzi, która dotyczy dokładnie tego samego punktu (pozytywnie oceniany). Zostawiam odpowiedź tutaj w celach informacyjnych.
źródło
Rozwiązanie delikatne
źródło