Q:

Why does subprocess.popen behave differently as a single statement?

When attempting a subprocess.Popen call to get the return code of a command, I get different results depending on whether I break the call up into distinct statements or not. I'm not tied up on making it work as a single statement anymore, but I am not able to articulate why this is the case and want to know more (if it's possible to get a single statement then obviously all the better).
What I wanted to do was the following:
my_variable = subprocess.Popen(
  'ip addr show ens192 | grep master',
  shell=True).communicate().returncode

Which yields:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'returncode'

However when I take the same logic and break it across several lines, it works:
>>> my_variable = subprocess.Popen('ip addr show ens192 | grep master', shell=True)
>>> my_variable.communicate()
(None, None)
>>> my_variable.returncode
1
>>>

Why is this? This is not behavior I'm used to with Python and I am guessing it has something to do with how it is running the command under the hood.

A:

returncode is an attribute of Popen, not of the tuple returned by communicate().
Therefore my_variable.returncode works, because my_variable is the Popen instance.
On the other hand subprocess.Popen(...).communicate().returncode doesn't work, because, while subprocess.Popen(...) is the Popen instance, subprocess.Popen(...).communicate() evaluates to a tuple (None, None) returned by communicate, not the Popen instance it was called on.
The tuple does not have an attribute returncode as the error message tells you.
Your problem is merely a confusion of what communicate() returns. It does not return the Popen instance that it was called on. This is not an issue of the inner workings or semantics of Popen.

