dict.fromkeys wijzen allemaal naar dezelfde lijst

Dit bezorgde me een beetje verdriet…

Ik heb een woordenboek gemaakt van een lijst

l = ['a','b','c']
d = dict.fromkeys(l, [0,0]) # initializing dictionary with [0,0] as values
d['a'] is d['b'] # returns True

Hoe kan ik van elke waarde van het woordenboek een aparte lijst maken? Is dit mogelijk zonder alle sleutels te herhalen en ze gelijk te stellen aan een lijst? Ik wil één lijst wijzigen zonder alle andere te wijzigen.


Antwoord 1, autoriteit 100%

Je zou een dictaatbegrip kunnen gebruiken:

>>> keys = ['a','b','c']
>>> value = [0, 0]
>>> {key: list(value) for key in keys}
    {'a': [0, 0], 'b': [0, 0], 'c': [0, 0]}

Antwoord 2, autoriteit 89%

Dit antwoord is hier om dit gedrag uit te leggen aan iedereen die verbijsterd is door de resultaten die ze krijgen als ze proberen een dictte instantiëren met fromkeys()met een veranderlijke standaardwaarde daarin dict.

Overweeg:

#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

dus elke wijziging in l1heeft geen invloed op l2en vice versa.
dit zou waar zijn voor alle veranderlijke tot nu toe, inclusief een dict.

# create a new dict from an iterable of keys
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], [])
>>> dict1
{'c': [], 'b': [], 'a': []}

dit kan een handige functie zijn.
hier wijzen we aan elke toets een standaardwaarde toe die ook een lege lijst is.

# 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

Ze gebruiken inderdaad allemaal dezelfde ref!
Een verandering in één is een verandering in allen, aangezien ze in feite hetzelfde object zijn!

>>> dict1['a'].append('apples')
>>> dict1
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
>>> id(dict1['a'])
>>> 140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

voor velen was dit niet de bedoeling!

Laten we het nu eens proberen door een expliciete kopie te maken van de lijst die als standaardwaarde wordt gebruikt.

>>> empty_list = []
>>> id(empty_list)
140150324169864

en maak nu een dictaat met een kopie van 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']}

Nog steeds geen vreugde!
Ik hoor iemand schreeuwen, dat komt omdat ik een lege lijst heb gebruikt!

>>> 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']}

Het standaardgedrag van fromkeys()is om Nonetoe te wijzen aan de waarde.

>>> 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

Inderdaad, alle waarden zijn hetzelfde (en de enige!) None.
Laten we nu op een van de talloze manieren het dictherhalen en de waarde wijzigen.

>>> for k, _ in dict4.items():
...    dict4[k] = []
>>> dict4
{'c': [], 'b': [], 'a': []}

Hmm. Ziet er hetzelfde uit als voorheen!

>>> id(dict4['a'])
140150318876488
>>> id(dict4['b'])
140150324122824
>>> id(dict4['c'])
140150294277576
>>> dict4['a'].append('apples')
>>> dict4
>>> {'c': [], 'b': [], 'a': ['apples']}

Maar het zijn inderdaad verschillende []en, wat in dit geval het beoogde resultaat was.


Antwoord 3, autoriteit 27%

U kunt dit gebruiken:

l = ['a', 'b', 'c']
d = dict((k, [0, 0]) for k in l)

Antwoord 4, autoriteit 7%

l = ['a','b','c']
d = dict((i, [0, 0]) for i in l)

Other episodes