[Python-ideas] Re: A “big picture” question.

2022-06-11 Thread Dennis Sweeney
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

2022-03-02 Thread Dennis Sweeney
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?

2022-02-24 Thread Dennis Sweeney
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

2021-10-01 Thread Dennis Sweeney
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

2021-09-29 Thread Dennis Sweeney
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

2021-05-05 Thread Dennis Sweeney
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?

2021-04-13 Thread Dennis Sweeney
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

2021-03-22 Thread Dennis Sweeney
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

2021-03-19 Thread Dennis Sweeney
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[...]

2021-02-19 Thread Dennis Sweeney
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

2020-11-05 Thread Dennis Sweeney
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

2020-10-26 Thread Dennis Sweeney
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

2020-10-26 Thread Dennis Sweeney
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

2020-10-25 Thread Dennis Sweeney
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

2020-09-18 Thread Dennis Sweeney
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

2020-09-17 Thread Dennis Sweeney
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

2020-09-17 Thread Dennis Sweeney
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/