Python 3 psutil, extracting pid and name values?

3.1k views Asked by At

For Python 3.5 on Windows 7 64-bit and the psutil 5 library.

I'm confused as to how to properly access the name and pid information provided within each class 'psutil.Process' item returned by psutil.process_iter().

The following code returns a class 'generator' object:

import psutil
curProcesses = psutil.process_iter()

A simple loop outputs each class 'psutil.Process' object contained within that generator:

for eachProcess in curProcesses:
    print(eachProcess)

OUTPUT:

psutil.Process(pid=0, name='System Idle Process')
psutil.Process(pid=4, name='System')
          ... and so on ...

Now here's where I'm getting confused.

IF I modify the previous loop as follows, THEN I'll get an integer pid and a string name.

for eachProcess in curProcesses:
    # Observe the two different forms of access.
    print(eachProcess.pid)
    print(eachProcess.name())

OUTPUT:

0
System Idle Process
4
System
... and so on ...

The resulting integer and string are exactly what I want. However, after several experiments I can only get them IF:

  • eachProcess.pid is NOT followed by parentheses ala eachProcess.pid. (Adding parentheses produces a TypeError: 'int' object is not callable exception.)

  • eachProcess.name is followed by parentheses ala eachProcess.name(). (Removing the parentheses returns a bound method Process.name instead of the name as a string.)

Why do the two keyword-looking arguments pid and name behave differently? (I suspect I'm about to learn something very useful about Python 3 generator objects...)

2

There are 2 answers

3
elethan On BEST ANSWER

There is not much to it really: pid is a read-only attribute (created with the @property decorator), and name() is a method, both of the Process class. Methods need parens to be called in order to return data, while attributes are accessed without them. This bit of documentation might be helpful. Also, if you find it helpful, you can see the difference in implementation between name() and pid.

As far as why pid is a read-only attribute of Process, while a method name() needs to be called in order to get the process name, I am not sure. In fact, pid appears to be the only read-only attrubute on the process class, while all other information about the process instance is retrieved through method calls. Personally it seems inconsistent/non-standard to do it this way, but I assume that there is a good reason for this choice. I assume the main reason is so the PID cannot be changed accidentally since it is a crucial component. If the PID were a method instead of a read-only attribute, then eachProcess.pid = 123 in your loop would change the method to the int 123, while the way it currently is, this attempted reassignment will raise an error instead, so that the PID is protected in a sense, while eachProcess.name = 'foo' will probably go by without raising an error.

Also, note that while they may look like keyword arguments in the way they appear in the string representations of Process class instances, name() and pid are not keyword arguments (although pid can be passed as a keyword argument when creating a Process instance, but that is not what is happening here).

0
Giampaolo RodolĂ  On

I made pid a class attribute / property mainly for consistency with subprocess.Popen.pid and multiprocessing.Process.pid stdlib modules (also threading.Thread.ident comes to mind).

Also, it's something which does not require any calculation (contrarily from name(), cmdline() etc.) and it never changes, so something read-only made more sense to me at the time.

It's a property rather than a mere attribute just to error out in case the user tries to change/set it.