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.
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
| Name | Type | Required | Description |
|---|---|---|---|
| pid | int | yes | getpgid / getsid / setpgid: the process to ask about or change; 0 means the calling process. |
| pgrp | int | yes | setpgid 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
True2. 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
True3. 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
True4. 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
True5. 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
True6. 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.