8 ms·
> I'm a Python programmer. I fully expect dict keys to be able to be arbitrary objects. I'm a Python programmer too, and I also fully expect dict keys to be ab
by Singletoned 10y ago
> I'm a Python programmer. I fully expect dict keys to be able to be arbitrary objects.
I'm a Python programmer too, and I also fully expect dict keys to be able to be arbitary objects, and I get really frustrated with the fact that they can't be arbitary objects. They have to be hashable objects, and the hash function refuses to hash certain objects that it has decided aren't allowed.
- gshulegaard 10y agoI was going to reply to him, but you beat me to it. But since you posed a different question regarding the term hashable, I thought I would link some helpful starting docs (for you and/or others): https://docs.python.org/3/glossary.html#term-hashable https://docs.python.org/3/glossary.html#term-hashable http://stackoverflow.com/questions/4348232/python-dictionary-keys-besides-strings-and-integers http://stackoverflow.com/questions/4348232/python-dictionary...
- amelius 10y agoAs an aside, what happens in Python when you try to hash objects that contain circular references?
- sametmax 10y agoCome on, how many time in your entire life did you need this ? For set, it's a bit more annoying. But for dicts. twice in 10 years maybe ?
- Singletoned 10y agoIt has been quite common when wanting to use a dictionary as a cache or counter such as a function cache or to count how many times a function is called with certain arguments. If the values of the arguments aren't hashable it doesn't work.
- dkersten 10y agoAfter a few years of Clojure(Script), where immutability means you can use almost anything as keys, I have found many cases where my python code would have been simpler and easier if I could use arbitrary objects (and therefore data structures) as keys. I mean, its not a huge deal, but it adds up.
- orf 10y ago> I have found many cases where my python code would have been simpler and easier if I could use arbitrary objects as keys You can use pretty much anything as a dictionary key
- dkersten 10y agoThat's really not true[1]. You can only use hashable types, which excludes dicts, lists and sets. For example (tested on both python 2.7 and 3.4): >>> {{'a': 1}: 2} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'dict' >>> {[1,2,3]: 4} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> {{1,2,3}: 4} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'set' Objects inheriting from object are hashable by default, but the hash is based on the objects instance such that each instance will return a unique value for that instance: >>> class A(object): ... def __init__(self): ... self.x = 1 ... >>> a = A() >>> b = A() >>> d = {a: 1, b: 2} >>> a.x = 10 >>> b.x = 10 >>> d[a] 1 >>> d[b] 2 While this makes sense for the instance stored in the dict (because mutability would otherwise mean that they key changes values), I don't think this is particularly useful. I rarely look up dicts by instance, but rather by value. That is, I would construct another object with the same attributes and look up by that. You can, of course, implement your own __hash__ to make it work, but you have to do it manually for any object you want it and most third-party objects won't have implemented it so you'd have to monkey patch them. Contrast that with Clojure, where all built-in data structures (maps, sets, lists, dicts etc) work as keys out of the box. [1] I guess its true in the sense that you can implement __hash__ to make it work. But its not particularly easy or idiomatic.
- deleted 10y ago[deleted]
- ccapndave 10y agohttp://package.elm-lang.org/packages/eeue56/elm-all-dict/latest http://package.elm-lang.org/packages/eeue56/elm-all-dict/lat...
- Erwin 10y agoWell, you cannot use a mutable object as a key without some help. What would you expect to happen if the object is modified after being inserted into the dictionary? If you have a list or dictionary you want to use a key, you can convert it into a tuple which would make it immutable. If you don't care about performance for larger collections you could just use a list instead of a dictionary, which does not require hashing. Changes to the original mutable object will also be reflected in your list.
- jstimpfle 10y ago> What would you expect to happen if the object is modified after being inserted into the dictionary? This question is sometimes not important: When the mutable object is not mutated.
- luckystarr 10y ago> This question is sometimes not important: When the mutable object is not mutated. Which you can't guarantee when the object is mutable, so for consistency's sake it's left out. Though you can always build your own Dict subclass and implement __hash__ on it and be angry with yourself when it fails. :)
- Noseshine 10y ago> What would you expect to happen if the object is modified after being inserted into the dictionary? I would expect it to continue to use the object. Why would it matter if it was mutated or not? You can try it right in your browser with Javascript and the Map() object type. You can mutate the object all you want, as long as it's the same object(-reference) you access the same value in the Map object. Just as I would expect. "Mutable" doesn't change which object you have, only what it looks like inside.
- gshulegaard 10y agoThis fundamentally reduces the usefulness of hash representations though. Instead of thinking of dict keys, think sets. It's also worth pointing out that user-defined objects operate the way you seem to desire (e.g. default to using the id() property of the object to derive the hash). So in my mind, this strikes the perfect balance? StdLib types that are immutable bake in more comparative hash properties while making it trivial for a user to wrap them and override this richer behavior with default hash based on id(). Consider: ``` >>> class myList(object): ... def __init__(self): ... self.inner_list = list() ... >>> x = myList() >>> x <myList object at 0x10bdabf10> >>> x.inner_list [] >>> y = {x: 'hi'} >>> y {<myList object at 0x10bdabf10>: 'hi'} >>> x.inner_list.append(1) >>> x.inner_list [1] >>> y {<myList object at 0x10bdabf10>: 'hi'} >>> for k in y.keys(): ... print k.inner_list ... [1] ```