[Python-ideas] Re: Variadic generics PEP draft

2020-11-28 Thread David Foster

On 10/7/20 2:11 PM, Greg Ewing wrote:

Generally looks good to me, although the name ListVariadic seems a
bit jargony (and worse, appears to be jargon imported from another
language). I think something like TypeListVar would be clearer.


Agreed. (I was just about to write my own comment saying the same thing.)

I was thinking "TypeVarList" originally, but I also like "TypeListVar".

--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/G2QFW2DOUWMIUK64VQ55DRX2UKP6YUML/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: async types?

2020-11-28 Thread David Foster

On 11/25/20 2:19 AM, Ben Avrahami wrote:
All too often I see the following pattern in asyncio 3rd-party libs, 
either in their own source code or in the inusage:

```
inst = SomeClass()
await inst.initialize()
```

[...]  allowing simply for `instance = await
SomeClass()`. In classes of `AsyncType`, the __new__ and __init__ 
methods must be async methods (returning coroutines).


I like the idea in principle but I don't currently use any async 
libraries so my opinion may not count much here. ;)


--
David Foster | Seattle, WA, USA
___
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/UQFOOGBQJOF7EES46NWEO5WV4QZOHREM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Alternative to Callable Annotation

2020-11-28 Thread David Foster

On 11/28/20 9:31 AM, Guido van Rossum wrote:
> I'm not so keen on the square brackets you propose. How about we write
> Callable[[x, y], z] as (x, y) -> z instead?

I also like the "(x, y) -> z" syntax a bit better than "[x, y -> z]". (+0.5)


On 11/28/20 3:46 PM, Guido van Rossum wrote:
> You could parenthesize the return value if you think it's not clear.
> (IIRC some functional languages like Haskell use the ... -> ... -> ...
> notation to indicate functions of multiple arguments, so it's probably
> good to avoid looking like that -- even if it'sconsistent it would
> mislead people into thinking that Python uses a similar idiom.

To avoid the "... -> ... -> ... " ambiguity, I'd suggest that kind of 
chaining be recognized and treated as a syntax error. If describing a 
Callable that itself returned another Callable, it would then be 
necessary to parenthesize the return value:


A function that has two Callables as arguments and a Callable return
type would then look like:

f: ((int, str) -> int, (…) -> str) -> ((str) -> int)

(It's worth noting that I don't think either the original "Callable[[x, 
y], z]" syntax OR the proposed "(x, y) -> z" syntax is particularly 
readable when lots of nesting is involved, but I suspect that's just 
because the type is just complicated. :) )



On 11/28/20 10:02 AM, Abdulla Al Kathiri wrote:
> Regardless of how it’s done, the less we depend on the typing module for
> annotations, the better I think because it encourages python users to
> annotate their functions.

Indeed. (+1)

--
David Foster | Seattle, WA, USA
___
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/EHZWQXXO4ANRXF6K7NHWSD3HYD5V7VWM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Matching TypedDicts and other values in JSON

2020-11-23 Thread David Foster

On 11/22/20 10:15 AM, Guido van Rossum wrote:
> - We intentionally don't support things like `isinstance(x, List[str])`
> because that would require checking all the items with `isinstance(item,
> str)`, and that seems a speed trap. Reverting this decision would be
> hard work.

Aye. I imagine many folks would expect isinstance() to be "fast" and 
altering

it to do recursive checks on its argument would lose its current O(1) time.

I imagine I *could* implement my own kind of isinstance() that would 
work on
TypedDict values that would still be recognized by typecheckers. Say I 
write

an implementation for the following method:

from typing import Optional, Type, TypeVar, TypedDict

TD = TypeVar(bound=TypedDict)

def try_cast(type: Type[TD], value: object) -> Optional[TD]:
"""Returns `value` if it can be parsed as a `type`, otherwise 
None."""

raise NotImplementedError()

Then I could use that method in a similar way as my earlier example to parse
a value very concisely:

if (shape := try_cast(Shape, request.json)) is not None:
draw_shape(shape)  # is narrowed to Shape
else:
return HTTPResponse(status=400)  # Bad Request

Going further, I could extend try_cast() to accept any (non-None) JSON-like
value as the top-level object (not just TypedDicts):

from typing import Dict, List, Optional, Type, TypeVar, TypedDict, 
Union


TD = TypeVar('TD', bound=TypedDict)
JsonValue = Union[
TD,
Dict[str, 'OptionalJV'],
List['OptionalJV'],
Dict,  # heterogeneous Dict
List,  # heterogeneous List
float,
int,  # because json.loads may return an int when parsing a number
str,
bool,
]
JV = TypeVar('JV', bound=JsonValue)
OptionalJV = TypeVar('OptionalJV', bound=Union[JsonValue, None])

def try_cast(type: Type[JV], value: object) -> Optional[JV]:
"""Returns `value` if it can be parsed as a `type`, otherwise 
None."""

raise NotImplementedError()

Now, I'm not sure if mypy can handle that kind of recursive TypedDict
definition :), but it *will* work at runtime.

I'll see about implementing a function like try_cast() as a separate 
package.

This should be fun. :)

--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/QSWAXFCOVRDCJZPIOTI336MJRSU7L45G/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Matching TypedDicts and other values in JSON

2020-11-21 Thread David Foster
ng a PEP to extend 
isinstance()

to cover at least the above cases, would that be welcome?

--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/Y2EJEZXYRKCXH7SP5MDF3PT2TYIB7SJS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 634-636: Mapping patterns and extra keys

2020-11-21 Thread David Foster

On 11/19/20 10:08 PM, David Foster wrote:
I've completed my survey of how other languages use pattern matching to 
match Mapping-like and dict-like types, especially focusing on whether 
they ignore (픸) or disallow (픹) extra keys by default. [...]


To close the loop on this thread:

* Based on (1) the explanation from PEP 622 and Guido RE that  "mappings 
[...] have natural structural sub-typing behavior, i.e., passing a 
dictionary with extra keys somewhere will likely just work" and (2) the 
survey results, I'm now personally fine (+0) with keys being ignored by 
default when matching against mappings.



* I do think it might be illustrative to copy the following explanatory 
sentences from the "Mapping Patterns" section of the older PEP 622 to 
the same section of PEP 635 (Structural Pattern Matching: Motivation and 
Rationale):


> Extra keys in the subject are ignored even if **rest is not present. 
This is different from sequence pattern, where extra items will cause a 
match to fail. But mappings are actually different from sequences: they 
have natural structural sub-typing behavior, i.e., passing a dictionary 
with extra keys somewhere will likely just work.


Specifically the above might replace the following sentence in PEP 635, 
which doesn't really give a rationale:


> Moreover, the mapping pattern does not check for the presence of 
additional keys.



* I still have an interest in strictly matching dictionaries that are 
destined to become TypedDicts, but I can take that conversation to a 
different thread.


--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/K5BUKMOCIBUQIITBUQNX6KEHOB4WB5BC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 634-636: Mapping patterns and extra keys

2020-11-19 Thread David Foster

On 11/15/20 12:11 AM, Steven D'Aprano wrote:

It would be good if the PEP gave a survey of the practical experience of
other languages with pattern matching:

- are there languages which require an exact match, with no left over
   keys? what issues, if any, do users have with that choice?

- which languages ignore extra keys? do users of those languages
   consider this feature a bug, a wart, or a feature?


If useful I can volunteer to conduct such a survey. I expect to have 
some cycles this coming weekend.


I've completed my survey of how other languages use pattern matching to 
match Mapping-like and dict-like types, especially focusing on whether 
they ignore (픸) or disallow (픹) extra keys by default.


In general:

1. Dynamically-typed languages that support pattern matching have mostly 
experimental (†) pattern-matching implementations that all ignore extra 
keys by default (픸) rather than disallow them (픹). Some popular 
dynamically-typed languages don't support pattern-matching at all (✖️).

- Erlang/Elixir are the only languages in this category with a
  non-experimental implementation.
- Ruby and JavaScript both have experimental implementations only.

2. Statically-typed languages frequently provide pattern matching 
capabilities but they can't be used for Mapping-like or dict-like types 
(路‍♀️). Frequently the pattern matching provided *can* however be used 
on association lists (ordered lists of key-value tuples) or 
dataclass-like instances.


So it certainly seems at least the popular vote points toward ignoring 
extra keys by default rather than disallowing them by default, which is 
consistent with the current wording of PEP 634-636.


Below is the full survey summary:

Key:
* Pattern Match Approach
픸 = Pattern-matches mappings/dicts, ignoring extra keys by default
픹 = Pattern-matches mappings/dicts, disallowing extra keys by 
default
路‍♀️ = Has pattern matching, but doesn't apply to a 
Mapping-like or dict-like types
✖️ = Has no pattern matching for algebraic data types (but 
might for strings)

* Maturity
† = Pattern-matching syntax is advertised as "experimental"

Dynamically-typed languages:
* Erlang
픸
* Elixir (derived from Erlang)
픸
* Ruby (2.7)
픸†
* JavaScript (TC39 draft)
픸†
* PHP
✖️
* Lua
✖️
* Python (current draft of PEP 634-636)
픸†

Statically-typed languages:
* OCaml
路‍♀️
* Scala
路‍♀️
* Swift
路‍♀️
* Rust
路‍♀️
* Haskell
路‍♀️
* C++
    路‍♀️

--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/JNQD3CJD4B5LEBT3N4BNMBQ6WDDGLGTZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 634-636: Mapping patterns and extra keys

2020-11-17 Thread David Foster

On 11/15/20 12:11 AM, Steven D'Aprano wrote:

It would be good if the PEP gave a survey of the practical experience of
other languages with pattern matching:

- are there languages which require an exact match, with no left over
   keys? what issues, if any, do users have with that choice?

- which languages ignore extra keys? do users of those languages
   consider this feature a bug, a wart, or a feature?


If useful I can volunteer to conduct such a survey. I expect to have 
some cycles this coming weekend.


--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/WBTOEFRUWB2MQWZ7OTJB6ME2IMSZXTPM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 634-636: Mapping patterns and extra keys

2020-11-14 Thread David Foster

On 11/14/20 10:17 PM, Guido van Rossum wrote:
It’s a usability issue; mappings are used quite differently than 
sequences. Compare to class patterns rather than sequence patterns.


I just found the following explanation from the superceded PEP 622 as to 
why extra keys are ignored:


> Extra keys in the subject are ignored even if **rest is not present. 
This is different from
> sequence pattern, where extra items will cause a match to fail. But 
mappings are actually
> different from sequences: they have natural structural sub-typing 
behavior, i.e., passing a

> dictionary with extra keys somewhere will likely just work.

I suppose this makes sense when using "match" to work with a dictionary 
used as a lightweight object, which I expect would be relatively common.


The examples I originally presented assume use of "match" for parsing, 
and parsing tends to default to stricter matching. :)


--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
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/YGN47RMUHK642TCVA32GWI3OBQIIEKZV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] PEP 634-636: Mapping patterns and extra keys

2020-11-14 Thread David Foster

From PEP 636 (Structural Pattern Matching):
> Mapping patterns: {"bandwidth": b, "latency": l} captures the 
"bandwidth" and "latency" values from a dict. Unlike sequence patterns, 
extra keys are ignored.


It surprises me that ignoring extra keys would be the *default* 
behavior. This seems unsafe. Extra keys I would think would be best 
treated as suspicious by default.


* Ignoring extra keys loses data silently. In the current proposal:

point = {'x': 1, 'y': 2, 'z': 3)
match point:
case {'x': x, 'y': y}:  # MATCHES, losing z  O_O
pass
case {'x': x, 'y': y, 'z': z}:  # will never match  O_O
pass

* Ignoring extra keys is inconsistent with the handling of sequences: We 
don't allow extra items when using a destructuring assignment to a sequence:


p = [1, 2]
[x, y] = p
[x, y, z] = p  # ERROR: ValueError: not enough values to unpack 
(expected 3, got 2)  :)


* Ignoring extra keys in mapping patterns is inconsistent with the 
current proposal for how sequence patterns match data:


point = [1, 2, 3]
match point:
case [x, y]:  # notices extra value and does NOT match  :)
pass
case [x, y, z]:  # matches :)
pass

* Ignoring extra keys is inconsistent with TypedDict's default "total" 
matching behavior:


from typing import TypedDict

class Point2D(TypedDict):
x: int
y: int

p1: Point2D = {'x': 1, 'y': 2}
p2: Point2D = {'x': 1, 'y': 2, 'z': 3)  # ERROR: Extra key 'z' for 
TypedDict "Point2D"  :)


* It is *possible* to force an exact key match with a pattern guard but 
it's clumsy to do so.

  It should not be clumsy to parse strictly.

point = {'x': 1, 'y': 2, 'z': 3)
match point:
# notices extra value and does NOT match, but requires ugly 
guard :/

case {'x': x, 'y': y, **rest} if rest == {}:
pass
case {'x': x, 'y': y, 'z': z, **rest} if rest == {}:
pass


To avoid the above problems, **I'd advocate for disallowing extra keys 
in mapping patterns by default**. For cases where extra keys want to be 
specifically allowed and ignored, I propose allowing a **_ wildcard.



Some examples that illustrate behavior when *disallowing* extra keys in 
mapping patterns:


1. Strict parsing

from typing import TypedDict, Union

Point2D = TypedDict('Point2D', {'x': int, 'y': int})
Point3D = TypedDict('Point3D', {'x': int, 'y': int, 'z': int})

def parse_point(point_json: dict) -> Union[Point2D, Point3D]:
match point_json:
case {'x': int(x), 'y': int(y)}:
return Point2D({'x': x, 'y': y})
case {'x': int(x), 'y': int(y), 'z': int(z)}:
return Point3D({'x': x, 'y': y, 'z': z})
case _:
raise ValueError(f'not a valid point: {point_json!r}')

2. Loose parsing, discarding unknown data.
   Common when reading JSON-like data when it's not necessary to output 
it again later.


from typing import TypedDict

TodoItem_ReadOnly = TypedDict('TodoItem_ReadOnly', {'title': str, 
'completed': bool})


def parse_todo_item(todo_item_json: Dict) -> TodoItem_ReadOnly:
match todo_item_json:
case {'title': str(title), 'completed': bool(completed), **_}:
return TodoItem_ReadOnly({'title': title, 'completed': 
completed})

case _:
raise ValueError()

input = {'title': 'Buy groceries', 'completed': True, 
'assigned_to': ['me']}
print(parse_todo_item(input))  # prints: {'title': 'Buy groceries', 
'completed': True}


3. Loose parsing, preserving unknown data.
   Common when parsing JSON-like data when it needs to be round-tripped 
and output again later.


from typing import Any, Dict, TypedDict

TodoItem_ReadWrite = TypedDict('TodoItem_ReadWrite', {'title': str, 
'completed': bool, 'extra': Dict[str, Any]})


def parse_todo_item(todo_item_json: Dict) -> TodoItem_ReadWrite:
match todo_item_json:
case {'title': str(title), 'completed': bool(completed), 
**extra}:
return TodoItem_ReadWrite({'title': title, 'completed': 
completed, 'extra': extra})

case _:
raise ValueError()

def format_todo_item(item: TodoItem_ReadWrite) -> Dict:
return {'title': item['title'], 'completed': item['completed'], 
**item['extra']}


input = {'title': 'Buy groceries', 'completed': True, 
'assigned_to': ['me']}

output = format_todo_item(parse_todo_item(input))
print(output)  # prints: {'title': 'Buy groceries', 'completed': 
True, 'assigned_to': ['me']}



Comments?

--
David Foster | Seattle, WA, USA
Contributor to TypedDict support for mypy
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https

Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-04 Thread David Foster
I have seen a ton of discussion about what dict addition should do, but 
have seen almost no mention of dict difference.


This lack of discussion interest combined with me not recalling having 
needed the proposed subtraction semantics personally makes me wonder if 
we should hold off on locking in subtraction semantics just yet. Perhaps 
we could just scope the proposal to dictionary addition only for now?


If I *were* to define dict difference, my intuition suggests supporting 
a second operand that is any iterable of keys and not just dicts. 
(Augmented dict subtraction is already proposed to accept such a broader 
second argument.)


David Foster | Seattle, WA, USA

On 3/1/19 8:26 AM, Steven D'Aprano wrote:

Attached is a draft PEP on adding + and - operators to dict for
discussion.

This should probably go here:

https://github.com/python/peps

but due to technical difficulties at my end, I'm very limited in what I
can do on Github (at least for now). If there's anyone who would like to
co-author and/or help with the process, that will be appreciated.




___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators: operators ?= and ?? and OR

2018-08-02 Thread David Foster

RE none-aware operators in general:
+1 overall for the latest version of PEP 505 and the utility of ?? in 
particular. There are several places in my code that could be simplified 
with ??.


find-pep505.py on my current Django-oriented codebase gives:
Total None-coalescing `if` blocks: 43
Total [possible] None-coalescing `or`: 4
Total None-coalescing ternaries: 8
Total Safe navigation `and`: 0
Total Safe navigation `if` blocks: 6
Total Safe navigation ternaries: 17

RE OR and ||:
* -1 for "OR" as an operator. Insufficiently distinct from "or". Reads 
the same out loud despite being a different operator.
* -1 for "||" with none-aware semantics. This differs from the semantics 
in every C-derived language I can think of, which will be confusing to 
several other developers.


David Foster | Seattle, WA, USA

On 7/19/18 5:30 AM, Jonathan Fine wrote:

Hi


There is a formatted version of this PEP at
https://www.python.org/dev/peps/pep-0505/


I've taken a look at this, and have some comments on the first two
examples drawn from standard library code. (And a very grateful +10
for writing a script to find such examples.)

I've started a subthread, just to discuss the ?= and ?? operators. And
something newish, that I call OR.

FIRST EXAMPLE
The first example is
---
 From bisect.py:
def insort_right(a, x, lo=0, hi=None):
 # ...
 if hi is None:
 hi = len(a)
---

Here, None is a sentinel value. The simpler code
---
   hi = hi or len(a)
---
fails when hi is zero (or any other value that is False in the boolean context).

This can be fixed by introducing a new operator OR which is similar to
'or' but has the semantics this example requires. Thus, given OR we
can write
---
   hi = hi OR len(a)
---
where (A OR B) returns A if A is not None, otherwise it returns B.

(Recall that (A or B) returns A if bool(A), otherwise it returns B.)

SECOND EXAMPLE
The second example is
---
 From calendar.py:
encoding = options.encoding
if encoding is None:
 encoding = sys.getdefaultencoding()
optdict = dict(encoding=encoding, css=options.css)
---

Once we have OR we would write this as
---
encoding = encoding OR sys.getdefaultencoding()
optdict = dict(encoding=encoding, css=options.css)
---

And from here we can condense into a single (longish) line:
---
optdict = dict(encoding=encoding OR sys.getdefaultencoding(), css=options.css)
--

SUMMARY
Here, for reference, are the suggestions using ?= and ?? in PEP 505.
---
hi ??= len(a)
---
optdict = dict(encoding=encoding ?? sys.getdefaultencoding(), css=options.css)
---

Comments ?? suggestions. For example, would a None-aware AND operator be useful?


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] The future of Python parallelism. The GIL. Subinterpreters. Actors.

2018-07-10 Thread David Foster
I was not aware of PyParallel. The PyParellel "parallel thread" 
line-of-execution implementation is pretty interesting. Trent, big kudos 
to you on that effort.


Since you're speaking in the past tense and said "but we're not doing it 
like that", I infer that the notion of a parallel thread was turned down 
for integration into CPython, as that appears to have been the original 
goal.


However I am unable to locate a rationale for why that integration was 
turned down. Was it deemed to be too complex to execute, perhaps in the 
context of providing C extension compatibility? Was there a desire to 
see a similar implementation on Linux as well as Windows? Some other 
reason? Since I presume you were directly involved in the discussions, 
perhaps you have a link to the relevant thread handy?


The last update I see from you RE PyParallel on this list is:
https://mail.python.org/pipermail/python-ideas/2015-September/035725.html

David Foster | Seattle, WA, USA

On 7/9/18 9:17 AM, Trent Nelson wrote:

On Sun, Jul 08, 2018 at 11:27:08AM -0700, David Foster wrote:


I'd like to solicit some feedback on what might be the most
efficient way to make forward progress on efficient parallelization
in Python inside the same OS process. The most promising areas
appear to be:


You might find PyParallel interesting, at least from a "here's what was
tried, it worked, but we're not doing it like that" perspective.

 http://pyparallel.org
 
https://speakerdeck.com/trent/pyparallel-how-we-removed-the-gil-and-exploited-all-cores

I still think it was a pretty successful proof-of-concept regarding
removing the GIL without having to actually remove it.  Performance was
pretty good too, as you can see in those graphs.


--
David Foster | Seattle, WA, USA


Regards,

 Trent.

--
https://trent.me


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 572 version 2: Statement-Local Name Bindings

2018-03-17 Thread David Foster
I mean approximately local to one line of source code. Perhaps the
unpopular opinion based on your reaction. :)

More specifically, for a simple statement (with no trailing colon), there
is one scope enclosing everything in the statement. For a compound
statement, composed of multiple clauses, where each clause has a header
(ending with a colon) and a suite, there are N non-overlapping scopes, one
scope for each of the N clause headers. The scope is limited to the header
only and does not include the suite.


In considering a 'for' loop, I'd advocate for keeping the scope of the
expression_list separate from the target_list, since I can't think of a
reasonable case where the target_list would want to reference something
from the expression_list. So the following code would have a NameError for
magic_index in the target_list:

> # NameError: name 'magic index' is not defined
> for my_array[magic_index] in list_of_lists[(f(...) as magic_index)]:
> ...

That's pretty bizarre code, using a fixed index of an array as an iteration
variable. The only other type of 'for' loop target that might try to use a
named expression from the expression_list is a slice expression, which
would be even more bizarre code. Best to make bizarre cases into errors.


Cheers,
--
David Foster | Seattle, WA, USA


On Sat, Mar 17, 2018 at 12:13 AM, Chris Angelico <ros...@gmail.com> wrote:

> On Sat, Mar 17, 2018 at 5:49 PM, David Foster <davidf...@gmail.com> wrote:
> > (3a) With a header-limited scope (in proposal #1 above), I advocate that
> a
> > named expression should NOT be able to shadow other variables, giving a
> > SyntaxError. I can't think of a reasonable reason why such shadowing
> should
> > be allowed, and preventing shadowing may eliminate unintentional errors.
>
> Header-limited scope is hard to define. Do you mean expression-local?
> (Also hard to define.) Do you mean local to one line of source code?
> Definitely not. And what happens with a 'for' loop - part of its
> header gets run after each loop iteration but still kinda references
> stuff that was done once-only before the loop started.
>
> ChrisA
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 
David Foster
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 572 version 2: Statement-Local Name Bindings

2018-03-17 Thread David Foster
(1) I am concerned with the proposal's ability to introduce variables with
a new broader kind of multi-line scope not seen anywhere else in Python. It
is difficult to reason about, particularly in constructs like lambdas and
inline def functions.

Limiting scope to the very same line is great:

> stuff = [[(f(x) as y), x/y] for x in range(5)]

However I advocate that named expressions should ONLY be usable in the
header of statements that enclose other statements. Thus I would expect the
following to be an error:

> if (re.match(...) as m):
> print(m.groups(0))  # NameError: name 'm' is not defined

> while (sock.read() as data):
> print("Received data:", data)  # NameError: name 'data' is not defined

Using the named expression in other parts of the statement header is still
fine:

> if (re.match(...) as m) is not None and m.groups(1) == 'begin':
> ...

In summary, -1 from me for introducing a new kind of sublocal scope. +0
from me for keeping the scope limited to the header of the statement.
Predictable conservative semantics.


(2) If there WAS a desire to allow a named expression inside the
substatements of a compound statement, I would advocate that the named
expression just be treated as a regular (usually-)local variable
assignment, with scope that extends to the entire function. This would
imply that the variable would appear in locals().

Under this interpretation, the following would be okay:

> while (sock.read() as data):
> print("Received data:", data)
> print("Last received data:", data)  # ok; data is a regular local

I would be -0 for using a regular local scope for a named expression.
Predictable semantics but leaks the expression to the wider scope of the
function.


(3a) With a header-limited scope (in proposal #1 above), I advocate that a
named expression should NOT be able to shadow other variables, giving a
SyntaxError. I can't think of a reasonable reason why such shadowing should
be allowed, and preventing shadowing may eliminate unintentional errors.

(3b) With a local scope (in proposal #2 above), a named expression simply
replaces any preexisting local with the same name. (Or it would replace the
global/nonlocal if a global/nonlocal statement was in use.) There is no
shadowing per-se.


Cheers,
--
David Foster | Seattle, WA, USA



On Fri, Mar 2, 2018 at 3:43 AM, Chris Angelico <ros...@gmail.com> wrote:

> After dozens of posts and a wide variety of useful opinions and
> concerns being raised, here is the newest version of PEP 572 for your
> debating pleasure.
>
> Formatted version:
>
> https://www.python.org/dev/peps/pep-0572/
>
> There are now several more examples, greater clarity in edge cases,
> and improved wording of the actual proposal and specifications. Also,
> the reference implementation has been significantly enhanced, for
> those who wish to try this themselves.
>
> ChrisA
>
> PEP: 572
> Title: Syntax for Statement-Local Name Bindings
> Author: Chris Angelico <ros...@gmail.com>
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 28-Feb-2018
> Python-Version: 3.8
> Post-History: 28-Feb-2018, 02-Mar-2018
>
>
> Abstract
> 
>
> Programming is all about reusing code rather than duplicating it.  When
> an expression needs to be used twice in quick succession but never again,
> it is convenient to assign it to a temporary name with small scope.
> By permitting name bindings to exist within a single statement only, we
> make this both convenient and safe against name collisions.
>
>
> Rationale
> =
>
> When a subexpression is used multiple times in a list comprehension, there
> are currently several ways to spell this, none of which is universally
> accepted as ideal. A statement-local name allows any subexpression to be
> temporarily captured and then used multiple times.
>
> Additionally, this syntax can in places be used to remove the need to
> write an
> infinite loop with a ``break`` in it.  Capturing part of a ``while`` loop's
> condition can improve the clarity of the loop header while still making the
> actual value available within the loop body.
>
>
> Syntax and semantics
> 
>
> In any context where arbitrary Python expressions can be used, a named
> expression can appear. This must be parenthesized for clarity, and is of
> the form ``(expr as NAME)`` where ``expr`` is any valid Python expression,
> and ``NAME`` is a simple name.
>
> The value of such a named expression is the same as the incorporated
> expression, with the additional side-effect that NAME is bound to that
> value in all retrievals for the remainder of the current statement.
>
> Just as function-local names shadow global names for the scope of the
> funct

Re: [Python-ideas] Coming up with an alternative to PEP 505's None-aware operators

2018-02-19 Thread David Foster
(1) This proposal serves well to eliminate repeated computations by 
allowing what is an inline assignment to a temporary variable. But it 
doesn't seem to make the case of None-aware operators any less verbose 
than they would be otherwise.


Proposal:
value = ?it.strip()[4:].upper() if (?it=var1) is not None else None
Traditional:
it = var1
value = it.strip()[4:].upper() if it is not None else None

If we wanted to get rid of the "if it is not None else None" 
boilerplate, we'd need something more concise. For example - completely 
off the cuff - syntax like:

value = var1?.strip()[4:].upper()

I'm not really interested in going down a rabbit hole of discussing 
those kinds of syntax alternatives on this thread. I just want to point 
out that the current proposal don't seem to make None-aware operations 
much more concise than they were before except in the case of complex 
subexpressions being None-tested, which I find uncommon in my own programs.


(2) In considering the proposal in the alternative light of specifically 
trying to eliminate complex subexpressions, I'll also put a +1 in for 
(expr as it) rather than (?it=) since I find it reads nicer. Also is 
consistent with existing syntax (with expr as var).


Cheers,
David

--
David Foster | Seattle, WA, USA

On 2/15/18 6:06 PM, Nick Coghlan wrote:

The recent thread on variable assignment in comprehensions has
prompted me to finally share
https://gist.github.com/ncoghlan/a1b0482fc1ee3c3a11fc7ae64833a315 with
a wider audience (see the comments there for some notes on iterations
I've already been through on the idea).

== The general idea ==

The general idea would be to introduce a *single* statement local
reference using a new keyword with a symbolic prefix: "?it"

* `(?it=expr)` is a new atomic expression for an "it reference
binding" (whitespace would be permitted around "?it" and "=", but PEP
8 would recommend against it in general)
* subsequent subexpressions (in execution order) can reference the
bound subexpression using `?it` (an "it reference")
* `?it` is reset between statements, including before entering the
suite within a compound statement (if you want a persistent binding,
use a named variable)
* for conditional expressions, put the reference binding in the
conditional, as that gets executed first
* to avoid ambiguity, especially in function calls (where it could be
confused with keyword argument syntax), the parentheses around
reference bindings are always required
* unlike regular variables, you can't close over statement local
references (the nested scope will get an UnboundLocalError if you try
it)

The core inspiration here is English pronouns (hence the choice of
keyword): we don't generally define arbitrary terms in the middle of
sentences, but we *do* use pronouns to refer back to concepts
introduced earlier in the sentence. And while it's not an especially
common practice, pronouns are sometimes even used in a sentence
*before* the concept they refer to ;)

If we did pursue this, then PEPs 505, 532, and 535 would all be
withdrawn or rejected (with the direction being to use an it-reference
instead).

== Examples ==

`None`-aware attribute access:

value = ?it.strip()[4:].upper() if (?it=var1) is not None else None

`None`-aware subscript access:

value = ?it[4:].upper() if (?it=var1) is not None else None

`None`-coalescense:

value = ?it if (?it=var1) is not None else ?it if (?it=var2) is
not None else var3

`NaN`-coalescence:

value = ?it if not math.isnan((?it=var1)) else ?it if not
math.isnan((?that=var2)) else var3

Conditional function call:

value = ?it() if (?it=calculate) is not None else default

Avoiding repeated evaluation of a comprehension filter condition:

filtered_values = [?it for x in keys if (?it=get_value(x)) is not None]

Avoiding repeated evaluation for range and slice bounds:

range((?it=calculate_start()), ?it+10)
data[(?it=calculate_start()):?it+10]

Avoiding repeated evaluation in chained comparisons:

value if (?it=lower_bound()) <= value < ?it+tolerance else 0

Avoiding repeated evaluation in an f-string:

print(f"{?it=get_value()!r} is printed in pure ASCII as {?it!a}
and in Unicode as {?it}"

== Possible future extensions ==

One possible future extension would be to pursue PEP 3150, treating
the nested namespace as an it reference binding, giving:

sorted_data = sorted(data, key=?it.sort_key) given ?it=:
def sort_key(item):
return item.attr1, item.attr2

(A potential bonus of that spelling is that it may be possible to make
"given ?it=:" the syntactic keyword introducing the suite, allowing
"given" itself to continue to be used as a variable name)

Another possible extension would be to combine it references with `as`
clauses on if statements and while loops:

if (?it=pattern.match(data))