Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #101551 > unrolled thread

subscripting Python 3 dicts/getting the only value in a Python 3 dict

Started byNick Mellor <thebalancepro@gmail.com>
First post2016-01-12 08:50 -0800
Last post2016-01-13 15:58 +0000
Articles 18 — 11 participants

Back to article view | Back to comp.lang.python


Contents

  subscripting Python 3 dicts/getting the only value in a Python 3 dict Nick Mellor <thebalancepro@gmail.com> - 2016-01-12 08:50 -0800
    RE: subscripting Python 3 dicts/getting the only value in a Python 3 dict Emanuel Barry <vgr255@live.ca> - 2016-01-12 12:00 -0500
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Chris Angelico <rosuav@gmail.com> - 2016-01-13 04:06 +1100
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Terry Reedy <tjreedy@udel.edu> - 2016-01-12 12:12 -0500
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Bernardo Sulzbach <mafagafogigante@gmail.com> - 2016-01-12 15:18 -0200
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Peter Otten <__peter__@web.de> - 2016-01-12 18:32 +0100
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Ian Kelly <ian.g.kelly@gmail.com> - 2016-01-12 10:39 -0700
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Jussi Piitulainen <jussi.piitulainen@helsinki.fi> - 2016-01-12 19:47 +0200
      Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Marko Rauhamaa <marko@pacujo.net> - 2016-01-12 21:42 +0200
        Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Jussi Piitulainen <jussi.piitulainen@helsinki.fi> - 2016-01-12 22:18 +0200
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Peter Otten <__peter__@web.de> - 2016-01-12 19:09 +0100
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Bernardo Sulzbach <mafagafogigante@gmail.com> - 2016-01-12 16:48 -0200
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Peter Otten <__peter__@web.de> - 2016-01-12 19:59 +0100
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Bernardo Sulzbach <mafagafogigante@gmail.com> - 2016-01-12 17:12 -0200
      Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Steven D'Aprano <steve@pearwood.info> - 2016-01-13 12:29 +1100
        Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Bernardo Sulzbach <mafagafogigante@gmail.com> - 2016-01-13 13:53 -0200
    Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Steven D'Aprano <steve@pearwood.info> - 2016-01-13 12:23 +1100
      Re: subscripting Python 3 dicts/getting the only value in a Python 3 dict Grant Edwards <invalid@invalid.invalid> - 2016-01-13 15:58 +0000

#101551 — subscripting Python 3 dicts/getting the only value in a Python 3 dict

FromNick Mellor <thebalancepro@gmail.com>
Date2016-01-12 08:50 -0800
Subjectsubscripting Python 3 dicts/getting the only value in a Python 3 dict
Message-ID<f2711b57-7b11-4fd5-8bab-a3e8581177b5@googlegroups.com>
Hi all,

Seemingly simple problem:

There is a case in my code where I know a dictionary has only one item in it. I want to get the value of that item, whatever the key is.

In Python2 I'd write:

>>> d = {"Wilf's Cafe": 1}
>>> d.values()[0]
1

and that'd be an end to it.

In Python 3:

>>> d = {"Wilf's Cafe": 1}
>>> d.values()[0]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'dict_values' object does not support indexing
"Wilf's Cafe"
>>> d[list(d)[0]]
1

>>> for k in d:
...     value = d[k]
...     break
...     
>>> value
1

>>> list(d.values())[0]
1

None of this feels like the "one, and preferably only one, obvious way to do it" we all strive for. Any other ideas?

Thanks,

Nick

[toc] | [next] | [standalone]


#101553

FromEmanuel Barry <vgr255@live.ca>
Date2016-01-12 12:00 -0500
Message-ID<mailman.70.1452618016.13488.python-list@python.org>
In reply to#101551
> Hi all,
> 
> Seemingly simple problem:
> 
> There is a case in my code where I know a dictionary has only one item in it. I want to get the value of that item, whatever the key is.
> 
> In Python2 I'd write:
> 
> >>> d = {"Wilf's Cafe": 1}
> >>> d.values()[0]
> 1
The equivalent in Python 3 is `list(d.values())[0]`
> None of this feels like the "one, and preferably only one, obvious way to do it" we all strive for. Any other ideas?

If you feel like doing that, `for v in d.values(): pass` will set `v` to your value. But it's a bit cryptic, so you can probably resort to the list() alternative above :)
- Emanuel 		 	   		  

[toc] | [prev] | [next] | [standalone]


#101554

FromChris Angelico <rosuav@gmail.com>
Date2016-01-13 04:06 +1100
Message-ID<mailman.71.1452618384.13488.python-list@python.org>
In reply to#101551
On Wed, Jan 13, 2016 at 3:50 AM, Nick Mellor <thebalancepro@gmail.com> wrote:
> There is a case in my code where I know a dictionary has only one item in it. I want to get the value of that item, whatever the key is.
>
> In Python2 I'd write:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> 1
>
> and that'd be an end to it.
>
> In Python 3:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> Traceback (most recent call last):
>   File "<input>", line 1, in <module>
> TypeError: 'dict_values' object does not support indexing
> "Wilf's Cafe"
>>>> d[list(d)[0]]
> 1

You could try:

next(iter(d.values()))

but honestly, this isn't all that common a situation, so I'm not
surprised there's no really simple and clean way to do it.

ChrisA

[toc] | [prev] | [next] | [standalone]


#101556

FromTerry Reedy <tjreedy@udel.edu>
Date2016-01-12 12:12 -0500
Message-ID<mailman.73.1452618784.13488.python-list@python.org>
In reply to#101551
On 1/12/2016 11:50 AM, Nick Mellor wrote:
> Hi all,
>
> Seemingly simple problem:
>
> There is a case in my code where I know a dictionary has only one item in it. I want to get the value of that item, whatever the key is.
>
> In Python2 I'd write:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> 1
>
> and that'd be an end to it.
>
> In Python 3:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> Traceback (most recent call last):
>    File "<input>", line 1, in <module>
> TypeError: 'dict_values' object does not support indexing

The intended use of dict views: "Dictionary views can be iterated over 
to yield their respective data, and support membership tests:"

> "Wilf's Cafe"
>>>> d[list(d)[0]]
> 1
>
>>>> for k in d:
> ...     value = d[k]
> ...     break
> ...
>>>> value
> 1
>
>>>> list(d.values())[0]
> 1
>
> None of this feels like the "one, and preferably only one,
 > obvious way to do it" we all strive for. Any other ideas?

Using the values views at intended (as an iterable):

 >>> dv = d.values()
 >>> next(iter(dv))
1

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#101557

FromBernardo Sulzbach <mafagafogigante@gmail.com>
Date2016-01-12 15:18 -0200
Message-ID<mailman.74.1452619122.13488.python-list@python.org>
In reply to#101551
Intentions aside, next(iter(...)) seems the most pythonic you can get
about this anyway.

Just in case you happen not to need the dictionary anymore,
d.popitem()[1] does the trick.

[toc] | [prev] | [next] | [standalone]


#101559

FromPeter Otten <__peter__@web.de>
Date2016-01-12 18:32 +0100
Message-ID<mailman.75.1452619985.13488.python-list@python.org>
In reply to#101551
Nick Mellor wrote:

> Hi all,
> 
> Seemingly simple problem:
> 
> There is a case in my code where I know a dictionary has only one item in
> it. I want to get the value of that item, whatever the key is.
> 
> In Python2 I'd write:
> 
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> 1
> 
> and that'd be an end to it.
> 
> In Python 3:
> 
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> Traceback (most recent call last):
>   File "<input>", line 1, in <module>
> TypeError: 'dict_values' object does not support indexing
> "Wilf's Cafe"
>>>> d[list(d)[0]]
> 1
> 
>>>> for k in d:
> ...     value = d[k]
> ...     break
> ...
>>>> value
> 1
> 
>>>> list(d.values())[0]
> 1
> 
> None of this feels like the "one, and preferably only one, obvious way to
> do it" we all strive for. Any other ideas?

If there is exactly one item you can unpack:

>>> d = {"Wilf's Cafe": 1}
>>> k, = d.values()
>>> k
1

[toc] | [prev] | [next] | [standalone]


#101561

FromIan Kelly <ian.g.kelly@gmail.com>
Date2016-01-12 10:39 -0700
Message-ID<mailman.77.1452620442.13488.python-list@python.org>
In reply to#101551
On Tue, Jan 12, 2016 at 10:12 AM, Terry Reedy <tjreedy@udel.edu> wrote:
> Using the values views at intended (as an iterable):
>
>>>> dv = d.values()
>>>> next(iter(dv))
> 1

Good coding practice also dictates that whenever next is called, the
potential StopIteration exception must be caught unless it is clearly
intended to be propagated up to some generator. So more fully, this
should be something like:

dv = iter(d.values())
try:
    next(dv)
except StopIteration:
    raise IndexError("d is empty")

At which point it may be desirable to extract that into a utility function.

[toc] | [prev] | [next] | [standalone]


#101563

FromJussi Piitulainen <jussi.piitulainen@helsinki.fi>
Date2016-01-12 19:47 +0200
Message-ID<lf5a8oaellh.fsf@ling.helsinki.fi>
In reply to#101551
Nick Mellor writes:

> Hi all,
>
> Seemingly simple problem:
>
> There is a case in my code where I know a dictionary has only one item
> in it. I want to get the value of that item, whatever the key is.
>
> In Python2 I'd write:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> d.values()[0]
> 1
>
> and that'd be an end to it.
>
> In Python 3:

If you are happy to give the sole value a name:

   >>> shoe = dict(it=math.pi)
   >>> [o] = shoe.values()
   >>> o
   3.141592653589793

You might be able to use * to pass the sole value to a function:

   >>> print(*shoe.values())
   3.141592653589793

But the most readable thing might be to have a function that extracts
the sole value by whatever means:

   >>> def sole(d): [o] = d.values() ; return o
   ... 
   >>> sole(shoe)
   3.141592653589793

[toc] | [prev] | [next] | [standalone]


#101572

FromMarko Rauhamaa <marko@pacujo.net>
Date2016-01-12 21:42 +0200
Message-ID<87egdmd1ou.fsf@elektro.pacujo.net>
In reply to#101563
Jussi Piitulainen <jussi.piitulainen@helsinki.fi>:

> But the most readable thing might be to have a function that extracts
> the sole value by whatever means:
>
>    >>> def sole(d): [o] = d.values() ; return o
>    ... 
>    >>> sole(shoe)
>    3.141592653589793

In the same vein:

   >>> def sole(d):
   ...   for o in d.values():
   ...     return o
   ... 
   >>> sole(shoe)
   3.141592653589793


Marko

[toc] | [prev] | [next] | [standalone]


#101573

FromJussi Piitulainen <jussi.piitulainen@helsinki.fi>
Date2016-01-12 22:18 +0200
Message-ID<lf537u2tuv8.fsf@ling.helsinki.fi>
In reply to#101572
Marko Rauhamaa writes:

> Jussi Piitulainen:
>
>> But the most readable thing might be to have a function that extracts
>> the sole value by whatever means:
>>
>>    >>> def sole(d): [o] = d.values() ; return o
>>    ... 
>>    >>> sole(shoe)
>>    3.141592653589793
>
> In the same vein:
>
>    >>> def sole(d):
>    ...   for o in d.values():
>    ...     return o
>    ... 
>    >>> sole(shoe)
>    3.141592653589793

Tuple assignment has a useful side effect that all other methods present
in this thread lack: it raises an exception if the number of dictionary
entries is not exactly one.

[toc] | [prev] | [next] | [standalone]


#101566

FromPeter Otten <__peter__@web.de>
Date2016-01-12 19:09 +0100
Message-ID<mailman.80.1452622185.13488.python-list@python.org>
In reply to#101551
Ian Kelly wrote:

> On Tue, Jan 12, 2016 at 10:12 AM, Terry Reedy <tjreedy@udel.edu> wrote:
>> Using the values views at intended (as an iterable):
>>
>>>>> dv = d.values()
>>>>> next(iter(dv))
>> 1
> 
> Good coding practice also dictates that whenever next is called, the
> potential StopIteration exception must be caught unless it is clearly
> intended to be propagated up to some generator. 

Even then you should be prepared for

https://docs.python.org/dev/whatsnew/3.5.html#pep-479-change-stopiteration-handling-inside-generators

> So more fully, this
> should be something like:
> 
> dv = iter(d.values())
> try:
>     next(dv)
> except StopIteration:
>     raise IndexError("d is empty")
> 
> At which point it may be desirable to extract that into a utility
> function.

[toc] | [prev] | [next] | [standalone]


#101568

FromBernardo Sulzbach <mafagafogigante@gmail.com>
Date2016-01-12 16:48 -0200
Message-ID<mailman.81.1452624540.13488.python-list@python.org>
In reply to#101551
On Tue, Jan 12, 2016 at 3:32 PM, Peter Otten <__peter__@web.de> wrote:
>
> If there is exactly one item you can unpack:
>
>>>> d = {"Wilf's Cafe": 1}
>>>> k, = d.values()
>>>> k
> 1
>

I personally don't like that trailing comma, it just looks wrong
there. But this is very neat.

-- 
Bernardo Sulzbach

[toc] | [prev] | [next] | [standalone]


#101569

FromPeter Otten <__peter__@web.de>
Date2016-01-12 19:59 +0100
Message-ID<mailman.82.1452625185.13488.python-list@python.org>
In reply to#101551
Bernardo Sulzbach wrote:

> On Tue, Jan 12, 2016 at 3:32 PM, Peter Otten <__peter__@web.de> wrote:
>>
>> If there is exactly one item you can unpack:
>>
>>>>> d = {"Wilf's Cafe": 1}
>>>>> k, = d.values()
>>>>> k
>> 1
>>
> 
> I personally don't like that trailing comma, it just looks wrong
> there. But this is very neat.
> 

[k] = d.values()

works the same. I used the tuple here to keep it consistent with all other 
cases where the brackets are superfluous, like

[foo, *bar] = ... 
foo, *bar = ...

etc.

[toc] | [prev] | [next] | [standalone]


#101570

FromBernardo Sulzbach <mafagafogigante@gmail.com>
Date2016-01-12 17:12 -0200
Message-ID<mailman.83.1452625998.13488.python-list@python.org>
In reply to#101551
I saw it in another answer. next(iter(d)) is still the winner.

This resembles a list just too much, making the coder's intent harder
to understand. This is **very** subjective, of course.

[toc] | [prev] | [next] | [standalone]


#101582

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-13 12:29 +1100
Message-ID<5695a86c$0$1588$c3e8da3$5496439d@news.astraweb.com>
In reply to#101570
On Wed, 13 Jan 2016 06:12 am, Bernardo Sulzbach wrote:

> I saw it in another answer. next(iter(d)) is still the winner.

Except that doesn't return the *value*, it returns the *key*.

py> d = {'key': 'value'}
py> next(iter(d))
'key'


To get the value:

py> next(iter(d.values()))
'value'

> This resembles a list just too much, making the coder's intent harder
> to understand. This is **very** subjective, of course.

I'm sorry, I don't understand what you mean by "resembles a list"? What
does? In what way?


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101626

FromBernardo Sulzbach <mafagafogigante@gmail.com>
Date2016-01-13 13:53 -0200
Message-ID<mailman.109.1452700467.13488.python-list@python.org>
In reply to#101582
On Tue, Jan 12, 2016 at 11:29 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Wed, 13 Jan 2016 06:12 am, Bernardo Sulzbach wrote:
>
>> I saw it in another answer. next(iter(d)) is still the winner.
>
> Except that doesn't return the *value*, it returns the *key*.
>

There is a typo, sorry. I assume that what is passed to iter is a
dict_values object.

>> This resembles a list just too much, making the coder's intent harder
>> to understand. This is **very** subjective, of course.
>
> I'm sorry, I don't understand what you mean by "resembles a list"? What
> does? In what way?
>

[a] = d.values()  resembles a list too much to my eyes.

--
Bernardo Sulzbach

[toc] | [prev] | [next] | [standalone]


#101580

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-13 12:23 +1100
Message-ID<5695a72a$0$1583$c3e8da3$5496439d@news.astraweb.com>
In reply to#101551
On Wed, 13 Jan 2016 03:50 am, Nick Mellor wrote:

> Hi all,
> 
> Seemingly simple problem:
> 
> There is a case in my code where I know a dictionary has only one item in
> it. I want to get the value of that item, whatever the key is.

[snip examples]

> None of this feels like the "one, and preferably only one, obvious way to
> do it" we all strive for. Any other ideas?

That's because this is a somewhat weird case. A dict with only one item that
you don't know the key of? Who does that? (Well, apart from you,
obviously.)

Three solutions:


item = d.popitem()[1]  # But this modifies the dict.

# Use tuple rather than list for efficiency.
item = tuple(d.values())[0]


Probably the best solution, because it will conveniently raise an exception
if your assumption that the dict has exactly one item is wrong:

item, = d.values()  # Note the comma after "item".


The comma turns the assignment into sequence unpacking. Normally we would
write something like this:

a, b, c, d = four_items

but you can unpack a sequence of one item too. If you really want to make it
obvious that the comma isn't a typo:

(item,) = d.values()




-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101627

FromGrant Edwards <invalid@invalid.invalid>
Date2016-01-13 15:58 +0000
Message-ID<n75s6v$n1e$1@reader1.panix.com>
In reply to#101580
On 2016-01-13, Steven D'Aprano <steve@pearwood.info> wrote:
> Probably the best solution, because it will conveniently raise an exception
> if your assumption that the dict has exactly one item is wrong:
>
> item, = d.values()  # Note the comma after "item".

[...]

> but you can unpack a sequence of one item too. If you really want to make it
> obvious that the comma isn't a typo:
>
> (item,) = d.values()

If it were I, I'd definitely do the later.  I used to do it the first
way, but I often times would not notice the comma later when
maintaining the code and end up wasting an embarassing amount of time
when what should have been an easy, trivial change broke.

-- 
Grant Edwards               grant.b.edwards        Yow! It was a JOKE!!
                                  at               Get it??  I was receiving
                              gmail.com            messages from DAVID
                                                   LETTERMAN!!  !

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web