[Steven D'Aprano firstname.lastname@example.org responding to Paul Sokolovsky] wrote:
Let us be clear: failed matches do not affect surrounding namespaces unless you declare capture variables as global or nonglobal. They might affect the current namespace, but not surrounding namespaces. Failed matches will not leak out to surrounding namespaces. The problem is that intuitively (just like with "for"),
"case a, b if a != b:" opens a new namespace for "a" and "b". That's why I talk about "surrounding namespace". Then if a particular case matching succeeds, weak of us (myself including) expect "a" and "b" to magically appear outside the "case" too. But if the case didn't match, nope, I don't expect "a" and "b" to appear there, it's not intuitive at all ;-).
I'm getting a bit confused over when people mean "the PEP currently says" vs "the implementation probably should" vs "the PEP should additionally require" vs "the PEP should instead say".
To be more specific, I'm not sure what is intended for the 2nd or 3rd case below, which reuse a variable "bound" by the first (failed) match. Nor am I sure whether it matters that the first match fails on the guard predicate, instead of immediately on the match.
case (a, b, c) if f(): # assume f() returns false
case (a, b) if a == c: # is a still bound from case above? Is that implementation-dependent?
case (d = a): # is a still bound from case above? Is that implementation-dependent? Is it even still possible to put restrictions in before the guard clause, like d=4?
My previous belief was that this was implementation defined, because the cases could be processed in parallel, so that the first case might not have finished by the time variable a was needed in the later cases. My reading of PEP 634 suggests that there is a linearization, but only of the guards, so ... now I am not sure.