os.getpid

getpid() works everywhere and getppid() on Unix and Windows. The process-group and session calls (getpgid, getpgrp, getsid, setpgid, setpgrp, setsid) are Unix only: they let a shell or supervisor put children in their own group so one signal reaches the whole group.

os functionPython 3.0+ (getppid on Windows 3.2+)
Common call
os.getpid()
Returns
int: the id of the current process
Replaces
reading /proc/self or $$ in shell scripts
Watch out
All threads share one pid; pids are reused after a process exits
os.getpid() / os.getppid() / os.getpgid(pid) / os.getpgrp() / os.getsid(pid, /) / os.setpgid(pid, pgrppgrp — setpgid only: the target process group id; 0 means use pid as the group id.type: int · required, /) / os.setpgrp() / os.setsid()
→ int

Parameters

NameTypeRequiredDescription
pidintyesgetpgid / getsid / setpgid: the process to ask about or change; 0 means the calling process.
pgrpintyessetpgid only: the target process group id; 0 means use pid as the group id.

Return value

int — getpid / getppid / getpgid / getpgrp / getsid: an id. The set* calls return None.

Common patterns

Tag log lines with the pid
Distinguish worker processes in a shared log.
import logging
logging.basicConfig(format='%(process)d %(levelname)s %(message)s')
Run a child in its own session (Unix)
start_new_session=True calls setsid() in the child, detaching it from your terminal and process group.
import subprocess
proc = subprocess.Popen(['long-job'], start_new_session=True)
Signal a whole process group (Unix)
Put the child in a new group, then signal the group, so its own children stop too.
import os, signal, subprocess
proc = subprocess.Popen(['server'], process_group=0)
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
Classic daemon step (Unix)
After fork, the child becomes a session leader with no controlling terminal.
import os
if os.fork() == 0:
    os.setsid()
    ...

Examples

1. A positive int
import os isinstance(os.getpid(), int) and os.getpid() > 0
Returns
True
2. A child sees us as its parent
import os, sys, subprocess out = subprocess.run([sys.executable, '-c', 'import os; print(os.getppid())'], capture_output=True, text=True).stdout.strip() out == str(os.getpid())
Returns
True
3. A child has its own pid
import os, sys, subprocess out = subprocess.run([sys.executable, '-c', 'import os; print(os.getpid())'], capture_output=True, text=True).stdout.strip() out != str(os.getpid())
Returns
True
4. Threads share the process id
import os, threading seen = [] t = threading.Thread(target=lambda: seen.append(os.getpid())) t.start() t.join() seen[0] == os.getpid()
Returns
True
5. Process groups exist only on Unix
import os all(hasattr(os, n) == (os.name == 'posix') for n in ('getpgid', 'getpgrp', 'getsid', 'setpgid', 'setpgrp', 'setsid'))
Returns
True
6. multiprocessing names the main process
import multiprocessing multiprocessing.current_process().name
Returns
'MainProcess'

Pitfalls

1. Using the pid to tell threads apart
Every thread of a process has the same pid. Use threading.get_ident() or threading.get_native_id() for threads.
os.getpid()
import os, threading
seen = []
t = threading.Thread(target=lambda: seen.append(os.getpid()))
t.start()
t.join()
seen[0] != os.getpid()
False
get_native_id()
import threading
seen = []
t = threading.Thread(target=lambda: seen.append(threading.get_native_id()))
t.start()
t.join()
seen[0] != threading.get_native_id()
True
2. Building unique file names from the pid
Two threads, or a later process that reuses the pid, get the same name. tempfile picks a name that is guaranteed new.
f'job-{pid}.tmp'
import os
names = [f'job-{os.getpid()}.tmp' for _ in range(2)]
names[0] == names[1]
True
tempfile
import os, tempfile
fds = [tempfile.mkstemp(dir='.', prefix='job-') for _ in range(2)]
for fd, _ in fds:
    os.close(fd)
fds[0][1] == fds[1][1]
False

When to use

Use it
  • Logging and debugging which process did something
  • Checking whether you are still the original process after fork (compare a saved pid)
  • Unix job control: own process group or session for a child or daemon
Reach for something else
  • New sessions / groups for children → subprocess.Popen(start_new_session=True) or process_group=0 (Unix)
  • Identifying threads → threading.get_ident() / get_native_id()
  • Unique names → tempfile or uuid.uuid4()

Notes

CPython impl
Direct wrappers of getpid(2), getppid(2), getpgid(2), getpgrp(2), getsid(2), setpgid(2), setpgrp(2) / setpgrp(0, 0) and setsid(2)
Availability
getpid: all platforms (a stub on WASI). getppid: Unix, Windows (Windows since 3.2). getpgid, getpgrp, getsid, setpgid, setpgrp, setsid: Unix only
getppid
When the parent has exited, Unix returns the pid of the init process (1); Windows keeps returning the old parent id, which may already belong to another process
Errors
getpgid of a pid that does not exist raises ProcessLookupError (errno ESRCH)

FAQ

A pid is different on every run and machine. getpid and getppid work on Unix and Windows; the process-group and session functions are Unix only (docs: Availability: Unix, not WASI). The examples compare pids with each other instead of printing them.