[Python-ideas] Re: A “big picture” question.
I would note that the accepted [PEP 626](https://peps.python.org/pep-0626/) explicitly constrains line-tracing behavior: """Python should guarantee that when tracing is turned on, “line” tracing events are generated for all lines of code executed and only for lines of code that are executed.""" So even peephole optimizations should now theoretically follow PEP 626 and produce the expected line-tracing events. For example, the line "try:" typically emits a "NOP" instruction that is kept around just for the sake of tracing. If I recall correctly, there might not be 100% compliance with PEP 626 so far, but in general, things have recently gotten more well-specified and predictable in this regard, not less. The interpreter is still allowed to go wild by, e.g., executing type-specialized versions of different opcodes (PEP 659), but just not in such a way as to change language semantics, including the semantics of tracing when tracing is enabled. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/EK2HDVLAVC7B3EY7RDZTMXIGL5RYQI6J/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Syntax proposal of for..in..if in regular for loops
I've heard "evaluation map" for a related mathematical concept: the natural map from X to (X -> Y) -> Y in some cartesian closed category (whatever that means :-), like the natural embedding of a vector space into its double dual space, or like this sort of eval_at function that you can then plug into map: def eval_at(x): return lambda f: f(x) list(map(eval_at(arg), functions)) It also reminds me of a Clojure feature, where IIRC a key can be used as a function so that `(:key mymap)` and `(mymap :key)` both mean "the value in `mymap` corresponding to the key `:key`" ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YFYX76ORCN4VTP2YZFWIBFIJDZ7MF7XZ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Make 10**400 / 1e200 work?
The non-associativity isn't just signed zeros: regular floating point addition and multiplication of positive numbers is not associative from math import nextafter x = nextafter(1.0, 2.0) print((x+x)+1.0, x+(x+1.0)) x2 = nextafter(1.0, 0.0) print((x*x2)*x2, x*(x2*x2)) ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GJDX7OMCR3MSGX3X5JFC6UGKRSYPGX6Y/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: String method to check for a float
I don't know how common it is to want to distinguish between string representations of integers and those of floats. It seems like a function that could have a million little variations: What if my boss says that now my input integers can have commas? Or have extra space added? Or if integer-valued floats should be considered integers? What if we run into localization issues with a commas-versus-periods-as-decimal-separator? What if we want to start accepting fractions like "22/7"? What if we find dollar signs in front? What if we want to return 0 or NaN in place of None? It seems to me that with all of these possible variations, it's best to spell out in your code exactly what to do for your individual use case, using try/except as necessary. That's not to say that you shouldn't make this function in your own code -- maybe you're personally writing dozens of scripts that use exactly this function. If so, great: add it to a personal utility library and import it when you need it. But I'm not sure it's worth the bloat of giving that same function to all Python users across the world whether they want it or not. By the way, if I were implementing something like this, I would probably instead write something like def parse_value(string): try: return int(string) except ValueError: pass try: return float(string) except ValueError: return None so that all of the parsing is together, and then elsewhere in the code write isinstance(number, float) rather than passing strings around and repeatedly parsing/re-parsing with some kind of isfloat(string) operation. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/CVMAIKDQMHQSOA7IIG75TNA5TBXGW3UD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Shorthand syntax for lambda functions that have a single parameter
IIUC a lot of what is being discussed has been implemented by the "placeholder" package on PyPI Here: https://pypi.org/project/placeholder/ It allows using things like `min(data, key=_[-1])` or `_.age < 18` (just using language features instead of adding new syntax). ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JWMTOOEU3G2OWFU6XW2DXJEMS5KDONKH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Support more conversions in format string
Maybe I'm missing something, but why do you need the SimpleNamespace at all? Why not make your own mapping as in class StringMapper: ... def __getitem__(self, s): # Whatever arbitrary behavior you want # Process suffixes, etc here, for example: if s.endswith(".lc"): return self.wrapped[s.removesuffix(".lc")].lower() return self.wrapped[s] format_string.format_map(StringMapper(whatever)) Maybe then the data can just be data and this wrapper can handle all the formatting conversions. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/RDS4KL7SUAP4AAA2XVBZTM5SZE4NUU46/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Iterable scalar values returning itself ones?
Whenever you extend the definition of an operation (`__iter__` in this case) to more existing objects, you lose a little bit of the ability to catch errors early. Consider the function: def traverse(something): for x in something: # do stuff ... If you accidentally call `traverse(42)`, then right now, you catch it immediately with a TypeError on the `for x in something:` line. Under your proposal, you might just get a strange answer and not realize anything is wrong. Besides, we already have ways to write "repeat 1 ten times", using `itertools.repeat(1, times=10)`. Or if you just need any iterable with ten items, you can use range(10). I think keeping numbers non-iterable is nice based on a couple of the lines PEP 20: `Explicit is better than implicit`, and `There should be one-- and preferably only one --obvious way to do it.` ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ANFR3IQW5TJHV4JRZT5UI7VEMFL7BKX2/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Itertools generator injection
Hm maybe there is something worthwhile here. I implemented a Python version with the same semantics as itertools.product, except only consuming the iterators when absolutely necessary; still only consuming each iterator once, but building its pools incrementally. See https://gist.github.com/sweeneyde/fb6734d7b9f7d17e132c28af9ecb6270 from itertools import count it = LazyProductObject(count(0), count(0), "ab", repeat=3) assert next(it) == (0, 0, "a", 0, 0, "a", 0, 0, "a") assert next(it) == (0, 0, "a", 0, 0, "a", 0, 0, "b") assert next(it) == (0, 0, "a", 0, 0, "a", 0, 1, "a") assert next(it) == (0, 0, "a", 0, 0, "a", 0, 1, "b") assert next(it) == (0, 0, "a", 0, 0, "a", 0, 2, "a") assert next(it) == (0, 0, "a", 0, 0, "a", 0, 2, "b") It looks like it could be made to have a similar tight loop as the current implementation if we decided to re-write it in C. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/HCX35TWZRDUY7LMGLOERWPVX6ZRICWRS/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Itertools generator injection
I'm assuming things like this are what you're talking about: def lazy_product2(*args, repeat=1): "recursive algorithm" args = args * repeat if not args: yield () return for all_but_last in lazy_product2(*args[:-1]): for last in args[-1](): yield all_but_last + (last,) def lazy_product(*args, repeat=1): "non-recursive algorithm" funcs = args * repeat iterators = [iter(f()) for f in funcs] try: result = [next(it) for it in iterators] except StopIteration: return rev_range = range(len(iterators))[::-1] sentinel = object() while True: yield tuple(result) # get the next one for i in rev_range: result[i] = next(iterators[i], sentinel) if result[i] is sentinel: iterators[i] = iter(funcs[i]()) result[i] = next(iterators[i], sentinel) if result[i] is sentinel: # No new data this time around return else: # stop "carrying", we incremented one. # ready to yield. break else: # no break return import itertools assert (list(lazy_product(lambda: range(3), lambda: range(2), repeat=2)) == list(itertools.product(range(3), range(2), repeat=2)) == list(lazy_product2(lambda: range(3), lambda: range(2), repeat=2))) infinite = lazy_product(itertools.count, lambda: "abc") print([next(infinite) for i in range(10)]) # [(0, 'a'), (0, 'b'), (0, 'c'), # (1, 'a'), (1, 'b'), (1, 'c'), # (2, 'a'), (2, 'b'), (2, 'c'), # (3, 'a')] I think these don't generally fit with the "feel" of the itertools module though since almost everything there accepts iterables and returns iterators, and it's very focused on performance. Accepting no-arg callables that return iterators doesn't feel like an obvious API to me. Another option is to accept iterables that repeatedly get iter() called on them, but that's hard to make work with generators, and people confuse iterables and iterators anyway, so that might be too subtle. Maybe it's the sort of thing that just goes into a personal library of small utility functions. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NZSUEF3EJNU7YOTEYH3GUFY7M3K4QT5M/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Syntax for duplicate types in seq[...]
Does this work? >>> tuple[(int,) * 7 + (str,)] tuple[int, int, int, int, int, int, int, str] ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/R56SVGSGWTINGIFNUC2QURZKATZ34AD4/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: propose index heap
I've thought about this before too. But if I remember correctly, most real-world path-finding algorithms can use a heap without an index to achieve basically the same results: with this approach, the heap can now store more than one copy of a node, but it doesn't need to put all of the nodes in the queue at the same time. Instead of calling a "decrease-key" function on a particular node, you can just throw in a new node into the heap with the smaller key. And when you pop a node off the heap, check that you haven't already popped off and processed that node. There may be marginally worse memory usage with this approach on extremely dense graphs, but there's generally better real-world performance with a naive un-indexed heap without the decrease-key function. This version also works on infinite graphs, where putting everything in the queue at the beginning would fail. See https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm#Practical_optimizations_and_infinite_graphs The other thing to worry about is that adding a new data structure to the stdlib is not without significant costs: it adds something new to the heapq module for everyone to learn, and it prompts the question "should my heap be indexed?" for all users. Per PEP 20, "There should be one-- and preferably only one --obvious way to do it." There may be some situations where some data structures are better than the standard ones, but I feel that PyPI is a good place for those to stay. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/LV7FYOPBCDPBPDVAWRTYNNGM7K43H4SZ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Dict unpacking assignment
MRAB wrote: > The assertions could still fail because there's nothing there to say > that a0, b0 and c0 are strings, or, indeed, that there isn't a comma in > one of them. > . That's true. But that's a weakness of parsing any ambiguous pattern, even with regular expressions. It would be up to the user to make sure their pattern is not too ambiguous for their use case. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/57K67AOLVOEQQ2WGUODBMC53C7VEM44P/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Inconsistency in splitting strings
For some explanation, see this StackOverflow answer by Raymond Hettinger: https://stackoverflow.com/a/16645307/11461120 ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YFKYYJTG33LVIBXHT5YDLZLKTS4FOYMR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Dict unpacking assignment
What if the mapping assignment were more harmonious with the pattern matching PEP? Something like this: items = {'eggs': 2, 'cheese': 3, 'spam': 1} {'eggs': eggs, 'spam': i_dont_need_to_name_this_spam, **rest} = items assert i_dont_need_to_name_this_spam == 1 assert eggs == 2 and cheese == 3 assert rest == {'cheese': 3} The keys here could be arbitrary hashables and the "values" could be arbitrary assignment targets (assigned all-or-nothing). This wouldn't need the right-hand-side double-star, and I think it more closely resembles the sequence unpacking assignment syntax. You can assign to a (thing that looks like a) tuple or to a (thing that looks like a) list or to a sequence subscript or object attribute, why not be able to assign to a (thing that looks like a) dictionary? This also avoids polluting the local namespace in case one of your keys is the string "range" or something. It also feels less magical to me, albeit more verbose. Calls to a hypothetical parse/sscanf function could closely mirror some str.format() calls: text = "{a}, {b}, {c}".format(**{'a': a0, 'b': b0, 'c': c0}) {'a': a1, 'b': b1, 'c': c1} = "{a}, {b}, {c}".parse(text) assert (a1, b1, c1) == (a0, b0, c0) Alternative positional parsing would be useful as well, as in: text = "{}, {}, {}".format(a0, b0, c0) a1, b1, c1 = "{}, {}, {}".parse(text) assert (a1, b1, c1) == (a0, b0, c0) This way, pattern.format() and pattern.parse() would be trying to be inverses of each other (as much as is reasonable, probably limited to parsing strings, floats and ints). Then maybe people could get used to a format-string-like mini-language for parsing, and eventually, the f-string assignment might be better received, and we could propose something like text = f"{a0}, {b0}, {c0}" f"{a1}, {b1}, {c1}" = text assert (a1, b1, c1) == (a0, b0, c0) as well, where we lose some of the flexibility but gain better D.R.Y. and more visual locality, useful in the simple cases. I see the potential for a strong analogy: positional format() : keyword-based format() : fstrings :: positional parse() : keyword-based parse(): assignment to fstrings ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/H5252OAGH2IWEVQ26F2OWNQZCGMVNZWP/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: f-strings as assignment targets
I think it would be easiest to reason about if an Exception is always raised when not everything is assigned to. Just like the behavior of other unpacking assignment, either everything is assigned or there's an error. My apologies if that wasn't clear from the examples. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BCSI2TNFZHHWASCX6WHKNOLWWIPUWXJA/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: f-strings as assignment targets
I was definitely not proposing "spooky action at a distance". My proposal is to existing f-strings as the `__setattr__` protocol is to the `__getattr__` protocol. The template would only ever be hard-coded inline during the f-string assignment. This is the same restriction that existing f-strings have. I am suggesting a syntactic construct where f-strings can be assignment targets, not suggesting to keep track of which strings were f-strings or overriding assignment or something silly like that. Existing f-strings do not aim to replace str.format in situations where the format string is re-used. Likewise, the proposal would not aim to replace regular expression in situations where the pattern is re-used. The change would amount a syntax change for assignments: whenever an f-string is on the LHS of an assignment, the interpreter would do a parsing operation, and there would be no change to code where the f-string is in any other situation. This is again analogous to the behavior of `__getattr__` and `__setattr__`. For example, f"""{text}""" = html Would be roughly equivalent to url, text = re.fullmatch(r"""(.*)""", html).groups() The LHS is never evaluated, it's only assigned to. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/5R72K64RQUDJAZJOFUFDX6JQRSNLY5M2/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] f-strings as assignment targets
TL;DR: I propose the following behavior: >>> s = "She turned me into a newt." >>> f"She turned me into a {animal}." = s >>> animal 'newt' >>> f"A {animal}?" = s Traceback (most recent call last): File "", line 1, in f"A {animal}?" = s ValueError: f-string assignment target does not match 'She turned me into a newt.' >>> f"{hh:d}:{mm:d}:{ss:d}" = "11:59:59" >>> hh, mm, ss (11, 59, 59) === Rationale === Part of the reason I like f-strings so much is that they reduce the cognitive overhead of reading code: they allow you to see *what* is being inserted into a string in a way that also effortlessly shows *where* in the string the value is being inserted. There is no need to "paint-by-numbers" and remember which variable is {0} and which is {1} in an unnecessary extra layer of indirection. F-strings allow string formatting that is not only intelligible, but *locally* intelligible. What I propose is the inverse feature, where you can assign a string to an f-string, and the interpreter will maintain an invariant kept in many other cases: >>> a[n] = 17 >>> a[n] == 17 True >>> obj.x = "foo" >>> obj.x == "foo" True # Proposed: >>> f"It is {hh}:{mm} {am_or_pm}" = "It is 11:45 PM" >>> f"It is {hh}:{mm} {am_or_pm}" == "It is 11:45 PM" True >>> hh '11' This could be thought of as analogous to the c language's scanf function, something I've always felt was just slightly lacking in Python. I think such a feature would more clearly allow readers of Python code to answer the question "What kinds of strings are allowed here?". It would add certainty to programs that accept strings, confirming early that the data you have is the data you want. The code reads like a specification that beginners can understand in a blink. === Existing way of achieving this === As of now, you could achieve the behavior with regular expressions: >>> import re >>> pattern = re.compile(r'It is (.+):(.+) (.+)') >>> match = pattern.fullmatch("It is 11:45 PM") >>> hh, mm, am_or_pm = match.groups() >>> hh '11' But this suffers from the same paint-by-numbers, extra-indirection issue that old-style string formatting runs into, an issue that f-strings improve upon. You could also do a strange mishmash of built-in str operations, like >>> s = "It is 11:45 PM" >>> empty, rest = s.split("It is ") >>> assert empty == "" >>> hh, rest = rest.split(":") >>> mm, am_or_pm = s.split(" ") >>> hh '11' But this is 5 different lines to express one simple idea. How many different times have you written a micro-parser like this? === Specification (open to bikeshedding) === In general, the goal would be to pursue the assignment-becomes-equal invariant above. By default, assignment targets within f-strings would be matched as strings. However, adding in a format specifier would allow the matches to be evaluated as different data types, e.g. f'{foo:d}' = "1" would make foo become the integer 1. If a more complex format specifier was added that did not match anything that the f-string could produce as an expression, then we'd still raise a ValueError: >>> f"{x:.02f}" = "0.12345" Traceback (most recent call last): File "", line 1, in f"{x:.02f}" = "0.12345" ValueError: f-string assignment target does not match '0.12345' If we're feeling adventurous, one could turn the !r repr flag in a match into an eval() of the matched string. The f-string would match with the same eager semantics as regular expressions, backtracking when a match is not made on the first attempt. Let me know what you think! ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JEGSKODAK5MCO2HHUF4555JZPZ6SKNEC/ Code of Conduct: http://python.org/psf/codeofconduct/