Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Creating Pipes With Popen

00:00 Earlier in the course, you learned about pipes and how to simulate a pipe using run(). Now, we did cover back then that this was not a real pipe, but the simulation of a pipe.

00:12 To create a real pipe, we will need to use Popen(). So let’s move on to the Popen class.

00:20 Now, Popen firstly stands for pipe open. Earlier in the course, you also learned that Popen is the underlying class, for the whole subprocess module.

00:31 So what that means is that all the functions are convenience wrappers around the Popen() constructor or the Popen class. And you should use run() for all cases it can handle, that’s what the documentation says.

00:45 But there might be situations that are a bit more complex, a bit more edgy for which you will use Popen. And creating real pipes is one of those situations.

00:55 Now run() is based on Popen. run() again is a convenience wrapper around the Popen() constructor or the Popen class.

01:03 So using run() and using Popen, that’s very similar, but there are some key differences that you will discover in this video. Now firstly, let’s start by refreshing your memory on how to simulate a pipe using run().

01:20 This is the code that we went through before and you’ll remember the simulation of the pipe by setting the input of the grep process to be the output or the stdout of the ls process.

01:35 Now let’s have a look at the code using Popen and what the key differences are. So in the second screen here, this is the code using Popen() and just for convenience, I’m leaving the code using run() visible at the top.

01:50 So instead of run(), we will use Popen(). Everything else here is the same, but for the grep process, again, we’re going to use Popen().

02:00 And here is a key difference. Instead of saying input and assigning the stdout of the ls process to input, we are assigning it to stdin.

02:13 Now that is quite a difference. The rest of the line is the same. Now why is that a difference? Because the stdin here expects a stream as an input and not a bytes object.

02:25 This touches on a few key differences here and let’s take a step back.

02:30 So the first key difference we spotted is that Popen() actually is written with a capital whereas run() is not.

02:37 The second piece is that Popen() is not a blocking call. Now, earlier in the course when we talked about run(), it was said that run() is a blocking call.

02:48 So what that means is that run() waits for the process to be finished before the program continues. That is not the case with Popen().

02:58 With Popen(), the two processes are running in parallel. So here we have the ls process and the grep process. They are running in parallel. So that is a key difference.

03:09 The other key difference is that the run() function returned a completed process, whereas the Popen() constructor returns a Popen object and those are very different objects.

03:22 Now, the Popen object has as its stdout a stream, an actual stream, whereas run(), which returns a CompletedProcess object, the stdout there is a bytes object as you have seen earlier in the course.

03:39 So now because the output, the stdout, is not a bytes object but a stream, you’ll need a loop to read the stdout while the process is running.

03:50 And that is what we are doing here. This is quite a crucial difference because the fact that your stdout is an actual stream, and the fact that the processes are running in parallel, that means that you can communicate between the processes while they are running and that is very different from run().

04:10 And that is also why you can create an actual pipe as opposed to simulate a pipe.

04:17 So all that’s left to do now is to run the code and see what it does. Press Enter, press Enter again, and I get these four lines. Remember, these are filenames that have the word python in it, and just to prove that that’s what was happening here as well.

04:33 There you go. That is the simulation of the pipe giving us the same output.

04:40 Okay, let’s just summarize the differences between run() and Popen(). Firstly, run() is a blocking call, whereas Popen() is a non-blocking call.

04:49 So run() will wait for the process to finish before the program continues, whereas Popen() will have processes run in parallel.

04:58 run() returns a CompletedProcess object of which stdout is a bytes object, whereas Popen() returns a Popen object of which the stdout and the standard stream attributes are actual streams and therefore with run(), you can only simulate a pipe.

05:17 But with Popen you can create actual pipes.

05:23 As a final point, the use of subprocess with actual pipes and parallel processes can become quite complex. So if you are considering complex use of subprocess that goes beyond run(), there is a module called asyncio and I will include a link to an excellent tutorial and that is a module that will help you along your journey.

05:47 That’s it for introduction to Popen(). Now it’s time to gather your thoughts and think about all you have learned during this course. The course summary is up next.

Become a Member to join the conversation.