Я пытаюсь понять, что является мотивацией использования библиотечных функций Python для выполнения специфических для ОС задач, таких как создание файлов / каталогов, изменение атрибутов файлов и т. Д., Вместо простого выполнения этих команд с помощью os.system()
или subprocess.call()
?
Например, почему я хотел бы использовать os.chmod
вместо того, чтобы делать os.system("chmod...")
?
Я понимаю, что более «питонно» использовать как можно больше доступных библиотечных методов Python вместо того, чтобы просто выполнять команды оболочки напрямую. Но есть ли какая-либо другая мотивация для этого с функциональной точки зрения?
Я говорю только о выполнении простых однострочных команд оболочки здесь. Когда нам нужно больше контроля над выполнением задачи, я понимаю, что с помощьюsubprocess
модуля имеет больше смысла, например.
источник
print
когда ты могos.system("echo Hello world!")
?os.path
для обработки путей вместо ручной обработки их: он работает на каждой ОС, где он работает.os.chmod
не будет вызыватьchmod
программу, которую будет делать оболочка. Использованиеos.system('chmod ...')
запускает оболочку для интерпретации строки для вызова другого исполняемого файла , чтобы сделать вызов на Cchmod
функцию, в то время какos.chmod(...)
идет гораздо более непосредственно к Cchmod
.Ответы:
Это быстрее ,
os.system
иsubprocess.call
создавать новые процессы, которые не нужны для чего-то такого простого. Фактически,os.system
иsubprocess.call
сshell
аргументом обычно создают как минимум два новых процесса: первый - это оболочка, а второй - команда, которую вы запускаете (если это не встроенная оболочка, какtest
).Некоторые команды бесполезны в отдельном процессе . Например, если вы запустите
os.spawn("cd dir/")
, он изменит текущий рабочий каталог дочернего процесса, но не процесса Python. Вы должны использоватьos.chdir
для этого.Вам не нужно беспокоиться о специальных символах, интерпретируемых оболочкой.
os.chmod(path, mode)
будет работать независимо от того, какое имя файла, аos.spawn("chmod 777 " + path)
ужасно потерпит неудачу, если имя файла будет чем-то вроде; rm -rf ~
. (Обратите внимание, что вы можете обойти это, если вы используетеsubprocess.call
безshell
аргумента.)Вам не нужно беспокоиться об именах файлов, начинающихся с тире .
os.chmod("--quiet", mode)
изменит права доступа к названному файлу--quiet
, ноos.spawn("chmod 777 --quiet")
потерпит неудачу, так как--quiet
интерпретируется как аргумент. Это верно даже дляsubprocess.call(["chmod", "777", "--quiet"])
.У вас меньше проблем с кроссплатформенностью и кросс-оболочкой, так как стандартная библиотека Python должна решить эту проблему для вас. У вашей системы есть
chmod
команда? Это установлено? Поддерживает ли он параметры, которые вы ожидаете поддерживать?os
Модуль будет пытаться быть кросс-платформенным , как это возможно и документов , когда , что это не возможно.Если команда, которую вы запускаете, имеет вывод, который вас волнует, вам нужно проанализировать его, что сложнее, чем кажется, поскольку вы можете забыть о угловых случаях (имена файлов с пробелами, табуляцией и символами новой строки в них), даже если вы не волнует переносимость
источник
ls
илиdir
довольно высокоуровневым по отношению к определенным типам разработчиков, так же, какbash
иcmd
/ksh
или любая оболочка, которую вы предпочитаете.ls
это более высокий уровень, поскольку это не прямой вызов API ядра вашей ОС. Это (небольшое) приложение.ls
или ,dir
ноopendir()/readdir()
(Linux API) илиFindFirstFile()/FindNextFile()
(Windows API) илиFile.listFiles
(Java API) илиDirectory.GetFiles()
(C #). Все они тесно связаны с прямым вызовом ОС. Некоторые могут быть такими же простыми, как вставка числа в регистр и вызовint 13h
режима ядра.Это безопаснее. Чтобы дать вам представление, вот пример сценария
Если вход от пользователя был
test; rm -rf ~
таким, то удалял бы домашний каталог.Вот почему безопаснее использовать встроенную функцию.
Следовательно, почему вы должны использовать подпроцесс вместо системы тоже.
источник
Есть четыре веских аргумента в пользу предпочтения более специфических методов Python в
os
модуле, чем при использованииos.system
илиsubprocess
модуле при выполнении команды:os
модуле доступны на нескольких платформах, в то время как многие команды оболочки зависят от ОС.os
модуле.Избыточность (см. Избыточный код ):
Вы фактически выполняете избыточного «посредника» на пути к возможным системным вызовам (
chmod
в вашем примере). Этот средний человек - это новый процесс или суб-оболочка.От
os.system
:И
subprocess
это просто модуль для порождения новых процессов.Вы можете делать то, что вам нужно, не вызывая эти процессы.
Переносимость (см. Переносимость исходного кода ):
Целью
os
модуля является предоставление общих служб операционной системы, и его описание начинается с:Вы можете использовать
os.listdir
как на Windows, так и на Unix. Попытка использоватьos.system
/subprocess
для этой функции заставит вас выполнить два вызова (дляls
/dir
) и проверить, в какой операционной системе вы работаете. Это не так переносимо и позже приведет к еще большему разочарованию (см. Обработка вывода ).Понимание результатов команды:
Предположим, вы хотите перечислить файлы в каталоге.
Если вы используете
os.system("ls")
/subprocess.call(['ls'])
, вы можете получить только выходные данные процесса, которые в основном представляют собой большую строку с именами файлов.Как вы можете отличить файл с пробелом в имени от двух файлов?
Что если у вас нет разрешения перечислять файлы?
Как вы должны отобразить данные на объекты Python?
Это только из головы, и, хотя есть решения этих проблем - зачем снова решать проблему, которая была решена для вас?
Это пример того , чтобы следовать не повторяйте себя принцип (часто обозначаемый как «DRY») по не повторять реализацию , которая уже существует и свободно доступны для вас.
Безопасность:
os.system
иsubprocess
мощные. Это хорошо, когда тебе нужна эта сила, но это опасно, когда тебе это не нужно. Когда вы используетеos.listdir
, вы знаете, что он не может делать ничего другого, кроме списка файлов или выдавать ошибку. Когда вы используетеos.system
илиsubprocess
для достижения того же поведения, вы можете в конечном итоге сделать то, что вы не хотели делать.Безопасность впрыска (см. Примеры инъекций в оболочку ) :
Если вы используете ввод от пользователя в качестве новой команды, вы в основном дали ему оболочку. Это очень похоже на SQL-инъекцию, предоставляющую пользователю оболочку в БД.
Примером может служить команда вида:
Это может быть легко использовано для запуска любого произвольного кода, используя input:
NASTY COMMAND;#
для создания возможного:Есть много таких команд, которые могут поставить вашу систему под угрозу.
источник
По простой причине - когда вы вызываете функцию оболочки, она создает вложенную оболочку, которая уничтожается после того, как ваша команда существует, поэтому, если вы измените каталог в оболочке - это не повлияет на вашу среду в Python.
Кроме того, создание суб-оболочки занимает много времени, поэтому использование команд ОС напрямую повлияет на вашу производительность.
РЕДАКТИРОВАТЬ
У меня было несколько временных тестов:
Внутренняя функция работает более чем в 10 раз быстрее
EDIT2
Могут быть случаи, когда вызов внешнего исполняемого файла может дать лучшие результаты, чем пакеты Python - я только что вспомнил письмо, отправленное моим коллегой, в котором производительность gzip, вызванного через подпроцесс, была намного выше, чем производительность пакета Python, который он использовал. Но, конечно, не тогда, когда мы говорим о стандартных пакетах ОС, эмулирующих стандартные команды ОС
источник
%
обычного интерпретатора.time <path to script>
в терминале, и он скажет вам реальное время, затраченное пользователем и процессами. Это если у вас нет iPython и у вас есть доступ к командной строке Unix.Вызов оболочки зависит от ОС, тогда как в большинстве случаев функции модуля Python os - нет. И это позволяет избежать порождения подпроцесса.
источник
Это гораздо эффективнее. «Оболочка» - это просто еще один бинарный файл ОС, который содержит множество системных вызовов. Зачем тратить время на создание всего процесса оболочки только для одного системного вызова?
Ситуация еще хуже, когда вы используете
os.system
что-то, что не является встроенной оболочкой. Вы запускаете процесс оболочки, который, в свою очередь, запускает исполняемый файл, который затем (на расстоянии двух процессов) выполняет системный вызов. По крайней мереsubprocess
, устранена необходимость в промежуточном процессе оболочки.Это не относится к Python, это.
systemd
Это такое улучшение времени запуска Linux по той же причине: оно делает необходимые системные вызовы сам, а не порождает тысячу оболочек.источник