NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
Dict Unpacking in Python (github.com)
xg15 2 hours ago [-]
Lame: 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.

notpushkin 3 hours ago [-]
So I see asottile has gone from backporting released features [1] to backporting unreleased ones!

[1]: https://pypi.org/p/future-fstrings, mentioned in https://github.com/asottile/dict-unpacking-at-home#please-do...

kristjansson 13 hours ago [-]
While 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

xg15 2 hours ago [-]
Looks 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.
thayne 1 minutes ago [-]
It 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.

1 hours ago [-]
zdimension 17 hours ago [-]
Did not know that such things could be accomplished by registering a new file coding format. Reminds me of https://pypi.org/project/goto-statement/
zahlman 17 hours ago [-]
This 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).

almostgotcaught 35 minutes ago [-]
> it's working at the source code level rather than the AST level.

this (lexing) is the only use of the codec hack - if you want to manipulate the AST you do not need this and can just to `ast.parse` and then recompile the function.

crabbone 8 hours ago [-]
I 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 5 hours ago [-]
17 hours ago [-]
yde_java 5 hours ago [-]
I 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
john-radio 4 hours ago [-]
That seems a bit crazy and like it would lead to unpredictable and hard-to-mantain code. (pardon my candor).
zelphirkalt 17 hours ago [-]
I 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 15 hours ago [-]
I love the union syntax in 3.9+:

  new_dict = old_dict | update_keys_and_values_dict
parpfish 14 hours ago [-]
Don’t forget the in place variant!

  the_dict |= update_keys_and_values_dict
masklinn 11 hours ago [-]
No 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 4 hours ago [-]
The |= does exactly what it says on the tin. How could it not mutate the left side of the assignment?
masklinn 55 minutes ago [-]
> The |= does exactly what it says on the tin. How could it not mutate the left side of the assignment?

The normal way? If the LHS is an integer. |= updates the binding but does not mutate the object.

Nothing requires that |= mutate the LHS let alone do so unconditionally (e.g. it could update the LHS in place as an optimisation iff the refcount indicated that was the only reference, which would optimise the case where you create a local then update it in multiple steps, but would avoid unwittingly updating a parameter in-place).

edit: you might not be understanding what dict.__ior__ is doing:

  >>> a = b = {}
  >>> c = {1: 2}
  >>> b |= c
  >>> a
  {1: 2}
That is, `a |= b` does not merely desugar to `a = a | b`, dict.__ior__ does a `self.update(other)` internally before updating the binding to its existing value. Which also leads to this fun bit of trivial (most known from list.__iadd__ but "working" just as well here):

  >>> t = ({},)
  >>> t[0] |= {1: 2}
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: 'tuple' object does not support item assignment
  >>> t
  ({1: 2},)
parpfish 2 hours ago [-]
In 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.

graemep 23 minutes ago [-]
I find the fewer mutations the easier code is to understand, at the level of an individual function.

Of course you do not have the safety you would have in a language that enforces immutability, but there is still a cost (in terms of maintenance and the likelihood of bugs) to mutation.

sametmax 1 hours ago [-]
Anthony is also the maintainer of the deadsnake ppa, if you were searching for reasons to love him more.
nine_k 17 hours ago [-]
In short, it runs a text preprocessor as the source text decoder (like you would decode from Latin-1 or Shift-JIS to Unicode).
agumonkey 12 hours ago [-]
yeah that's the funny part here, would never have thought of this
sco1 16 hours ago [-]
The author also has an accompanying video: https://youtu.be/eqiM0xRmFJg
agumonkey 12 hours ago [-]
Coming 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.
qwertox 10 hours ago [-]
This 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]
masklinn 6 hours 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.

qexat 7 hours ago [-]
None of the last two LHSes will match `dct`, so you'll get a runtime error.
nikisweeting 13 hours ago [-]
I would donate $500 to the PSF tomorrow if they added this, the lack of it is daily pain
IshKebab 9 hours ago [-]
You shouldn't be using dicts for data that you know the name of anyway - use dataclasses or named tuples. Dicts are best for things with keys that are not known at compile time.
IgorPartola 3 hours ago [-]
Since when can you use data classes for kwargs? There are plenty of times when you should use a dict even if you know the keys.
IshKebab 3 hours ago [-]
You shouldn't be using kwargs! That is also well known to be bad practice (or it should be anyway).

https://medium.com/codex/stop-using-kwargs-as-method-argumen...

http://ivory.idyll.org/blog/on-kwargs.html

Give me another one.

almostgotcaught 37 minutes ago [-]
lol i think you didn't read/understand this - the article is about **kwargs (which is sometimes sloppy) while the person you're responding to is talking about "exploding" a dict when calling a function (this does not require **kwargs at all).
almostgotcaught 12 hours ago [-]
you can't do this consistently across all cases without compiler assistance (see https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html or https://peps.python.org/pep-0636/#matching-builtin-classes linked below).
nikisweeting 12 hours ago [-]
perfect 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 11 hours ago [-]
If 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 3 hours 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-do...

almostgotcaught 11 hours 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.

crabbone 8 hours ago [-]
Now come on... for code golf? Why on Earth would anyone want extra syntax in a language with already tons of bloat in the syntax that contribute nothing to language's capabilities? It's, in Bill Gates words, like paying to make airplanes heavier...

This package is a funny gimmick, to illustrate, probably, unintended consequences of some of the aspects of Python's parser. Using this for anything other than another joke is harmful...

7 hours ago [-]
andy99 16 hours ago [-]

  def u(**kwargs):
    return tuple(kwargs.values())
Am I missing something, is this effectively the same?

*I realize the tuple can be omitted here

Izkata 16 hours ago [-]
You have to pull them out by key name, and not just get everything. Here's a working version, though with a totally different syntax (to avoid having to list the keys twice, once as keys and once as resulting variable names):

  >>> def u(locals, dct, keys):
  ...     for k in keys:
  ...         locals[k] = dct[k]
  ... 
  >>> dct = {'greeting': 'hello', 'thing': 'world', 'farewell': 'bye'}
  >>> u(locals(), dct, ['greeting', 'thing'])
  >>> greeting
  'hello'
  >>> thing
  'world'
  >>> farewell
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  NameError: name 'farewell' is not defined

Modifying locals() is generally frowned upon, as there's no guarantee it'll work. But it does for this example.
sischoel 11 hours ago [-]
Or use itemgetter:

  >>> from operator import itemgetter
  >>> dct = {'greeting': 'hello', 'thing': 'world', 'farewell': 'bye'}
  >>> thing, greeting = itemgetter("thing", "greeting")(dct)
  >>> thing
  'world'
  >>> greeting
  'hello'
notpushkin 3 hours ago [-]
Ohhh, 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.att...

giingyui 8 hours ago [-]
There are so many things like this one in the standard library that it kinda pisses me off when I discover a new one.
11 hours ago [-]
Grikbdl 16 hours ago [-]
Yours relies on ordering, OP's presumably does not.
masklinn 11 hours ago [-]
TFA looks things up by key, and allows pulling a subset of the dict.
unit149 12 hours ago [-]
[dead]
odyssey7 7 hours ago [-]
Python needs a better dictionary. Also, Python needs better names for things than dict.
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 16:38:35 GMT+0000 (Coordinated Universal Time) with Vercel.