Ta odpowiedź jest tutaj, aby wyjaśnić to zachowanie nikomu flummoxed wynikami próbują utworzyć instancję dict
z fromkeys()
z domyślną wartością zmienną w tym dict
.
Rozważmy:
#Python 3.4.3 (default, Nov 17 2016, 01:08:31)
# start by validating that different variables pointing to an
# empty mutable are indeed different references.
>>> l1 = []
>>> l2 = []
>>> id(l1)
140150323815176
>>> id(l2)
140150324024968
więc każda zmiana l1
nie wpłynie l2
i vice versa. Dotyczy to wszystkich możliwych zmian, w tym dict
.
# create a new dict from an iterable of keys
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], [])
>>> dict1
{'c': [], 'b': [], 'a': []}
może to być przydatna funkcja. tutaj przypisujemy każdemu kluczowi wartość domyślną, która również jest pustą listą.
# the dict has its own id.
>>> id(dict1)
140150327601160
# but look at the ids of the values.
>>> id(dict1['a'])
140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328
Rzeczywiście wszystkie używają tego samego ref. Zmiana na jedną jest zmianą dla wszystkich, ponieważ w rzeczywistości są one tym samym obiektem!
>>> dict1['a'].append('apples')
>>> dict1
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
>>> id(dict1['a'])
>>> 140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328
dla wielu, to nie było to, co było zamierzone!
Spróbujmy teraz, używając jawnej kopii listy jako wartości domyślnej.
>>> empty_list = []
>>> id(empty_list)
140150324169864
i teraz utwórz dyktor z kopią empty_list
.
>>> dict2 = dict.fromkeys(['a', 'b', 'c'], empty_list[:])
>>> id(dict2)
140150323831432
>>> id(dict2['a'])
140150327184328
>>> id(dict2['b'])
140150327184328
>>> id(dict2['c'])
140150327184328
>>> dict2['a'].append('apples')
>>> dict2
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
Nadal nie ma radości! Słyszę, że ktoś krzyczy, bo użyłem pustej listy!
>>> not_empty_list = [0]
>>> dict3 = dict.fromkeys(['a', 'b', 'c'], not_empty_list[:])
>>> dict3
{'c': [0], 'b': [0], 'a': [0]}
>>> dict3['a'].append('apples')
>>> dict3
{'c': [0, 'apples'], 'b': [0, 'apples'], 'a': [0, 'apples']}
Domyślne zachowanie fromkeys()
jest przypisanie None
wartości.
>>> dict4 = dict.fromkeys(['a', 'b', 'c'])
>>> dict4
{'c': None, 'b': None, 'a': None}
>>> id(dict4['a'])
9901984
>>> id(dict4['b'])
9901984
>>> id(dict4['c'])
9901984
Rzeczywiście, wszystkie wartości są takie same (i jedyne!) None
. Teraz, iterujemy, na jeden z niezliczonych sposobów, poprzez dict
i zmieniamy wartość.
>>> for k, _ in dict4.items():
... dict4[k] = []
>>> dict4
{'c': [], 'b': [], 'a': []}
Hmm. Wygląda tak samo jak wcześniej!
>>> id(dict4['a'])
140150318876488
>>> id(dict4['b'])
140150324122824
>>> id(dict4['c'])
140150294277576
>>> dict4['a'].append('apples')
>>> dict4
>>> {'c': [], 'b': [], 'a': ['apples']}
Jednak są one rzeczywiście różne []
s, co w tym przypadku było zamierzonym rezultatem.
'lista (wartość)' to to samo, co "wartość [:]" tutaj? – Droogans
@Droogany: Tak. Po prostu uważam, że pusta notacja plastyczna jest brzydka. – Blender