1265

With Python 2.7, I can get dictionary keys, values, or items as a list:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

With Python >= 3.3, I get:

>>> newdict.keys()
dict_keys([1, 2, 3])

How do I get a plain list of keys with Python 3?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 33
    I'm new to Python, and to me it seems that this proliferation of useless new datatypes is one of the worst aspects of Python. Of what use is this dict_keys datatype? Why not a list? – Phil Goetz Apr 09 '20 at 20:22
  • 8
    @PhilGoetz it saves memory by creating a *view* onto the dictionary that can use all the dictionary's data, rather than having to store a list of however many elements. It also provides some set operations (i.e., it can take advantage of the fact that it "knows" it does not contain duplicates), which are more efficient than checking e.g. the intersection of two lists. – Karl Knechtel Aug 29 '22 at 13:08

13 Answers13

1568

This will convert the dict_keys object to a list:

list(newdict.keys())

On the other hand, you should ask yourself whether or not it matters. It is Pythonic to assume duck typing -- if it looks like a duck and it quacks like a duck, it is a duck. The dict_keys object can be iterated over just like a list. For instance:

for key in newdict.keys():
    print(key)

Note that dict_keys doesn't support insertion newdict[k] = v, though you may not need it.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Chris
  • 16,872
  • 1
  • 15
  • 16
  • 97
    newdict.keys() does not support indexing – gypaetus Sep 10 '14 at 17:54
  • 96
    `list(newdict)` also works (at least in python 3.4). Is there any reason to use the `.keys()` method? – naught101 Mar 31 '15 at 11:58
  • 77
    Note: in the debugger `pdb> list(newdict.keys()) ` fails because it clashes with pdb's command of the same name. Use `pdb> !list(newdict.keys())` to escape pdb commands. – Rian Rizvi Dec 24 '16 at 20:37
  • 39
    @naught101 Yes, `.keys()` is way more clear on what goes on. – Felix D. May 27 '18 at 21:43
  • 10
    Note that if you use list(newdict.keys()) that the keys are not in the order you placed them due to hashing order! – Nate M Jan 30 '19 at 03:28
  • @NateM, do any of the methods preserve insertion order of the keys? – dumbledad Oct 16 '19 at 13:13
  • I can't sort dict.keys() either, which is why I want it as a list. – n8mob Jan 31 '20 at 21:17
  • 1
    @n8mob: `sorted(mydict.keys())`, or just `sorted(mydict)` – Nick Matteo Apr 07 '20 at 01:59
  • I disagree with the "Obviously, insertion operators may not work, but that doesn't make much sense for a list of dictionary keys anyway" part. In my use case, I need to place an item at the beginning of the list, then step through the list as shown above. In this case, it makes perfect sense to place this item at the beginning of the list. – Itsme2003 Aug 06 '20 at 05:38
  • There are a number of scenarios to want a dict's keys as a list. In addition to those mentioned above, You may want to iterate over that list and modify the dict in the middle of iteration. You have to copy the data somewhere or you'll get an exception. Another scenario is where the dictionary was a holding area for data aggregation and once complete, a list of the keys is all that was needed. If you want to print out the keys, a repr of the output of keys() isn't nearly as useful as converting it to a list first. – royce3 Mar 29 '21 at 07:42
  • I don't wanna hear a word about duck typing in this context. The comparison `newdict.keys() == [1, 2, 3] -> False` caught me by surprise. That's way worse than Python 2. – Joooeey Nov 11 '21 at 12:38
  • I guess when you're not coming from Python 2, it makes more sense. The view object returned by `newdict.keys()` is duck-typed but to Iterable and Set (not to List). From the docs: "Keys views are set-like since their entries are unique and hashable.". So you get `newdict.keys() == {1, 2, 3} -> True` and you can iterate over the keys object like you always could. – Joooeey Nov 11 '21 at 12:55
514

Python >= 3.5 alternative: unpack into a list literal [*newdict]

New unpacking generalizations (PEP 448) were introduced with Python 3.5 allowing you to now easily do:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

Unpacking with * works with any object that is iterable and, since dictionaries return their keys when iterated through, you can easily create a list by using it within a list literal.

Adding .keys() i.e [*newdict.keys()] might help in making your intent a bit more explicit though it will cost you a function look-up and invocation. (which, in all honesty, isn't something you should really be worried about).

The *iterable syntax is similar to doing list(iterable) and its behaviour was initially documented in the Calls section of the Python Reference manual. With PEP 448 the restriction on where *iterable could appear was loosened allowing it to also be placed in list, set and tuple literals, the reference manual on Expression lists was also updated to state this.


Though equivalent to list(newdict) with the difference that it's faster (at least for small dictionaries) because no function call is actually performed:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

with larger dictionaries the speed is pretty much the same (the overhead of iterating through a large collection trumps the small cost of a function call).


In a similar fashion, you can create tuples and sets of dictionary keys:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

beware of the trailing comma in the tuple case!

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • great explanation,but please can you refer any link which describes this "*newdict" type of syntax,I mean how and why this returns the keys from dictionary just for understanding.Thanx – Muhammad Younus Apr 07 '18 at 02:56
  • 3
    @MYounas That syntax has been available for quite some time, even in Python 2. In function calls you can do `def foo(*args): print(args)` followed by `foo(*{1:0, 2:0})` with the result `(1, 2)` being printed. This behavior is specified in the [Calls](https://docs.python.org/3/reference/expressions.html#calls) section of the reference manual. Python 3.5 with PEP 448 just loosened the restrictions on where these can appear allowing `[*{1:0, 2:0}]` to now be used. Either way, I'll edit my answer and include these. – Dimitris Fasarakis Hilliard Apr 07 '18 at 10:56
  • 6
    `*newdict` - this is definitely the answer for code golfers ;P. Also: *which, in all honesty, isn't something you should really be worried about* - and if you are, **don't use python**. – Artemis Apr 05 '19 at 14:26
  • 7
    Learned two things today: 1. I can shorten `list(some_dict.keys())` to `[*some_dict]`, 2. the expression 'code golfer' (and 2a. the meaning of 'code golfer' - after Googling it) – kasimir Jul 08 '20 at 12:16
71

list(newdict) works in both Python 2 and Python 3, providing a simple list of the keys in newdict. keys() isn't necessary.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Seb
  • 821
  • 6
  • 7
38

You can also use a list comprehension:

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

Or, shorter,

>>> [k  for  k in  newdict]
[1, 2, 3]

Note: Order is not guaranteed on versions under 3.7 (ordering is still only an implementation detail with CPython 3.6).

cs95
  • 379,657
  • 97
  • 704
  • 746
sixsixsix
  • 1,768
  • 21
  • 19
31

A bit off on the "duck typing" definition -- dict.keys() returns an iterable object, not a list-like object. It will work anywhere an iterable will work -- not any place a list will. a list is also an iterable, but an iterable is NOT a list (or sequence...)

In real use-cases, the most common thing to do with the keys in a dict is to iterate through them, so this makes sense. And if you do need them as a list you can call list().

Very similarly for zip() -- in the vast majority of cases, it is iterated through -- why create an entire new list of tuples just to iterate through it and then throw it away again?

This is part of a large trend in python to use more iterators (and generators), rather than copies of lists all over the place.

dict.keys() should work with comprehensions, though -- check carefully for typos or something... it works fine for me:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
Chris Barker
  • 587
  • 6
  • 3
  • 3
    You don’t even need to use `.keys()`; the dictionary object is *itself* iterable and produces keys when iterated over: `[key.split(", ") for key in d]`. – Martijn Pieters Sep 27 '19 at 12:16
27

If you need to store the keys separately, here's a solution that requires less typing than every other solution presented thus far, using Extended Iterable Unpacking (Python3.x+):

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

Operation no. Of characters
k = list(d) 9 characters (excluding whitespace)
k = [*d] 6 characters
*k, = d 5 characters
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
cs95
  • 379,657
  • 97
  • 704
  • 746
  • 1
    The only minor caveat I'd point out is that `k` is always a list here. If a user wants a tuple or set from the keys they'll need to fall back to the other options. – Dimitris Fasarakis Hilliard Apr 05 '19 at 17:45
  • 1
    A more noteworthy note is the fact that, as a statement, `*k, = d` has limitations on where it can appear (but see, and maybe update this answer for, [PEP 572](https://www.python.org/dev/peps/pep-0572/) -- extended unpacking is not supported for assignment expressions atm *but* it might be someday!) – Dimitris Fasarakis Hilliard Apr 05 '19 at 17:55
  • what if you want both the keys and values to lists? – endolith Aug 26 '19 at 23:26
  • 3
    @endolith perhaps `keys, vals = zip(*d.items())` (although that gives two tuples, close enough). I don't know of a shorter expression than this. – cs95 Aug 26 '19 at 23:45
17

Converting to a list without using the keys method makes it more readable:

list(newdict)

and, when looping through dictionaries, there's no need for keys():

for key in newdict:
    print key

unless you are modifying it within the loop which would require a list of keys created beforehand:

for key in list(newdict):
    del newdict[key]

On Python 2 there is a marginal performance gain using keys().

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
Cas
  • 6,123
  • 3
  • 36
  • 35
13

Yes, There is a better and simplest way to do this in python3.X


use inbuild list() function

#Devil
newdict = {1:0, 2:0, 3:0}
key_list = list(newdict)
print(key_list) 
#[1, 2, 3] 
Devil
  • 1,054
  • 12
  • 18
7

I can think of 2 ways in which we can extract the keys from the dictionary.

Method 1: - To get the keys using .keys() method and then convert it to list.

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

Method 2: - To create an empty list and then append keys to the list via a loop. You can get the values with this loop as well (use .keys() for just keys and .items() for both keys and values extraction)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']
Rahul
  • 325
  • 5
  • 11
6

Beyond the classic (and probably more correct) way to do this (some_dict.keys()) there is also a more "cool" and surely more interesting way to do this:

some_dict = { "foo": "bar", "cool": "python!" }
print( [*some_dict] == ["foo", "cool"] )         # True  

Note: this solution shouldn't be used in a develop environment; I showed it here just because I thought it was quite interesting from the *-operator-over-dictionary side of view. Also, I'm not sure whether this is a documented feature or not, and its behaviour may change in later versions :)

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Giuppox
  • 1,393
  • 9
  • 35
3

You can you use simple method like below

keys = newdict.keys()
print(keys)
0
Get a list of keys with specific values

You can select a subset of the keys that satisfies a specific condition. For example, if you want to select the list of keys where the corresponding values are not None, then use

[k for k,v in newdict.items() if v is not None]
Slice the list of keys in a dictionary

Since Python 3.7, dicts preserve insertion order. So one use case of list(newdict) might be to select keys from a dictionary by its index or slice it (not how it's "supposed" to be used but certainly a possible question). Instead of converting to a list, use islice from the built-in itertools module, which is much more efficient since converting the keys into a list just to throw away most of it is very wasteful. For example, to select the second key in newdict:

from itertools import islice
next(islice(newdict, 1, 2))

or to slice the second to fifth key:

list(islice(newdict, 1, 6))

For large dicts, it's thousands of times faster than list(newdict)[1] etc.

cottontail
  • 10,268
  • 18
  • 50
  • 51
-1

This is the best way to get key List in one line of code

dict_variable = {1:"a",2:"b",3:"c"}  
[key_val for key_val in dict_variable.keys()]
Neeraj Kumar
  • 133
  • 1
  • 4