Reputation: 103884
There are dozens of questions on turning a Python dict with some number of elements into a list of tuples. I am looking for a shortcut to turn a one element dict into a tuple.
Ideally, it would:
dict
, not a function, etc).dict
.I am looking for a shortcut to do this (that is not destructive to the dict):
k,v=unpack_this({'unknown_key':'some value'})
*
does not work here.
I have come up with these that work:
k,v=next(iter(di.items())) # have to call 'iter' since 'dict_items' is not
Or:
k,v=(next(((k,v) for k,v in di.items())))
Or even:
k,v=next(zip(di.keys(), di.values()))
Finally, the best I can come up with:
k,v=list(di.items())[0] # probably the best...
Which can be wrapped into a function if I want a length check:
def f(di):
if (len(di)==1): return list(di.items())[0]
raise ValueError(f'Too many items to unpack. Expected 2, got {len(di)*2}')
These methods seem super clumsy and none throw an error if there is more than one element.
Is there an idiomatic shortcut that I am missing?
Upvotes: 1
Views: 372
Reputation: 103884
@chepner has the right approach with .popitem()
:
>>> d = {'a': 1}
>>> d.popitem()
('a', 1) # d is now {}
This will return the pair associated with the last key added, with no error error if the dict
has multiple keys. It will also destroy d
.
You can keep d
intact by using this idiom to create a new dict and pop off the last item from the new dict created with {**d}
:
>>> {**d}.popitem()
('a', 1)
>>> d
{'a': 1}
As far as a 1 line unpackable tuple that throws an error if the dict has more than one item, you can use a Python conditional expression with an alternate that throws the error desired:
# success: k=='a' and v==1
>>> d={'a':1}
>>> k,v={**d}.popitem() if len(d)==1 else 'wrong number of values'
# len(d)!=1 - pass a string to k,v which is too long
>>> d={'a':1,'b':2}
>>> k,v={**d}.popitem() if len(d)==1 else 'wrong number of values'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
If you object to different types being passed, you could do:
>>> k,v={**d}.popitem() if len(d)==1 else {}.fromkeys('too many keys').items()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
Upvotes: 0
Reputation: 531480
>>> d = {'a': 1}
>>> d.popitem()
('a', 1)
This will return the pair associated with the last key added, with no error error if the dict
has multiple keys, but the same length check you've made in your function f
can be used.
def f(di):
if len(di) == 1:
return d.popitem()
raise ValueError(f'Dict has multiple keys')
Upvotes: 3