Когда использовать os.name, sys.platform или platform.system?

105

Насколько мне известно, у Python есть 3 способа узнать, на какой операционной системе работает:

  1. os.name
  2. sys.platform
  3. platform.system()

Знание этой информации часто бывает полезно при условном импорте или использовании функций, которые различаются между платформами (например, time.clock()в Windows и time.time()UNIX).

У меня вопрос: почему это можно сделать тремя разными способами? Когда следует использовать один способ, а не другой? Какой способ является «наилучшим» (наиболее перспективным или с наименьшей вероятностью случайно исключить конкретную систему, на которой действительно может работать ваша программа)?

Кажется, что sys.platformэто более конкретный, чем os.name, позволяющий отличать win32от cygwin(в отличие от просто nt) и linux2от darwin(в отличие от просто posix). Но если это так, то как насчет разницы между sys.platformи platform.system()?

Например, что лучше, это:

import sys
if sys.platform == 'linux2':
    # Do Linux-specific stuff

или это? :

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

Пока я буду придерживаться этого sys.platform, так что этот вопрос не особенно актуален, но я был бы очень благодарен за некоторые разъяснения по этому поводу.

тангенс
источник
15
использовать sys.platform.startswith('linux')вместо sys.platform == 'linux2'для будущей совместимости
jfs

Ответы:

68

Немного погрузился в исходный код.

Вывод sys.platformи os.nameопределяется во время компиляции. platform.system()определяет тип системы во время выполнения.

  • sys.platform указывается в качестве определения компилятора во время конфигурации сборки.
  • os.nameпроверяет , будет ли конкретные модули определенных бя доступны (например posix, nt...)
  • platform.system()фактически запускается unameи, возможно, несколько других функций для определения типа системы во время выполнения.

Мое предложение:

  • Используйте, os.nameчтобы проверить, совместима ли это система с posix.
  • Используйте, sys.platformчтобы проверить, является ли это linux, cygwin, darwin, atheos и т. Д.
  • Используйте, platform.system()если не верите другим источникам.
муеее
источник
2
Я провел дополнительные исследования, и вот подробный ответ: stackoverflow.com/a/58071295/207661 .
Шитал Шах
20

Между и есть тонкая грань, 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). Некоторые системы усекают имя узла до 8 символов или до ведущего компонента; лучший способ получить имя хоста - socket.gethostname () или даже socket.gethostbyaddr (socket.gethostname ()).

Availability: recent flavors of Unix.
Абхиджит
источник
11

Из sys.platformдокументов :

  • os.name имеет более грубую детализацию
  • os.uname() дает системно-зависимую информацию о версии
  • platformМодуль содержит подробные проверки идентичности системы

Часто «лучший» ориентированный на будущее способ проверить, доступна ли какая-либо функция, - это просто попытаться использовать ее и использовать запасной вариант, если он не работает.

как насчет разницы между sys.platform и platform.system ()?

platform.system()возвращает нормализованное значение , что он может получить из нескольких источников: os.uname(), sys.platform, verкоманда (на Windows).

jfs
источник
10

Это зависит от того, предпочитаете ли вы создавать исключение или пробовать что-либо в непроверенной системе, и является ли ваш код настолько высоким или таким низким, что он может или не может работать в аналогичной непроверенной системе (например, непроверенный Mac - 'posix' или на встроенные системы ARM). Более питоническим является не перечисление всех известных систем, а проверка возможных соответствующих свойств. (например, считается важным порядок байтов системы, но не важны свойства многопроцессорности.)

  • os.name - достаточное разрешение для правильного использования osмодуля. Возможные значения: posix, nt, os2, ce, java или riscos в Python 2.7, в то время как с 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модуля для сообщений и регистрации ошибок.

Hynekcer
источник
os.nameВозможные возвращаемые значения 'posix', 'nt', в 'java'соответствии с Python 3 Docs . См. Также: документацию модуля платформы . Я не верю '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. Я не просматривал разные версии документации и сделал грубое предположение, что поведение Python 3 os.nameбыло одинаковым для разных версий. Я также не перепроверил документацию 2.7 , но теперь я знаю, что вы правы.
afeique
3

Я считаю, что модуль платформы, вероятно, предпочтительнее для нового кода. Остальные существовали до этого. Это эволюция, а остальные остаются для обратной совместимости.

Кит
источник
7
Интересно, сможем ли мы получить подтверждение этого от разработчиков Python. Может, даже тот, кто разработал платформенный модуль.
ztangent