Hence the former can be used in contexts like "if x := 10: pass", which is the whole point of the PEP.
Hence the former can be used in contexts like "if x := 10: pass", which is the whole point of the PEP.
if (match := re.match(r1, s)):
o = match.group(1)
elif (match := re.match(r2, s)):
o = match.group(1)
That doesn't seem possible (see my sibling comments). You might be able to write a different program, which might be similar (e.g. same return value, most of the time), but I don't think there's anything that's equivalent.
This is an important distinction! For example, let's say you're given a program that uses a lot of `x := y` expressions. You're asked to back-port this to an older Python version, which doesn't have `x := y`. What do you do? If there's an equivalent expression, you can just swap them out; you could even automate it with a keyboard macro, since there's no need to think about it.
If, on the other hand, you only know how to write similar code, you can't be as confident. Some examples of where "similar" programs can end up behaving differently are:
- The application makes heavy use of threading
- There are lots of magic methods defined, like `__getattribute__`, which can alter the meaning of common Python expressions (e.g. `foo.bar`)
- Those magic methods cause global side effects which the program relies on, so that they have to get triggered in the correct order
- The program manipulates implementation features, like `locals()`, `func_globals`, `__class__`, etc.
- The software is a library, which must accept arbitrary values/objects given by users
- It makes use of hashes, e.g. to check for data in an existing database, and those hashes may depend on things like the order of insertion into internal properties
Whilst it's perfectly reasonable to curse whoever wrote such monstrous code, that doesn't help us backport it. We would have to tread very carefully, and write lots of tests.
> I'd prefer more lines for readability reasons
Verbosity and readability are not the same thing. Overly verbose code might have easier to understand parts, whilst obscuring the big picture of what it's actually doing. A classic example is assembly: each instruction is pretty easy, e.g. "add the value of register A to register B", "jump to the location stored in register C if register B is non-positive", etc. Yet we can pluck a page of disassembled machine code from, say, the middle of LibreOffice and have no idea what problem it's meant to be solving. (I posted a rant about this at https://news.ycombinator.com/item?id=16223583 ).
match = re.match(r1, s)
if match:
o = match.group(1)
else:
match = re.match(r2, s)
if match:
o = match.group(1)
or a bit shorter: match = re.match(r1, s)
if not match:
match = re.match(r2, s)
if match:
o = match.group(1)
You could also just loop: for pattern in (r1, r2, ...):
match = re.match(pattern, s)
if match:
o = match.group(1)
break
else:
do_failure_handling()
But this goes a bit beyond the original question. if (match := re.match(r1, s)):
o = match.group(1)
# plus some code here
elif (match := re.match(r2, s)):
o = match.group(2)
# plus some other code here
In this case only your first solution works, I think. Leaving aside that having those deeply nested ifs is incredibly ugly, I find it hard to accept that something which completely changes the possible structure of the code is just "syntactic sugar".But the overall question is: when is the sugar just syntactical, and at what point does it become a complete new taste?
re.match shouldn't return None at all. I often write helper functions like:
matcher = lambda r, s: getattr(re.match(r, s), 'group', lambda i: '')
o = matcher(r1, s)(1) or matcher(r2, s)(3)
here matcher have a fixed, static return type, string.