361

I'd like to get from this:

keys = [1,2,3]

to this:

{1: None, 2: None, 3: None}

Is there a pythonic way of doing it?

This is an ugly way to do it:

>>> keys = [1,2,3]
>>> dict([(1,2)])
{1: 2}
>>> dict(zip(keys, [None]*len(keys)))
{1: None, 2: None, 3: None}
evtoh
  • 444
  • 3
  • 10
  • 21
Juanjo Conti
  • 28,823
  • 42
  • 111
  • 133
  • Do you intend for the dictionary to have `None` values for all keys? If so, why not use a `set` instead? The only reason that comes to mind for using a `dict` instead of `set` in this case is if you want to iterate the structure in insertion order. – joseville Aug 07 '22 at 14:08

7 Answers7

541

dict.fromkeys directly solves the problem:

>>> dict.fromkeys([1, 2, 3, 4])
{1: None, 2: None, 3: None, 4: None}

This is actually a classmethod, so it works for dict-subclasses (like collections.defaultdict) as well.

The optional second argument, which defaults to None, specifies the value to use for the keys. Note that the same object will be used for each key, which can cause problems with mutable values:

>>> x = dict.fromkeys([1, 2, 3, 4], [])
>>> x[1].append('test')
>>> x
{1: ['test'], 2: ['test'], 3: ['test'], 4: ['test']}

If this is unacceptable, see How can I initialize a dictionary whose values are distinct empty lists? for a workaround.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Thomas Wouters
  • 130,178
  • 23
  • 148
  • 122
  • 212
    Be careful with initializing to something mutable: If you call, e.g., `dict.fromkeys([1, 2, 3], [])`, all of the keys are mapped to the same list, and modifying one will modify them all. – charleslparker Jun 26 '13 at 16:47
  • 47
    Initializing with `{k:[] for k in [1, 2, 3]}` is still safe though. – Aziz Alto Jun 24 '19 at 16:13
356

Use a dict comprehension:

>>> keys = [1,2,3,5,6,7]
>>> {key: None for key in keys}
{1: None, 2: None, 3: None, 5: None, 6: None, 7: None}

The value expression is evaluated each time, so this can be used to create a dict with separate lists (say) as values:

>>> x = {key: [] for key in [1, 2, 3, 4]}
>>> x[1] = 'test'
>>> x
{1: 'test', 2: [], 3: [], 4: []}
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Adrien Plisson
  • 22,486
  • 6
  • 42
  • 73
81
dict.fromkeys(keys, None)
Dominic Cooney
  • 6,317
  • 1
  • 26
  • 38
22

A list comprehension can be used to build a list of key-value pairs, which can then be passed to the dict constructor. Thus:

>>> keys = {"a", "b", "c", "d"}
>>> d = dict([(key, []) for key in keys])
>>> d
{'d': [], 'c': [], 'a': [], 'b': []}

The value expression is evaluated each time, creating separate lists in the above example:

>>> d['a'].append('test')
>>> d
{'d': [], 'c': [], 'a': ['test'], 'b': []}
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Mayur Koshti
  • 1,794
  • 15
  • 20
  • 3
    While this code may answer the question, providing additional context regarding _how_ and/or _why_ it solves the problem would improve the answer's long-term value. – spongebob Aug 24 '15 at 12:49
  • 9
    the name `keyDict` is misleading, as the first line of code returns a `set`, not a `dict`. – Bryan Oakley May 23 '16 at 15:55
  • 1
    They probably will be mapped to the same list though – VMAtm Jul 14 '21 at 12:28
15

Simply iterate and add the values to an empty dictionary:

d = {}
for i in keys:
    d[i] = None
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
9

In many workflows where you want to attach a default / initial value for arbitrary keys, you don't need to hash each key individually ahead of time. You can use collections.defaultdict. For example:

from collections import defaultdict

d = defaultdict(lambda: None)

print(d[1])  # None
print(d[2])  # None
print(d[3])  # None

This is more efficient, it saves having to hash all your keys at instantiation. Moreover, defaultdict is a subclass of dict, so there's usually no need to convert back to a regular dictionary.

For workflows where you require controls on permissible keys, you can use dict.fromkeys as per the accepted answer:

d = dict.fromkeys([1, 2, 3, 4])
jpp
  • 159,742
  • 34
  • 281
  • 339
1

Just because it's fun how the dict constructor works nicely with zip, you can repeat the default value and zip it to the keys:

from itertools import repeat

keys = [1, 2, 3]
default_value = None

d = dict(zip(keys, repeat(default_value)))
print(d)

Will give:

{1: None, 2: None, 3: None}

repeat creates an infinite iterator of the element passed to it but as zip stops on the shortest iterable all works well.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61