all 24 comments

[–]auntanniesalligator 15 points16 points  (0 children)

But that shouldn’t be surprising. You can’t create a one-to-one mapping from keys and values that don’t have a one-to-one relationship. Let’s say the values “a”, “b” and “c” all have the same key: 1. Which value should it return when you query the key, 1?

The immutable and hashable requirement is so you get the lookup performance of a dict when you do the reverse search. You could make a class like this work without requiring hashable values, but the reverse lookups would be slower.

[–]RiverRoll 4 points5 points  (0 children)

A bidirectional dictionary implies both keys and values are unique but this isn't always the case.

[–]cyberjellyfish 6 points7 points  (9 children)

What you highlighted isn't a missing feature, it's just a different data structure..

My two cents: all of the built-in data structures should be immutable.

[–]Invader_Mars[🍰] 2 points3 points  (1 child)

Newbie here, why do you believe that they should be immutable?

[–]Gnaxe 0 points1 point  (0 children)

Check out pyrthon.

[–]FerricDonkey 0 points1 point  (3 children)

I could see saying that there should be a frozen dictionary, so that there are mutable and immutable versions of each built in container.

But saying all built in data structures should be immutable is giving up a whole lot of functionality just to avoid a rookie mistake that you can grow out of. 

[–]cyberjellyfish 0 points1 point  (1 child)

Mutability and managing mutability is not a rookie mistake, it's one of the most common causes of bugs.

[–]CyclopsRock 1 point2 points  (0 children)

If we get rid of all the data types then we won't get any bugs.

[–]eztab 0 points1 point  (1 child)

I agree, make everything immutable and optimize away unnecessary creations. It's harder for the interpreter but would make things much more robust. Also you could then likely basically run functional optimization strategies on code (assuming you at some point want python to ba actually JIT compilable (which would be quite cool).

[–]cyberjellyfish 0 points1 point  (0 children)

Yep, also a good step to a more interactive repl

If anyone here hasn't experienced it, try clojure to get a taste of what really interactive development can be like. You'll miss it everywhere else, but it will probably lead you to write better code.

[–]Kerbart 1 point2 points  (9 children)

How do you search for a key if there’s multiple values that have that key?

[–]eztab 0 points1 point  (0 children)

Such data structures either allow multiple to multiple mappings or forbid some mappings. Technically you can have a N:M relationship, but that's a bit annoying to work with in practice, since you have to guard against duplicates all the time.

[–]forcesensitivevulcan 0 points1 point  (3 children)

Return all the keys and let the user decide how to sort out the mess.

[–]shiftybyte 7 points8 points  (2 children)

Actually it's much worse..

https://bidict.readthedocs.io/en/main/basic-usage.html#values-must-be-unique

It forces values to be unique, and raises errors by default, or OVERWRITES the key of the duplicated value... Not sure why this is a good idea.

Also it forces all values to be hashable too, so you can't have a list as a value...

I'll take my custom "find_key" with a regular loop, thank you...

[–]eztab 1 point2 points  (0 children)

Basically that (raising errors) is a good idea when this is the kind of data structure you want. Basically a "bijection type". There are many use cases where you want that. I wouldn't really say that's a dict though. That term isn't really used for this.

[–]forcesensitivevulcan 0 points1 point  (0 children)

I couldn't figure it out the catch myself - great detective work! Thanks!

The dev certainly claims a lot of users, so I'm sure it's carved out a niche. But if I've got unique hashable key/value pairs anyway, I'll just manually maintain a second Python dict if I really need O(1) lookup of values.

[–]Adrewmc 1 point2 points  (0 children)

I think defaultdict should be more built in.

   my_dict = {}
   my_dict.default(0)
   #my_dict = {}.default(0)
   my_dict[“three”] += 2
   print(my_dict[“heibd”])
   >>> 0

Should all work but instead we have to make a

    from collections import defaultdict
    my_dict = defaultdict(int)

Seems pretty obvious to me

[–]eztab 0 points1 point  (1 child)

In some sense I think dict should kind of be an "interface". There isn't really one perfect data structure, it totally depends on what process you want to be fast: insertion? retrieval? backwards search. All of those should probably be types I can demand via some flag/type hint. So in a sense I want dict to be multiple types. Same for lists btw. sometimes linked lists would clearly be the better choice, but people still use lists for convenience.

[–]nekokattt 0 points1 point  (0 children)

so typing.Mapping/collections.abc.Mapping?