8

I have a list of day names (typically Monday-Saturday, though special cases apply) that I want to create a dictionary out of. I want to initialize the value of each day to zero.

If I had a list of zeroes the same length of the list of days, this would be a simple use case of zip(). However, a list of zeroes is a waste of space, and if that were the only solution I'd just as soon do something like:

for day in weekList:
    dayDict[day] = 0

Is there a more pythonic way?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user1427661
  • 11,158
  • 28
  • 90
  • 132
  • 4
    You might also want to look into a `collections.defaultdict(int)` -- This would do basically the same thing, but you won't get a `KeyError` if you try to get a key that doesn't exist. – mgilson Jan 10 '13 at 13:30
  • Also see [dict.fromkeys all point to same list](https://stackoverflow.com/questions/15516413/dict-fromkeys-all-point-to-same-list) – user202729 Aug 08 '18 at 16:05

2 Answers2

25

Use the .fromkeys() class method:

dayDict = dict.fromkeys(weekList, 0)

It builds a dictionary using the elements from the first argument (a sequence) as the keys, and the second argument (which defaults to None) as the value for all entries.

By it's very nature, this method will reuse the value for all keys; don't pass it a mutable value such as a list or dict and expect it to create separate copies of that mutable value for each key. In that case, use a dict comprehension instead:

dayDict = {d: [] for d in weekList}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
18

Apart from dict.fromkeys you can also use dict-comprehension, but fromkeys() is faster than dict comprehensions:

In [27]: lis = ['a', 'b', 'c', 'd']

In [28]: dic = {x: 0 for x in lis}

In [29]: dic
Out[29]: {'a': 0, 'b': 0, 'c': 0, 'd': 0}

For 2.6 and earlier:

In [30]: dic = dict((x, 0) for x in lis)

In [31]: dic
Out[31]: {'a': 0, 'b': 0, 'c': 0, 'd': 0}

timeit comparisons:

In [38]: %timeit dict.fromkeys(xrange(10000), 0)         # winner
1000 loops, best of 3: 1.4 ms per loop

In [39]: %timeit {x: 0 for x in xrange(10000)}
100 loops, best of 3: 2.08 ms per loop

In [40]: %timeit dict((x, 0) for x in xrange(10000))
100 loops, best of 3: 4.63 ms per loop

As mentioned in comments by @Eumiro and @mgilson it is important to note that fromkeys() and dict-comprehensions may return different objects if the values used are mutable objects:

In [42]: dic = dict.fromkeys(lis, [])

In [43]: [id(x) for x in dic.values()]
Out[43]: [165420716, 165420716, 165420716, 165420716] # all point to a same object

In [44]: dic = {x: [] for x in lis}

In [45]: [id(x) for x in dic.values()]
Out[45]: [165420780, 165420940, 163062700, 163948812]  # unique objects
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 3
    Note that `.fromkeys()` is a lot faster. – Martijn Pieters Jan 10 '13 at 13:31
  • 1
    While you can use the dict comprehension with default value being a list or anything else, `.fromkeys()` can be used for immutable objects only (None, bool, ints, floats, strings and tuples) – eumiro Jan 10 '13 at 13:39
  • 1
    @eumiro -- Can you elaborate on this comment? `dict.fromkeys(range(10),[])` works OK (of course, you're storing multiple references to *the same list* if that's what you're talking about), but that may be OK or even desireable in some cases. – mgilson Jan 10 '13 at 13:45
  • 1
    @mgilson - I was speaking exactly about that case. It is important to mention, that dict comprehension and `.fromkeys()` do not return the same data structure (which will be probably ignored by inexperienced user). – eumiro Jan 10 '13 at 13:49