alvas
alvas

Reputation: 122072

dict(list(tuple)) vs {list(tuple)}?

Why does dict(list(tuple)) work but not {list(tuple)} E.g.

>>> dict([('b', 456), ('a', 123)])
{'a': 123, 'b': 456}
>>> {[('b', 456), ('a', 123)]}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Which part of the CPython code allows for dict([('b', 456), ('a', 123)])?

Upvotes: 0

Views: 1371

Answers (4)

AKS
AKS

Reputation: 19831

dict is a class and when you use dict(list(tuple)) it instantiate the class using constructor.

Looking at the documentation for dict:

Dictionaries can be created by placing a comma-separated list of key: value pairs within braces, for example: {'jack': 4098, 'sjoerd': 4127} or {4098: 'jack', 4127: 'sjoerd'}, or by the dict constructor.

If no positional argument is given, an empty dictionary is created. If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterable object. Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value. If a key occurs more than once, the last value for that key becomes the corresponding value in the new dictionary.


When you use {list(tuple)} it tries to create a set object.

A set object is an unordered collection of distinct hashable objects.

But here you have used a list element which is a mutable container and is not hashable which leads to the error:

TypeError: unhashable type: 'list'

There is a nice explanation on Why Lists Can't Be Dictionary Keys?, and the same behavior applies to set members as well.

Upvotes: 1

qvpham
qvpham

Reputation: 1938

dict(list(tuple)) create a new dict use the dict() constructor. And here is what he does

def __init__(self, seq=None, **kwargs): # known special case of dict.__init__
        """
        dict() -> new empty dictionary
        dict(mapping) -> new dictionary initialized from a mapping object's
            (key, value) pairs
        dict(iterable) -> new dictionary initialized as if via:
            d = {}
            for k, v in iterable:
                d[k] = v
        dict(**kwargs) -> new dictionary initialized with the name=value pairs
            in the keyword argument list.  For example:  dict(one=1, two=2)
        """

If you use {list(tuple)}, you are using set literals. It creates a new set, not dict For dict literals you need minimum a pair of two values separated by a colon. (Don't ask me why ;). This is definition of Python)

To create a set or a dict, the keys (of dict) or values (of set) must be hashable. The definition says:

An object is hashable if it has a hash value which never changes during its lifetime

A list is a mutable sequence. So list is unhashable. That's why you got the error message

TypeError: unhashable type: 'list'

If you want to create a new dict use braces from a list(tuple), you can use dict comprehension. (But only supported on Python 3)

{a,b for a,b in list(tuple)}

P/S: dict literals is a little more performance than dict()

Upvotes: 0

zondo
zondo

Reputation: 20336

{} can be used for both sets and dictionaries. For example, {8: 2} is a dictionary, but {1, 2, 3, 4} is a set. Since you gave no key, Python assumes that you want a set. A set depends on having hashable items, so it complains when you give it a list.

If you want to use a literal, try a comprehension:

{k: v for k, v in mylist}

Upvotes: 7

user2357112
user2357112

Reputation: 280837

Just like with ["asdf"] and list("asdf") or str(thing) and "thing", calling the dict constructor on a thing does something completely different from surrounding it with braces.

When you construct a dict with braces, you're supposed to write out key-value pairs explicitly:

{'b': 456, 'a': 123}

When you just write {thing}, Python sees that you've written a single item instead of key-value pairs, and it instead tries to build a single-element set containing that thing. This fails, because the thing in the braces is a list and lists aren't hashable.

When you construct a dict with the dict constructor, you can pass in a single object used to initialize the dict. This object can either be another mapping, which will be copied into the dict, or a sequence of key-value pairs represented as tuples:

dict([('b', 456), ('a', 123)])

You cannot use colon notation:

dict('b': 456, 'a': 123)  # Syntax error

You can use keyword arguments, since the constructor also allows you to provide string keys as keyword arguments, a syntax that the braces notation doesn't support:

dict(b=456, a=123)  # Works
{b=456, a=123)  # Syntax error

Upvotes: 3

Related Questions