| I stand corrected on the mylist.sort() vs sorted(mylist). But really, such a mistake is more likely with two very different ways of doing the same kind of operation. In ruby you would just mylist.sort() for a new sorted list (although parens are optional if no arguments, but I show them), or mylist.sort!() to sort mylist in place. You don't have to know two very different things. Plus it's obvious with the ! > Getting keys from a dictionary is literally just calling dict.keys() Nope. Unless your definition of "keys" is a 'dict_keys' class. Chances are really good that what you wanted was a list of keys, not some object which does not behave exactly like a list. If you want to access the keys by index, you can't do it like mydict.keys()[0] because dict_keys does not have an index method. Oddly, if you want a list of keys of a dict in Python, you just do list(mydict). But you can also do [*mydict], which gives you a list of keys but is something special you have to learn. Here's a fun one. Give me the first key of a dict. Ruby: mydict.keys.first Python: (several ways) next(iter(mydict)) # which makes no sense at all... asking for the next value of something when you're actually asking for the first. list(mydict)[0] [*mydict][0] What if you want the values of the dict? Well, no surprise, Python gives you a dict_values object when you do mydict.values(). Likewise, you can't do listy things with that because it's not a list. You have to convert it to a list with list(mydict.values()). Or you can do the [*mydict.values()] thing. Python is full of so many inconsistencies, the cognitive overhead is much higher than it needs to be. I would argue that it makes people dumber, because they have to waste mental energy learning weird things for special cases. But what about the rest of my previous post list? Here's one I left out. The return-early pattern is common in imperative programming. We like to exit a function as soon as we know things aren't going a certain way. In Ruby: x = fetch_object("bob") or return "bob not found" In Python you need 2 or 3 lines (2 if you're using the walrus := operator). if (x := fetch_object("bob") is None): return "bob not found"
How about setting a value for a variable if it is unset? This is a common thing done when you have variable argumentsRuby: x ||= "default" Python: x = x or "default" # not only does it look stupid setting a thing to itself, but it will fail if x is zero. Edit: fixed asterisks. |
Since dict keys are generally intended to be unique, this is a much better data structure, because very often you just want to check if x in d.keys(), being a o(1) rather than linear search into a list -twice, because you first have to construct the list also!
It’s also more of a set-like view into the original key-set. This is why it shows up as dict_keys rather than set. You wouldn’t want every piece of code that simply does for k in d.keys() to first make a copy of the entire dataset before starting the iteration. Beginners will use these functions all over just like that, even though you can simply do for k in d. Or if k in d. Preventing such footguns is worth the inconvenience of having to convert to list(d.keys()) for the rare case of when it’s absolutely needed.
I’ve also never seen any code that need to get the first item out of a dict, what does that even mean? Dicts are mappings. Better optimize both syntax and performance for the more common use cases. Only use case I can see is an LRU cache but for that there are better ways, like @lru_cache or OrderedDict.pop. Where that’s needed, copying the whole dict into a new array would also be extremely inefficient.