3

Is it possible to do something like the following Perl code in Python? From what I can tell the answer is no, but I figured I'd double check.

The Perl code I want to replicate in Python:

#!/usr/bin/perl

my $line = "hello1234world";

if($line=~/hello(.*)world/) {
  print($1);
}
#prints 1234    

The following is the closest stylistically I can think off, but when running I (obviously) get the following error:

import re
line = "hello1234world"

if matchObj = re.match(r'hello(.*)world',line):
    print(matchObj.group(1))

#error: if matchObj = re.match(r'hello(.*)world',line):
#error:             ^
#error: SyntaxError: invalid syntax

The following is the best working code I can come up with:

import re
line = "hello1234world"

matchObj = re.match(r'hello(.*)world',line)

if matchObj:
    print(matchObj.group(1))
#prints 1234

I'd really like to avoid a separate line for the variable declaration and if statement if possible.

noah
  • 2,418
  • 7
  • 21
  • 4
    This syntax is possible through [assignment expressions](https://www.python.org/dev/peps/pep-0572/) (`:=`), available for Python 3.8+. – Rfroes87 Sep 24 '20 at 01:15
  • 2
    Does this answer your question? [How do Assignment Expressions \`:=\` work in Python?](https://stackoverflow.com/questions/54544744/how-do-assignment-expressions-work-in-python) – Rfroes87 Sep 24 '20 at 01:27
  • 1
    I don't see how this is supposed to be a duplicate of the linked page. Just because that is about `:=`? That question and answer are pretty much unrelated to what is asked here. There's probably pages where this question is answered, but not the selected one in my opinion. Voted to reopen. – zdim Sep 24 '20 at 09:21

1 Answers1

5

Can just print the (assumed) capture and use exceptions to handle the case when group method is called on None, returned when there isn't a match. If there is indeed nothing to do when the match fails it's one line via With Statement Context Manager (3.4+)

from contextlib import suppress

with suppress(Exception):
    print( re.match(r'hello(.*)world', line).group(1) )

To avoid ignoring exceptions that almost surely shouldn't be ignored here, like SystemExit and KeyboardInterrupt, use

with suppress(BaseException):
    ...

This is now rather compact, as asked for, and it behaves as desired. Using exceptions merely to shorten code could be considered misguided though, but perhaps there'd be further uses of this.

As mentioned in comments, since 3.8 there is the Assignment Expression

if match := re.match(r'hello(.*)world', line):
    print( match.group(1) )

which matches almost directly the motivating semantics. However, this newer feature has drawn some sensitive discussions, while using it to merely shorten code may confuse and mislead as it differs from an expected pythonic approach.

I'd like to add, that I'd suggest to not worry about a few extra lines of code, and specially to avoid emulating styles and program flow from other languages. There is a huge value in using styles and idioms native to the language at hand.

zdim
  • 53,586
  • 4
  • 45
  • 72
  • I am unfortunately using version 3.6.0 (out of my control - work's environment controls) so the assignment expression is not an option for me (but cool to know that it is theoretically possible in some versions. Never seen it before). Based on your answer it seems like I am best off just having a few extra lines and keeping it pythonic. I think suppressing exceptions is just asking for maintenance problems down the road when the code gets handed off. – noah Sep 24 '20 at 18:58
  • @noah I agree, and that's what I'd do. Write good Python (well, or try to :). Whatever number of lines that is. This applies to any language. In this case I'm not aware of a clean/idiomatic approach, that would be more concise, other than what you show in Q. – zdim Sep 26 '20 at 05:04