6 ms·
Dict Unpacking in Python
- kristjansson 1y agoWhile not nearly as fun as the OP, I’d note that this sort of unpacking is very pleasant in the newish PEP636 match case statements: https://peps.python.org/pep-0636/#matching-builtin-classes https://peps.python.org/pep-0636/#matching-builtin-classes
- xg15 1y agoLooks really cool! Will this allow combinations of bound and unbound variables? E.g.: def is_on_horizontal_line(point, line_y): match point: case (x, line_y): return f"Yes, with x={x}" case _: return "No" Seems both useful and potentially confusing.
- deleted 1y ago[deleted]
- thayne 1y agoIt allows you to use bound variables/constants as long as the expression includes a dot so you can distinguish it from a capture variable. Scala allows matching against bound variables but requires it either start with an uppercase letter or be surrounded in backtics in the pattern. I don't know that that would make sense for python, but there could potentially be some special syntax to spicify you want to compare against an existing variable instead of capturing a new variable.
- xg15 1y agoAh, that makes sense. Maybe the "exceptions" (dots, uppercase letters, etc) are needed to permit bound variables that we usually don't think of as variables at all, like class or package identifiers?
- nikisweeting 1y agoI would donate $500 to the PSF tomorrow if they added this, the lack of it is daily pain
- almostgotcaught 1y agoyou can't do this consistently across all cases without compiler assistance (see https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html or https://peps.python.org/pep-0636/#matching-builtin-classes https://peps.python.org/pep-0636/#matching-builtin-classes linked below).
- nikisweeting 1y agoperfect is enemy of good imo, dict destructuring is so valuable that I'm willing to bend some rules / add some rules to make it possible. can't we just copy whatever JS does?
- skeledrew 1y agoIf it's that valuable to you personally you can use that project to remove your "daily pain". No need to inflict the pain caused by such a thing being present in official Python. Some of us like for the language to remain highly readable.
- notpushkin 1y ago> you can use that project It’s not meant for production use. Quite clearly so: https://github.com/asottile/dict-unpacking-at-home#please-dont-use-this https://github.com/asottile/dict-unpacking-at-home#please-do...
- almostgotcaught 1y ago> perfect is enemy of good imo You can't land a language feature that only sometimes works - that's absolutely horrid UX. > can't we just copy whatever JS does? I wasn't aware that js does this and I don't know it's implemented. So maybe I should retract my claim about compiler assistance.
- agumonkey 1y agoComing from lisp/haskell I always wanted destructuring but after using it quite a lot in ES6/Typescript, I found it's not always as ergonomic and readable as I thought.
- unit149 1y ago[dead]
- qwertox 1y agoThis confuses me a bit dct = {'a': [1, 2, 3]} {'a': [1, *rest]} = dct print(rest) # [2, 3] Does this mean that i can use? dct = {'a': [1, 2, 3]} {'b': [4, *rest]} = dct print(rest) # [2, 3] and more explicit dct = {'a': [1, 2, 3]} {'_': [_, *rest]} = dct print(rest) # [2, 3]
- qexat 1y agoNone of the last two LHSes will match `dct`, so you'll get a runtime error.
- masklinn 1y ago> Does this mean that i can use? They'll both trigger a runtime error, since the key you're using in the pattern (LHS) does not match any key in the dict. Note that `'_'` is an actual string, and thus key, it's not any sort of wildcard. Using a bare `_` as key yields a syntax error, I assume because it's too ambiguous for the author to want to support it.
- deleted 1y ago[deleted]
- odyssey7 1y agoPython needs a better dictionary. Also, Python needs better names for things than dict.
- nikisweeting 1y agoIn the meantime I find myself resorting to these: - https://pypi.org/project/python-benedict/ https://pypi.org/project/python-benedict/ - https://docs.pydantic.dev/ https://docs.pydantic.dev/ - https://github.com/alexmojaki/sorcery https://github.com/alexmojaki/sorcery
- yde_java 1y agoI use the Python package 'sorcery' [0] in all my production services. It gives dict unpacking but also a shorthand dict creation like this: from sorcery import dict_of, unpack_keys a, b = unpack_keys({'a': 1, 'b': 42}) assert a == 1 assert b == 42 assert dict_of(a, b) == {'a': 1, 'b': 42} [0] https://github.com/alexmojaki/sorcery https://github.com/alexmojaki/sorcery
- john-radio 1y agoThat seems a bit crazy and like it would lead to unpredictable and hard-to-mantain code. (pardon my candor).
- rrishi 1y agoim curios why you think so ?
- notpushkin 1y agoSo I see asottile has gone from backporting released features [1] to backporting unreleased ones! [1]: https://pypi.org/p/future-fstrings https://pypi.org/p/future-fstrings, mentioned in https://github.com/asottile/dict-unpacking-at-home#please-dont-use-this https://github.com/asottile/dict-unpacking-at-home#please-do...
- xg15 1y agoLame: Submit a PEP, campaign for community support, write a patch, go back and forth with the maintainers, endure weeks and months of bikeshedding, then maybe, eventually have your feature included in the next Python release. Game: Use the codec hack, immediately publish your feature for all Python versions, then write "please do not use" to be safe.
- sametmax 1y agoAnthony is also the maintainer of the deadsnake ppa, if you were searching for reasons to love him more.
- mixmastamyk 1y agoBelieve he’s the same person who won’t allow pyflakes to support # noqa, because it’s “opinionated.” As if dropping that word is some sort of justification. I don’t know what the opinion is! Worse is better?
- ziofill 1y agoThe confusing bit to me is that the LHS of this {greeting, thing} = dct is a set, which is not ordered, so why would greeting and thing be assigned in the order in which they appear?
- xg15 1y agoI don't think they are. They are matched by variable names, so this: {thing, greeting} = dct Should have the exact same result.
- frollogaston 1y agoAfter using JS, Python dicts and objects feel so cumbersome. I don't see why they need to be separate things, and why you can't access a dict like `dict.key`. Destructuring is the icing on the cake. In JS, it even handles the named args use case like const foo = ({name, age, email}) => { } I'm guessing all of this has been proposed in Python before, and rejected in part because at this point it'd create way more confusion than it's worth.
- tkcranny 1y agoI don’t mind the distinction of it as a map container keeping dot properties/methods separate from the keyed values. But yeah the endless string quoting is painful coming back from JS, bare key literals in constructors like JS would be a welcome addition for sure, as would named key unpacking like this whole post is about.
- dogukancey 1y ago[dead]
- zdimension 1y agoDid not know that such things could be accomplished by registering a new file coding format. Reminds me of https://pypi.org/project/goto-statement/ https://pypi.org/project/goto-statement/
- crabbone 1y agoI think there's a package to treat Jupyter notebooks as source code (so you can import them as modules). While the OP package is obviously a joke, the one with notebooks is kind of useful. And, of course, obligatory quote about how languages that don't have meta-programming at the design level will reinvent it, but poorly.
- Y_Y 1y agoYou talking about this? https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Importing%20Notebooks.html https://jupyter-notebook.readthedocs.io/en/stable/examples/N...
- xg15 1y agoI'd argue "import from notebooks" is still only helpful in the "space bar heating" sense. I think Notebooks are great for quick, "explorative" sketches of code. They are absolutely terrible for organizing "production" code. I know it often happens that something starts in a notebook and then sort of morphs into a generic script or full-on application. But I think, this is usually the signal you should refactor, pull out the "grown" parts from the notebooks and organize them into proper Python modules. If you have parts that are still experimental or explorative, consider importing your new modules into the notebook instead of the other way around. Source: personal experience
- zahlman 1y agoThis one is arguably even more of a hack; it's working at the source code level rather than the AST level. The "coding" here is a bytes-to-text encoding. The Python lexer expects to see character data; you get to insert arbitrary code to convert the bytes to characters (or just use existing schemes the implement standards like UTF-8).
- nine_k 1y agoIn short, it runs a text preprocessor as the source text decoder (like you would decode from Latin-1 or Shift-JIS to Unicode).
- agumonkey 1y agoyeah that's the funny part here, would never have thought of this
- tkcranny 1y agoYeah I had totally forgotten about this. I remember seeing it around a bit in the python 2 days when UTF-8 wasn’t always assumed. The fact a ~macro system can be bolted on using this is impressive, hilarious, and shockingly terrible.
- zelphirkalt 1y agoI found dictionary unpacking to be quite useful, when you don't want to mutate things. Code like: new_dict = {**old_dict, **update_keys_and_values_dict} Or even complexer: new_dict = { **old_dict, **{ key: val for key, val in update_keys_and_values_dict if key not in some_other_dict } } It is quite flexible.
- peter422 1y agoI love the union syntax in 3.9+: new_dict = old_dict | update_keys_and_values_dict
- parpfish 1y agoDon’t forget the in place variant! the_dict |= update_keys_and_values_dict
- masklinn 1y agoNo no, do forget about it: like += for lists, |= mutates “the dict”, which often makes for awkward bugs. And like += over list.extend, |= over dict.update is very little gain, and restricts legal locations (augmented assignments are statements, method calls are expressions even if they return "nothing")
- IgorPartola 1y agoThe |= does exactly what it says on the tin. How could it not mutate the left side of the assignment?
- parpfish 1y agoIn typed languages, I’m all about using nice safe immutable variables/values. But in python, everything is mutable so there’s only so much safety you can wring out of adhering the an immutable style. Any other function can hop in and start mutating things (even your “private” attributes). Plan for mutations occurring everywhere.
- sco1 1y agoThe author also has an accompanying video: https://youtu.be/eqiM0xRmFJg https://youtu.be/eqiM0xRmFJg
- andy99 1y agodef u(**kwargs): return tuple(kwargs.values()) Am I missing something, is this effectively the same? *I realize the tuple can be omitted here
- sischoel 1y agoOr use itemgetter: >>> from operator import itemgetter >>> dct = {'greeting': 'hello', 'thing': 'world', 'farewell': 'bye'} >>> thing, greeting = itemgetter("thing", "greeting")(dct) >>> thing 'world' >>> greeting 'hello'
- deleted 1y ago[deleted]
- giingyui 1y ago[dead]
- notpushkin 1y agoOhhh, nice. Also, attrgetter (which also supports dotted notation to get nested attrs! Sadly, no dotted notation for itemgetter.) https://docs.python.org/3/library/operator.html#operator.attrgetter https://docs.python.org/3/library/operator.html#operator.att...
- sischoel 1y agoDotted notation would not work because the keys in a dict can also contain dots. I am not terrible familiar with them but there is something called `lenses` that comes from functional programming that should allow you to access nested structures. And I am pretty sure there must be at least one python library that implements that.
- masklinn 1y agoTFA looks things up by key, and allows pulling a subset of the dict.
- Grikbdl 1y ago