Game: Use the codec hack, immediately publish your feature for all Python versions, then write "please do not use" to be safe.
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.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.
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).
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.
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.
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
[1]: https://pypi.org/p/future-fstrings, mentioned in https://github.com/asottile/dict-unpacking-at-home#please-do...
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 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. new_dict = old_dict | update_keys_and_values_dict
the_dict |= update_keys_and_values_dict
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")
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},)
This behavior is congruent to C++ and it’s documented and idiomatic.
It’d be weird if the in-place operator deeply copied the LHS, and problematic for a garbage-collected language in high throughput applications.
It’s the default behaviour of |= if you override |, you need to specifically override |= to do otherwise.
> This behavior is congruent to C++
An excellent reason to do something else in and of itself.
> it’s documented and idiomatic.
Documenting a trap does not make it less of a trap. Innocently replacing | by |= induces a massive behavioural change which the user has little reason to expect, and which can easily lead to bugs due to mutating shared data.
> It’d be weird if the in-place operator deeply copied the LHS
I see you understand neither Python nor the behaviour of the | operator.
> problematic for a garbage-collected language in high throughput applications.
dict.update exists, if you specifically need to update the LHS in place it works just fine.
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.
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.
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. 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]
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.
As if dropping that word is some sort of justification. I don’t know what the opinion is! Worse is better?
https://medium.com/codex/stop-using-kwargs-as-method-argumen...
http://ivory.idyll.org/blog/on-kwargs.html
Give me another one.
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.
It’s not meant for production use. Quite clearly so: https://github.com/asottile/dict-unpacking-at-home#please-do...
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...
Not saying it needs to be done with the decoder hack, it should have proper compiler support, but it's basically necessary. It's the best feature in JS hands down.
>> a, b = 2, 3 # say
>> d = dict_of(a, b)
>> d
{"a": 2, "b": 3}
>> # somewhere else...
>> { a, b } = d
>> a + b
5
The dict_of() function is already possible at runtime with python `ast` magic, see [1]. That package also has unpack_keys() again made possible with `ast`, but we'd of course want proper language support.{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?
{thing, greeting} = dct
Should have the exact same result. def u(**kwargs):
return tuple(kwargs.values())
Am I missing something, is this effectively the same?*I realize the tuple can be omitted here
>>> 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. >>> from operator import itemgetter
>>> dct = {'greeting': 'hello', 'thing': 'world', 'farewell': 'bye'}
>>> thing, greeting = itemgetter("thing", "greeting")(dct)
>>> thing
'world'
>>> greeting
'hello'
https://docs.python.org/3/library/operator.html#operator.att...
- https://pypi.org/project/python-benedict/ - https://docs.pydantic.dev/ - https://github.com/alexmojaki/sorcery