Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #51114 > unrolled thread
| Started by | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| First post | 2013-07-23 18:16 -0700 |
| Last post | 2013-07-25 12:20 +1000 |
| Articles | 6 — 4 participants |
Back to article view | Back to comp.lang.python
Python 3: dict & dict.keys() Ethan Furman <ethan@stoneleaf.us> - 2013-07-23 18:16 -0700
Re: Python 3: dict & dict.keys() Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-24 02:11 +0000
Re: Python 3: dict & dict.keys() Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-24 09:02 -0600
Re: Python 3: dict & dict.keys() Ethan Furman <ethan@stoneleaf.us> - 2013-07-24 17:59 -0700
Re: Python 3: dict & dict.keys() Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-25 05:57 +0000
Re: Python 3: dict & dict.keys() Ben Finney <ben+python@benfinney.id.au> - 2013-07-25 12:20 +1000
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-07-23 18:16 -0700 |
| Subject | Python 3: dict & dict.keys() |
| Message-ID | <mailman.5024.1374628577.3114.python-list@python.org> |
Back in Python 2.x days I had a good grip on dict and dict.keys(), and when to use one or the other.
Then Python 3 came on the scene with these things called 'views', and while range couldn't be bothered, dict jumped up
and down shouting, "I want some!"
So now, in Python 3, .keys(), .values(), even .items() all return these 'view' thingies.
And everything I thought I knew about when to use one or the other went out the window.
For example, if you need to modify a dict while iterating over it, use .keys(), right? Wrong:
--> d = {1: 'one', 2:'two', 3:'three'}
--> for k in d.keys():
... if k == 1:
... del d[k]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
If you need to manipulate the keys (maybe adding some, maybe deleting some) before doing something else with final key
collection, use .keys(), right? Wrong:
--> dk = d.keys()
--> dk.remove(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict_keys' object has no attribute 'remove'
I understand that the appropriate incantation in Python 3 is:
--> for k in list(d)
... ...
or
--> dk = list(d)
--> dk.remove(2)
which also has the added benefit of working the same way in Python 2.
So, my question boils down to: in Python 3 how is dict.keys() different from dict? What are the use cases?
--
~Ethan~
[toc] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-07-24 02:11 +0000 |
| Message-ID | <51ef37e3$0$29971$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #51114 |
On Tue, 23 Jul 2013 18:16:08 -0700, Ethan Furman wrote:
> Back in Python 2.x days I had a good grip on dict and dict.keys(), and
> when to use one or the other.
>
> Then Python 3 came on the scene with these things called 'views', and
> while range couldn't be bothered, dict jumped up and down shouting, "I
> want some!"
>
> So now, in Python 3, .keys(), .values(), even .items() all return these
> 'view' thingies.
>
> And everything I thought I knew about when to use one or the other went
> out the window.
Surely not. The fundamental behaviour of Python's data model hasn't
changed. Lists are lists, views are views, and iterators are iterators.
Only the way you get each has changed.
- If in Python 2, you used the viewkeys() method, that's been renamed
keys() in Python 3. So d.viewkeys() => d.keys().
- If in Python 2, you used the keys() method, it returns a list, and
like any function that has been made lazy instead of eager in Python 3
(e.g. map, zip, filter) if you want the same behaviour, simply call
list manually. So d.keys() => list(d.keys()).
- If in Python 2, you used the iterkeys() methods, it returns a simple
iterator, not a view. So d.iterkeys() => iter(d.keys()).
None of these distinctions really matter if all you are doing is
iterating over the keys, without modifying the dict. Not in Python 2, nor
in Python 3.
And naturally the same applies to the various flavours of *items and
*values.
> For example, if you need to modify a dict while iterating over it, use
> .keys(), right? Wrong:
>
> --> d = {1: 'one', 2:'two', 3:'three'} --> for k in d.keys():
> ... if k == 1:
> ... del d[k]
> ...
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> RuntimeError: dictionary changed size during iteration
Fundamentally, this behaviour has not changed from Python 2: you should
not iterate over a data structure while changing it, instead you should
make a copy of the data you iterate over. In Python 2, d.keys() makes a
copy and returns a list, so in Python 3 you would call list(d.keys()).
> If you need to manipulate the keys (maybe adding some, maybe deleting
> some) before doing something else with final key collection, use
> .keys(), right? Wrong:
>
> --> dk = d.keys()
> --> dk.remove(2)
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> AttributeError: 'dict_keys' object has no attribute 'remove'
Repeat after me: "In Python 2, d.keys() returns a list of keys, so if I
want a list of keys in Python 3, call list explicitly list(d.keys())."
> I understand that the appropriate incantation in Python 3 is:
>
> --> for k in list(d)
> ... ...
>
> or
>
> --> dk = list(d)
> --> dk.remove(2)
>
> which also has the added benefit of working the same way in Python 2.
>
> So, my question boils down to: in Python 3 how is dict.keys() different
> from dict? What are the use cases?
*shrug* For most purposes, there is no difference, especially when merely
iterating over the dict. Such differences as exist are trivial:
- if you need an actual callable function or method, say to pass to some
other function, you can do this:
for method in (d.items, d.keys, d.values):
process(method)
instead of this:
# untested
for method in (d.items, d.keys, lambda d=d: iter(d)):
process(method)
- d.keys() is a view, not the dict itself. That's a pretty fundamental
difference: compare dir(d.keys()) with dir(d).
Basically, views are set-like, not list-like.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2013-07-24 09:02 -0600 |
| Message-ID | <mailman.5042.1374678199.3114.python-list@python.org> |
| In reply to | #51116 |
On Tue, Jul 23, 2013 at 8:11 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > Basically, views are set-like, not list-like. The keys and items views are set-like. The values view is not.
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-07-24 17:59 -0700 |
| Message-ID | <mailman.5075.1374713993.3114.python-list@python.org> |
| In reply to | #51116 |
On 07/23/2013 07:11 PM, Steven D'Aprano wrote: > On Tue, 23 Jul 2013 18:16:08 -0700, Ethan Furman wrote: >> >> So now, in Python 3, .keys(), .values(), even .items() all return these >> 'view' thingies. >> >> And everything I thought I knew about when to use one or the other went >> out the window. > > Surely not. The fundamental behaviour of Python's data model hasn't > changed. Poetic effect. Dramatic license. Blah blah. ;) > Repeat after me: "In Python 2, d.keys() returns a list of keys, so if I > want a list of keys in Python 3, call list explicitly list(d.keys())." Actually, I would recommend `list(d)`, which also works the same in both 2 and 3. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-07-25 05:57 +0000 |
| Message-ID | <51f0be51$0$29971$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #51179 |
On Wed, 24 Jul 2013 17:59:43 -0700, Ethan Furman wrote: >> Repeat after me: "In Python 2, d.keys() returns a list of keys, so if I >> want a list of keys in Python 3, call list explicitly list(d.keys())." > > Actually, I would recommend `list(d)`, which also works the same in both > 2 and 3. Fair point. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2013-07-25 12:20 +1000 |
| Message-ID | <mailman.5077.1374719106.3114.python-list@python.org> |
| In reply to | #51116 |
Ethan Furman <ethan@stoneleaf.us> writes: > On 07/23/2013 07:11 PM, Steven D'Aprano wrote: > > On Tue, 23 Jul 2013 18:16:08 -0700, Ethan Furman wrote: > >> And everything I thought I knew about when to use one or the other went > >> out the window. > > > > Surely not. The fundamental behaviour of Python's data model hasn't > > changed. > > Poetic effect. Dramatic license. Blah blah. ;) Text-only medium. Clarity of communication. Et cetera. :-) -- \ “Two hands working can do more than a thousand clasped in | `\ prayer.” —Anonymous | _o__) | Ben Finney
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web