Jaka jest preferowana składnia do inicjowania dict: literały nawiasów klamrowych {} lub funkcja dict ()?


212

Wkładam trochę wysiłku w naukę języka Python i zwracam szczególną uwagę na wspólne standardy kodowania. To może wydawać się bezcelowe, wybredne pytanie, ale staram się skupiać na najlepszych praktykach, kiedy się uczę, więc nie muszę się uczyć żadnych „złych” nawyków.

Widzę dwie typowe metody inicjowania nagrania:

a = {
    'a': 'value',
    'another': 'value',
}

b = dict( 
    a='value',
    another='value',
)

Który uważa się za „bardziej pythonowy”? Z którego korzystasz Czemu?


5
Jakiego samouczka używasz? Gdzie widziałeś przykłady prowadzące do zamieszania?
S.Lott,

2
Cóż, korzystałem z samouczka Python, Dive into Python, a następnie różnych blogów, postów SO i innych zasobów Googled. Oficjalne dokumenty używają {}dość jednolicie, ale widzę wiele wyraźnego dict()podejścia gdzie indziej. Widziałem korzyści z wyraźnej składni, ale brak podejścia w oficjalnych dokumentach wzbudził we mnie podejrzenia. Po opublikowaniu tego, przejrzałem dokumenty biblioteczne dicti znalazłem ostrożność, że klucze muszą być prawidłowymi identyfikatorami, gdy jawne dictjest używane do inicjowania nagrania.
daotoad

2
W jaki sposób „dict ()” jest bardziej wyraźne niż „{}”? Nie rozumiem twojego zamieszania. Oba wydają mi się wyraźne. Czy możesz podać cytat lub odniesienie, które każą powiedzieć, że „dykt” jest „jednoznaczny”, a „{}” nie jest jednoznaczny? Jak myślisz, skąd się wzięło to rozróżnienie?
S.Lott

21
Różnica polega na pisowni. dict()jest napisane - dictużywa nazwy typu. Nawiasy klamrowe ( {}) polegają na interpunkcji w celu identyfikacji typu.
daotoad

Odpowiedzi:


235

Nawiasy klamrowe. Przekazywanie argumentów słów kluczowych dodict() , choć działa pięknie w wielu scenariuszach, może zainicjować mapę tylko wtedy, gdy klucze są poprawnymi identyfikatorami Pythona.

To działa:

a = {'import': 'trade', 1: 7.8}
a = dict({'import': 'trade', 1: 7.8})

To nie zadziała:

a =                  dict(import='trade', 1=7.8)
>> SyntaxError: invalid syntax  ^

85

Pierwsze, kręcone szelki. W przeciwnym razie wystąpią problemy z spójnością z kluczami, które zawierają w sobie nieparzyste znaki, np =.

# Works fine.
a = {
    'a': 'value',
    'b=c': 'value',
}

# Eeep! Breaks if trying to be consistent.
b = dict( 
    a='value',
    b=c='value',
)

11
Właśnie dlatego można preferować metodę inicjowania dict (), która wymusza, aby klucze słownika były prawidłowymi identyfikatorami, więc są one zgodne na przykład z ** kwargs, a klucze są prawidłowymi nazwami atrybutów.
RufusVS,

57

Preferowana jest pierwsza wersja:

  • Działa dla wszystkich rodzajów kluczy, więc możesz na przykład powiedzieć {1: 'one', 2: 'two'}. Drugi wariant działa tylko dla (niektórych) kluczy ciągów. Stosowanie różnych rodzajów składni w zależności od rodzaju kluczy byłoby niepotrzebną niespójnością.
  • To jest szybsze:

    $ python -m timeit "dict(a='value', another='value')"
    1000000 loops, best of 3: 0.79 usec per loop
    $ python -m timeit "{'a': 'value','another': 'value'}"
    1000000 loops, best of 3: 0.305 usec per loop
  • Jeśli specjalna składnia literałów słownikowych nie była przeznaczona do użycia, prawdopodobnie nie istniałaby.

3

Myślę, że pierwsza opcja jest lepsza, ponieważ masz zamiar uzyskać dostęp do wartości jako [„a”] lub [„inny”]. Klucze w twoim słowniku są łańcuchami i nie ma powodu udawać, że nie są. Dla mnie składnia słowa kluczowego na początku wygląda na sprytną, ale na drugi rzut oka jest niejasna. Ma to dla mnie sens tylko wtedy, gdy pracujesz __dict__, a słowa kluczowe staną się później atrybutami, coś w tym rodzaju.


3

Do Twojej wiadomości, na wypadek gdybyś musiał dodać atrybuty do słownika (rzeczy, które są dołączone do słownika, ale nie są jednym z kluczy), będziesz potrzebować drugiej formy. W takim przypadku możesz zainicjować słownik za pomocą klawiszy o dowolnych znakach, pojedynczo:

    class mydict(dict): pass
    a = mydict()        
    a["b=c"] = 'value'
    a.test = False

2

Czasami dict()jest dobrym wyborem:

a=dict(zip(['Mon','Tue','Wed','Thu','Fri'], [x for x in range(1, 6)]))

mydict=dict(zip(['mon','tue','wed','thu','fri','sat','sun'],

[random.randint (0,100) dla xw zakresie (0,7)]))


2
Istnieje funkcja wyliczeniowa, która mogłaby to zrobić lepiej. Jeśli o to chodzi, istnieje typ Enum, który lepiej robi to, co tutaj robisz. Poza tym tak naprawdę wcale nie jest to odpowiedź na pytanie.
dusktreader

2

Prawie zawsze używam nawiasów klamrowych; jednak w niektórych przypadkach, w których piszę testy, pakuję / rozpakowuję słowa kluczowe, aw tych przypadkach dict () jest znacznie łatwiejszy w utrzymaniu, ponieważ nie muszę zmieniać:

a=1,
b=2,

do:

'a': 1,
'b': 2,

Pomaga również w niektórych okolicznościach, w których myślę, że w późniejszym czasie mogę chcieć przekształcić je w instancję nazwaną lub klasową.

W samej implementacji, z powodu mojej obsesji na punkcie optymalizacji, a kiedy nie widzę szczególnie dużych korzyści w zakresie konserwacji, zawsze będę faworyzować nawiasy klamrowe.

W testach i implementacji nigdy nie użyłbym dict (), jeśli istnieje szansa, że ​​klucze dodane wtedy lub w przyszłości:

  • Nie zawsze być ciągiem
  • Nie tylko zawierają cyfry, litery ASCII i znaki podkreślenia
  • Zacznij od liczby całkowitej ( dict(1foo=2)podnosi błąd SyntaxError)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.