Hacker News new | past | comments | ask | show | jobs | submit login

Absolutely. For me it is a 50-50 chance whether I have data in a dict that needs to be mapped to something or have data in a list/tuple that needs mapping.

Many major programming languages undersell how natural key-value data structures are; usually by providing unwieldy mapping data types. Clojure has spoiled me.

> you could throw one together

Yeah, I do. Most Python programmers wouldn't see a need for that, but that can be attributed to Python not having the capability by default and so they've just internalised not to use dict for anything that needs to be a key. World's mildest form of learned helplessness, I suppose.




> Most Python programmers wouldn't see a need for that, but that can be attributed to Python not having the capability by default and so they've just internalised not to use dict for anything that needs to be a key.

You're being extremely uncharitable here.

To a Python programmer "using a dict as a key" is a nonsensical idea for the same reason "using a list as a key" is — both dicts and lists are mutable. Python programmers don't think of dicts or lists as synonymous with their content.

I'm assuming you don't want to literally use a dict as a key, you want to use the keys and values contained in a dict as a key. Nothing stops you. You just have to say it:

    point = dict(x=4, y=5, z=1)
    point_reviews = dict()
    point_reviews[tuple(point.items())] = "A+++ great coord would point to again"
You might wonder why you can't just use dicts directly. Again, dicts are mutable. What happens if you write:

    point = dict(x=0, y=9001)
    point_reviews = dict()
    point_reviews[point] = "Love how it's over 9000 here!"
    point["y"] = 8999
    result = point_reviews[dict(x=0, y=8999)]  # Is this a KeyError or not?
More detail on this issue is explained here: https://wiki.python.org/moin/DictionaryKeys

In the simplest case where you have a predefined list of keys, I'd suggest using a namedtuple instead of a dict. If you need to treat a dict's content as hashable but can't enumerate the keys, `tuple(d.items())` is probably the best choice in recent Python versions. Be aware though that in older Pythons you can't rely on stable sort order of dictionary items, so you have to use something like `frozenset(d.items())`.


Good information, and well put. A small quibble: you should probably almost never use tuple(), even on recent Python:

    >>> tuple(dict(a=1, b=2).items())
    (('a', 1), ('b', 2))
    >>> tuple(dict(b=2, a=1).items())
    (('b', 2), ('a', 1))
Of course, if you can absolutely guarantee how the dictionary has been constructed, it is possible. No rules are absolute. But in my experience, frozenset() is probably better:

    >>> frozenset(dict(a=1, b=2).items())
    frozenset({('b', 2), ('a', 1)})
    >>> frozenset(dict(b=2, a=1).items())
    frozenset({('b', 2), ('a', 1)})
(Or sometimes even id(), as, if you are confident enough that the dictionary is identical, that might be because it came from the same place. If you are building a reverse dictionary, say, or a cache of indices. Though obviously that it is much more situationally dependent.)


Well. Now that dictionaries remember their order in newer Python versions, there is a case to be made that dict(a=1, b=2) is not the same dictionary as dict(b=2, a1). So they should be different dict keys, if they could be dict keys.


    dict(a=1,b=2) == dict(b=2,a=1)
is True (on 3.7.3). I'm not too keen on introducing a third type of equality on the same type, even if it makes some theoretical sense.


And worse, the dict's values may themselves be mutable. So even tuple(point.items()) is not a sensible dict key in the general case.


id(dictionary) is the key you want: immutable, reliable, cheap.


That value will not change when the contents of the dict are updated. You’re keying on the dict itself rather than the hashed contents. That’s what you want in some situations, but it’s not what the parent post is looking for.


It's also not reliable, since the same address can be reused if the dict is GCed. This is actually really easy to induce in Python, since it uses immediate refcounting. In my REPL (3.7.3):

    >>> a = {}
    >>> x = id(a)
    >>> del a
    >>> a = {}
    >>> y = id(a)
    >>> x == y
    True




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: