ZetCode

Python os.get_inheritable 函数

上次修改时间:2025 年 4 月 11 日

这份全面的指南探索了 Python 的 os.get_inheritable 函数,该函数用于检查文件描述符是否可以被子进程继承。我们将涵盖文件描述符标志、继承行为和实际示例。

基本定义

os.get_inheritable 函数检查文件描述符是否被标记为可继承。可继承的描述符会被传递给子进程。

关键参数:fd(要检查的文件描述符)。如果描述符可继承,则返回 True,否则返回 False。在 Python 3.4+ 中可用。

检查标准流继承

标准流(stdin、stdout、stderr)通常是可继承的。此示例检查它们的继承状态。

std_inheritance.py
import os
import sys

# Check standard streams
print(f"stdin inheritable: {os.get_inheritable(sys.stdin.fileno())}")
print(f"stdout inheritable: {os.get_inheritable(sys.stdout.fileno())}")
print(f"stderr inheritable: {os.get_inheritable(sys.stderr.fileno())}")

# Check a regular file
with open("test.txt", "w") as f:
    print(f"Regular file inheritable: {os.get_inheritable(f.fileno())}")

此示例首先检查标准流,通常返回 True。然后它检查一个新打开的文件,该文件通常继承默认的继承设置。

结果可能因平台和 Python 进程的启动方式而异。

修改继承标志

我们可以使用 os.set_inheritable 更改继承状态,并使用 os.get_inheritable 验证更改。

modify_inheritance.py
import os

# Create a temporary file
with open("temp.txt", "w") as f:
    fd = f.fileno()
    print(f"Original inheritable: {os.get_inheritable(fd)}")
    
    # Disable inheritance
    os.set_inheritable(fd, False)
    print(f"After disabling: {os.get_inheritable(fd)}")
    
    # Re-enable inheritance
    os.set_inheritable(fd, True)
    print(f"After re-enabling: {os.get_inheritable(fd)}")

这演示了如何更改文件描述符的继承标志并验证更改。修改后文件描述符仍然有效。

请注意,更改继承只会影响新的子进程,不会影响现有的子进程。

检查管道继承

可以使用 os.pipe 创建的管道来检查继承。此示例显示了管道的读取端和写入端。

pipe_inheritance.py
import os

# Create a pipe
r, w = os.pipe()

print(f"Read end inheritable: {os.get_inheritable(r)}")
print(f"Write end inheritable: {os.get_inheritable(w)}")

# Modify one end
os.set_inheritable(r, False)
print(f"Modified read end: {os.get_inheritable(r)}")

# Clean up
os.close(r)
os.close(w)

这会创建一个管道并检查两端的继承状态。默认情况下,两端通常都是可继承的。然后,我们修改一端的状态。

始终记住在不再需要文件描述符时将其关闭。

子进程中的继承

此示例演示了继承如何影响实际的子进程行为。我们将创建一个文件并检查其在子进程中的可见性。

subprocess_inheritance.py
import os
import subprocess

# Create a test file
with open("shared.txt", "w") as f:
    fd = f.fileno()
    print(f"Before change: {os.get_inheritable(fd)}")
    
    # Test with inheritable descriptor
    subprocess.run(["python", "-c", "import os; print(os.path.exists('shared.txt'))"])
    
    # Make non-inheritable and test again
    os.set_inheritable(fd, False)
    print(f"After change: {os.get_inheritable(fd)}")
    subprocess.run(["python", "-c", "import os; print(os.path.exists('shared.txt'))"])

第一个子进程可以访问该文件,因为描述符是可继承的。禁用继承后,仍然可以通过文件系统访问该文件。

这显示了描述符继承和文件路径访问之间的区别。

与 fcntl 模块的比较

我们可以将 os.get_inheritablefcntl 模块检查描述符标志的方法进行比较。

fcntl_comparison.py
import os
import fcntl

with open("compare.txt", "w") as f:
    fd = f.fileno()
    
    # Using os.get_inheritable
    print(f"os.get_inheritable: {os.get_inheritable(fd)}")
    
    # Using fcntl
    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
    print(f"fcntl FD_CLOEXEC: {not bool(flags & fcntl.FD_CLOEXEC)}")
    
    # Make them differ
    os.set_inheritable(fd, False)
    print("\nAfter change:")
    print(f"os.get_inheritable: {os.get_inheritable(fd)}")
    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
    print(f"fcntl FD_CLOEXEC: {not bool(flags & fcntl.FD_CLOEXEC)}")

这显示了两种检查继承状态的方法。os.get_inheritable 更简单,而 fcntl 提供了更多的控制。

请注意,FD_CLOEXEC 是可继承的逆属性 - 设置后,描述符不可继承。

平台差异

此示例演示了 Unix 和 Windows 系统之间 os.get_inheritable 的平台特定行为。

platform_differences.py
import os
import sys

def check_inheritance(fd):
    try:
        return os.get_inheritable(fd)
    except (AttributeError, OSError) as e:
        return f"Error: {e}"

# Check standard streams
print("Platform:", sys.platform)
print(f"stdin: {check_inheritance(sys.stdin.fileno())}")
print(f"stdout: {check_inheritance(sys.stdout.fileno())}")
print(f"stderr: {check_inheritance(sys.stderr.fileno())}")

# Check invalid descriptor
print(f"Invalid fd: {check_inheritance(9999)}")

此代码检查不同平台上的继承并处理潜在的错误。对于某些描述符,Windows 的行为可能与类 Unix 系统不同。

该示例还展示了无效文件描述符的错误处理。

安全注意事项

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我在教学编程方面拥有超过十年的经验。

列出所有 Python 教程