Python os.set_inheritable 函数
上次修改时间:2025 年 4 月 11 日
这份全面的指南探讨了 Python 的 os.set_inheritable
函数,该函数控制跨进程创建的文件描述符继承。我们将涵盖继承标志、进程管理和实际示例。
基本定义
os.set_inheritable
函数设置文件描述符的继承标志。这决定了子进程是否可以继承该描述符。
关键参数:fd(文件描述符),inheritable(布尔标志)。 返回 None。 在具有不同底层实现的 Unix 和 Windows 系统上可用。
基本用法示例
此示例演示了在生成子进程之前将文件描述符设置为可继承。子进程将继承打开的文件。
import os # Create a temporary file fd = os.open("test.txt", os.O_RDWR | os.O_CREAT) # Make the file descriptor inheritable os.set_inheritable(fd, True) # Spawn a child process pid = os.fork() if pid == 0: # Child process print(f"Child process with PID {os.getpid()}") os.write(fd, b"Written by child\n") os.close(fd) else: # Parent process print(f"Parent process with PID {os.getpid()}") os.waitpid(pid, 0) # Wait for child os.lseek(fd, 0, os.SEEK_SET) print("File content:", os.read(fd, 100)) os.close(fd) os.unlink("test.txt")
父进程创建一个文件并在分叉之前将其设置为可继承。 然后,两个进程都可以写入同一个文件描述符。
这演示了父进程和子进程之间的基本继承行为。
阻止继承
此示例展示了如何防止文件描述符被子进程继承。 这对于安全敏感的文件操作很有用。
import os # Open a sensitive file fd = os.open("secret.txt", os.O_RDONLY) # Explicitly prevent inheritance os.set_inheritable(fd, False) # Spawn child process pid = os.fork() if pid == 0: # Child process try: # Attempt to read from the file print(os.read(fd, 100)) except OSError as e: print(f"Child failed to access file: {e}") finally: os._exit(0) else: # Parent process os.waitpid(pid, 0) print("Parent can still read:", os.read(fd, 100)) os.close(fd)
父进程打开一个文件但阻止继承。 子进程无法访问文件描述符,而父进程保留访问权限。
此技术有助于保护敏感资源免受子进程的访问。
使用管道的继承
此示例演示了管道文件描述符的继承行为,这些文件描述符通常用于进程间通信。
import os # Create a pipe r, w = os.pipe() # Set read end as inheritable os.set_inheritable(r, True) pid = os.fork() if pid == 0: # Child process os.close(w) # Close write end print("Child received:", os.read(r, 100)) os.close(r) else: # Parent process os.close(r) # Close read end os.write(w, b"Message from parent") os.close(w) os.waitpid(pid, 0)
父进程创建一个管道并将读取端设置为可继承。 子进程继承读取描述符,可以从父进程接收数据。
管道是受控描述符继承的常见用例。
检查继承状态
此示例展示了如何使用 os.get_inheritable
检查文件描述符的当前继承状态。
import os fd = os.open("temp.txt", os.O_RDWR | os.O_CREAT) # Check default inheritance status print("Default inheritable:", os.get_inheritable(fd)) # Change and verify status os.set_inheritable(fd, True) print("After setting True:", os.get_inheritable(fd)) os.set_inheritable(fd, False) print("After setting False:", os.get_inheritable(fd)) os.close(fd) os.unlink("temp.txt")
该代码打开一个文件并检查其默认继承状态。 然后它修改并验证状态更改。
这演示了如何动态检查和修改继承标志。
与子进程的继承
此示例展示了文件描述符继承如何与 Python 的 subprocess
模块一起工作。
import os import subprocess # Create a file and make inheritable fd = os.open("output.txt", os.O_RDWR | os.O_CREAT) os.set_inheritable(fd, True) # Launch subprocess with inherited descriptor proc = subprocess.Popen( ["python3", "-c", f"import os; os.write({fd}, b'Written by subprocess\\n')"], pass_fds=[fd] ) proc.wait() # Verify content os.lseek(fd, 0, os.SEEK_SET) print("File content:", os.read(fd, 100)) os.close(fd) os.unlink("output.txt")
父进程打开一个文件并显式地将其传递给一个子进程。 子进程继承该描述符并写入该文件。
这演示了使用 Python 的更高级别进程 API 进行的受控继承。
Windows 特定的行为
此示例重点介绍了 set_inheritable
的 Windows 特有行为,其中继承的工作方式与 Unix 系统不同。
import os import sys if sys.platform != "win32": print("This example is for Windows only") sys.exit(1) # On Windows, inheritance must be set at creation time import msvcrt fd = os.open("winfile.txt", os.O_RDWR | os.O_CREAT) # Windows requires setting inheritable flag at creation handle = msvcrt.get_osfhandle(fd) print(f"Original handle inheritable: {msvcrt.HANDLE(handle).inheritable}") # Try to modify inheritance (may not work as expected) os.set_inheritable(fd, True) print(f"After set_inheritable: {msvcrt.HANDLE(handle).inheritable}") os.close(fd) os.unlink("winfile.txt")
在 Windows 上,继承标志通常在句柄创建时设置。 与 Unix 系统相比,set_inheritable
的效果可能有限。
这演示了描述符继承中的重要平台差异。
安全注意事项
- 最小权限: 只需将必要的描述符设置为可继承
- 平台差异: Windows 和 Unix 处理继承的方式不同
- 资源泄漏: 继承的描述符必须正确关闭
- 竞争条件: 在进程创建之前设置继承标志
- 替代方法: 考虑更高级别的 IPC 机制
最佳实践
- 显式控制: 始终显式设置继承标志
- 清理: 确保所有进程中都进行正确的描述符清理
- 文档: 明确记录继承要求
- 测试: 验证所有目标平台上的行为
- 替代方案: 考虑使用管道或套接字进行 IPC
资料来源
作者
列出所有 Python 教程。