何时使用os.name、sys.platform或platform.system?

142
据我所知,Python有三种方法可以找出正在运行的操作系统:
  1. os.name
  2. sys.platform
  3. platform.system()
了解这些信息通常在条件导入或使用不同平台之间差异功能时非常有用(例如在Windows上使用time.clock()和在UNIX上使用time.time())。
我的问题是,为什么要有三种不同的方法?应该在什么情况下使用一种而不是另一种?哪种方式最好(未来最具有可扩展性或最不可能意外地排除程序实际可以运行的特定系统)?
似乎sys.platformos.name更具体,允许您区分win32cygwin(而不仅仅是nt),以及linux2darwin(而不仅仅是posix)。但如果是这样的话,那么sys.platformplatform.system()之间的区别呢?
例如,哪一个更好:
import sys
if sys.platform == 'linux2':
    # Do Linux-specific stuff

还是这个?:

import platform
if platform.system() == 'Linux':
    # Do Linux-specific stuff

目前我会继续使用sys.platform,因此这个问题并不特别紧急,但我非常感激对此进行澄清。


20
在未来的兼容性方面,请使用sys.platform.startswith('linux')而不是sys.platform =='linux2' - jfs
我是这样做的:如果 sys.platform == "linux" 或 sys.platform == "linux2": - Robin
6个回答

91

深入源代码进行了一些研究。

sys.platformos.name 的输出是在编译时确定的。platform.system() 在运行时确定系统类型。

  • sys.platform 在构建配置期间被指定为编译器定义。
  • os.name 检查是否有某些特定于操作系统的模块可用(例如posixnt等)。
  • platform.system() 实际上运行uname和可能几个其他函数来在运行时确定系统类型。

我的建议:

  • 使用os.name检查是否为符合posix标准的系统。
  • 使用sys.platform检查是否为linux、cygwin、darwin、atheos等系统。
  • 如果不确定,使用platform.system()

5
我做了更多的研究,这里是详细的答案:https://dev59.com/qXVD5IYBdhLWcg3wXacd#58071295。 - Shital Shah
请注意,在 Python 3.10 中,platform.system 在 Unix 以外的系统中默认为 sys.platform(在 Unix 中使用 uname)。 - Heberto Mayorquin

25

platform.system()sys.platform之间有一条微弱的差别,有趣的是对于大多数情况而言,platform.system()会退化成sys.platform

以下是源文件Python2.7\Lib\Platform.py\system的内容。

def system():

    """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.

        An empty string is returned if the value cannot be determined.

    """
    return uname()[0]

def uname():
    # Get some infos from the builtin os.uname API...
    try:
        system,node,release,version,machine = os.uname()
    except AttributeError:
        no_os_uname = 1

    if no_os_uname or not filter(None, (system, node, release, version, machine)):
        # Hmm, no there is either no uname or uname has returned
        #'unknowns'... we'll have to poke around the system then.
        if no_os_uname:
            system = sys.platform
            release = ''
            version = ''
            node = _node()
            machine = ''

根据文档

os.uname()

返回一个包含5个字符串的元组,用于标识当前操作系统的信息。这个元组包含了5个字符串:(sysname, nodename, release, version, machine)。一些系统会将nodename截断为8个字符或截取前导部分;获取主机名的更好方法是使用socket.gethostname(),甚至是socket.gethostbyaddr(socket.gethostname())。

Availability: recent flavors of Unix.

12

来自sys.platform文档

通常,“最好”的测试某些功能是否可用的方法是尝试使用它,并在失败时使用备用方案。

sys.platform和platform.system()之间有什么区别?

platform.system()返回一个归一化的值,它可能来自多个来源:os.uname()sys.platformver命令(在Windows上)。


10
这取决于您是更喜欢引发异常还是在未经测试的系统上尝试任何操作,以及您的代码是如此高级还是如此低级,以至于它能否在类似的未经测试的系统上工作(例如未经测试的Mac-"posix"或嵌入式ARM系统)。更符合Python风格的方法是不枚举所有已知的系统,而是测试可能相关的属性。(例如,系统的字节序很重要,但多处理属性并不重要。)
os.name对于正确使用os模块足够了。在Python 2.7中,可能的值为'posix'、'nt'、'os2'、'ce'、'java'或'riscos',而自Python 3.4以来仅使用'posix'、'nt'和'java'。
sys.platform提供了更精细的分辨率。建议使用if sys.platform.startswith('linux')习惯用法,因为"linux2"表示Linux内核版本2.xx或3。旧版内核目前从未使用过。在Python 3.3中,所有Linux系统都是简单的"linux"。
我不了解"Mac"和"Java"系统的具体情况,因此无法使用非常好的platform.system()方法进行分支,但我会利用platform模块的优势来进行消息和错误记录。

os.name 可能的返回值为 'posix''nt''java',根据 Python 3 文档。另请参阅:平台模块文档。我不相信 'riscos''os2'os.name 的可能返回值;它们可能是 sys.platform 的返回值Python 3 sys.platform 文档 看起来并不详尽。 - afeique
1
@afeique:我更新了我的答案以适应较新的Python版本,但在那个时候它是正确的。请参阅Python 3.3 - os.name(当时的最新版本)。 Python 2.7仍受支持,并且'riscos'是其中一个可能的值。 - hynekcer
感谢@hynekcer,我很感激您编辑添加Python版本号。我很抱歉没有意识到它在Python 3.3之后发生了变化。我没有浏览文档的不同版本,并且错误地假设os.name的Python 3行为在各个版本中是一致的。我也没有双重检查2.7文档,但现在我知道您是正确的。 - afeique

3

我认为平台模块可能更适合新代码。其他模块是在它之前存在的。它是一种进化,而其他模块仍然存在以保持向后兼容性。


11
我想知道能否找到任何Python开发者来证实这一点,甚至可能是开发 platform 模块的人。 - ztangent

0

sys.platform 是在编译时确定的,platform.system() 是在运行时确定的。

这意味着前者的使用能够在 IDE 中检查语法并消除无法到达的代码块。

在我看来,如果 sys.platform 能够满足您的需求并且在您的代码中正常工作,请使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接