Próbuję zrozumieć, jaka jest motywacja stojąca za używaniem funkcji bibliotecznych Pythona do wykonywania zadań specyficznych dla systemu operacyjnego, takich jak tworzenie plików / katalogów, zmiana atrybutów plików itp., Zamiast po prostu wykonywać te polecenia za pomocą os.system()
lub subprocess.call()
?
Na przykład, dlaczego miałbym chcieć używać os.chmod
zamiast robić os.system("chmod...")
?
Rozumiem, że bardziej „pythonowe” jest używanie dostępnych metod bibliotecznych Pythona tak często, jak to możliwe, zamiast tylko bezpośredniego wykonywania poleceń powłoki. Ale czy jest jakaś inna motywacja do zrobienia tego z punktu widzenia funkcjonalności?
Mówię tutaj tylko o wykonywaniu prostych jednowierszowych poleceń powłoki. Kiedy potrzebujemy większej kontroli nad wykonaniem zadania, rozumiem, że np. Użycie subprocess
modułu ma większy sens.
źródło
print
kiedy mogłeśos.system("echo Hello world!")
?os.path
do obsługi ścieżek zamiast obsługiwać je ręcznie: działa w każdym systemie operacyjnym, na którym działa.os.chmod
nie będzie wywoływaćchmod
programu, który by zrobił. Korzystanieos.system('chmod ...')
uruchamia powłokę interpretować ciąg, aby zadzwonić do innego pliku wykonywalnego, aby wykonać połączenie do Cchmod
funkcja, gdyos.chmod(...)
idzie o wiele bardziej bezpośrednio do folderu Cchmod
.Odpowiedzi:
Jest szybciej ,
os.system
isubprocess.call
tworzyć nowe procesy, które jest konieczne do czegoś to proste. W rzeczywistości,os.system
isubprocess.call
zshell
argumentacji zwykle utworzyć co najmniej dwa nowe procesy: pierwszy z nich to powłoki, a drugi jest polecenie, które używasz (jeśli nie jest to powłoka wbudowane w podobnytest
).Niektóre polecenia są bezużyteczne w oddzielnym procesie . Na przykład, jeśli uruchomisz
os.spawn("cd dir/")
, zmieni bieżący katalog roboczy procesu potomnego, ale nie procesu Pythona. Musisz do tego użyćos.chdir
.Nie musisz martwić się o znaki specjalne interpretowane przez powłokę.
os.chmod(path, mode)
będzie działać bez względu na nazwę pliku, aleos.spawn("chmod 777 " + path)
zakończy się strasznym niepowodzeniem, jeśli nazwa pliku będzie podobna; rm -rf ~
. (Pamiętaj, że możesz to obejść, jeśli używaszsubprocess.call
bezshell
argumentu).Nie musisz się martwić o nazwy plików zaczynające się od myślnika .
os.chmod("--quiet", mode)
zmieni uprawnienia pliku o nazwie--quiet
, aleos.spawn("chmod 777 --quiet")
zakończy się niepowodzeniem, co--quiet
jest interpretowane jako argument. Dotyczy to nawetsubprocess.call(["chmod", "777", "--quiet"])
.Masz mniej problemów między platformami i powłokami, ponieważ standardowa biblioteka Pythona powinna sobie z tym poradzić. Czy Twój system ma
chmod
polecenia? Czy jest zainstalowany? Czy obsługuje parametry, które ma obsługiwać?os
Moduł będzie starał się być jak cross-platform, jak to możliwe i dokumentów, gdy to nie jest możliwe.Jeśli uruchamiane polecenie ma wyjście, na którym Ci zależy, musisz je przeanalizować, co jest trudniejsze niż się wydaje, ponieważ możesz zapomnieć o przypadkach narożnych (nazwach plików ze spacjami, tabulatorami i znakami nowej linii), nawet jeśli nie obchodzi mnie przenośność.
źródło
ls
albodir
są dość wysoki poziom niektórych rodzajów programistów, jakbash
lubcmd
lubksh
lub cokolwiek zapłacić wolisz są.ls
jest na wyższym poziomie, ponieważ nie jest to bezpośrednie wywołanie API jądra twojego systemu operacyjnego. To (mała) aplikacja.ls
czydir
jednakopendir()/readdir()
(Linux API) lubFindFirstFile()/FindNextFile()
(Windows API) lubFile.listFiles
(Java API) lubDirectory.GetFiles()
(C #). Wszystko to jest ściśle powiązane z bezpośrednim wywołaniem systemu operacyjnego. Niektóre mogą być tak proste, jak wstawienie liczby do rejestru i wywołanieint 13h
trybu jądra.To jest bezpieczniejsze. Aby dać ci pomysł, oto przykładowy skrypt
Jeśli dane wejściowe użytkownika były
test; rm -rf ~
takie, spowoduje to usunięcie katalogu domowego.Dlatego bezpieczniej jest korzystać z funkcji wbudowanej.
Dlatego też powinieneś używać podprocesu zamiast systemu.
źródło
Istnieją cztery mocne argumenty przemawiające za preferowaniem bardziej specyficznych metod Pythona w
os
module zamiast używaniaos.system
lubsubprocess
modułu podczas wykonywania polecenia:os
modułu jest dostępnych na wielu platformach, podczas gdy wiele poleceń powłoki jest specyficznych dla systemu operacyjnego.os
module.Nadmiarowość (patrz kod nadmiarowy ):
W rzeczywistości wykonujesz zbędnego „pośrednika” w drodze do ewentualnych wywołań systemowych (
chmod
w twoim przykładzie). Ten pośrednik jest nowym procesem lub podpowłoką.Od
os.system
:I
subprocess
jest tylko moduł do odradzania nowych procesów.Możesz robić to, czego potrzebujesz, bez tworzenia tych procesów.
Przenośność (patrz przenośność kodu źródłowego ):
Celem
os
modułu jest zapewnienie ogólnych usług systemu operacyjnego, a jego opis zaczyna się od:Możesz używać
os.listdir
zarówno w systemie Windows, jak i unix. Próba użyciaos.system
/subprocess
do tej funkcji zmusi Cię do utrzymania dwóch wywołań (dlals
/dir
) i sprawdzenia, w jakim systemie operacyjnym jesteś. To nie jest tak przenośny i będzie powodować jeszcze większą frustrację później (patrz Magazynowanie Output ).Zrozumienie wyników polecenia:
Załóżmy, że chcesz wyświetlić listę plików w katalogu.
Jeśli używasz
os.system("ls")
/subprocess.call(['ls'])
, możesz odzyskać tylko dane wyjściowe procesu, które są w zasadzie dużym ciągiem z nazwami plików.Jak odróżnić plik ze spacją w nazwie od dwóch plików?
A jeśli nie masz uprawnień do wyświetlania plików?
Jak należy odwzorować dane na obiekty Pythona?
Są to tylko z góry mojej głowy, i chociaż istnieją rozwiązania tych problemów - po co rozwiązywać ponownie problem, który został rozwiązany za Ciebie?
To jest przykład przestrzegania zasady „ Nie powtarzaj się ” (często określanej jako „SUCHA”) poprzez nie powtarzanie implementacji, która już istnieje i jest dostępna bezpłatnie.
Bezpieczeństwo:
os.system
isubprocess
są potężne. Dobrze, gdy potrzebujesz tej mocy, ale jest to niebezpieczne, gdy jej nie potrzebujesz. Kiedy używaszos.listdir
, wiesz, że nie może zrobić nic innego niż wyświetlenie plików lub zgłoszenie błędu. Kiedy używaszos.system
lubsubprocess
osiągasz to samo zachowanie, możesz potencjalnie zrobić coś, czego nie chciałeś zrobić.Bezpieczeństwo wtrysku (patrz przykłady wtrysku powłoki ) :
Jeśli używasz danych wejściowych od użytkownika jako nowego polecenia, w zasadzie dałeś mu powłokę. Jest to podobne do iniekcji SQL zapewniającej użytkownikowi powłokę w bazie danych.
Przykładem może być polecenie w postaci:
To może być łatwo wykorzystany do uruchomienia dowolnego dowolnego kodu przy użyciu wkład:
NASTY COMMAND;#
stworzyć ostateczne:Istnieje wiele takich poleceń, które mogą stanowić zagrożenie dla systemu.
źródło
Z prostego powodu - kiedy wywołujesz funkcję powłoki, tworzy ona podpowłokę, która jest niszczona po zaistnieniu twojego polecenia, więc jeśli zmienisz katalog w powłoce - nie wpływa to na twoje środowisko w Pythonie.
Poza tym tworzenie podpowłoki jest czasochłonne, więc bezpośrednie użycie poleceń systemu operacyjnego wpłynie na wydajność
EDYTOWAĆ
Przeprowadziłem kilka testów czasowych:
Funkcja wewnętrzna działa ponad 10 razy szybciej
EDYCJA2
Mogą zdarzyć się sytuacje, w których wywołanie zewnętrznego pliku wykonywalnego może dać lepsze wyniki niż pakiety Pythona - właśnie przypomniałem sobie wiadomość wysłaną przez mojego kolegę, że wydajność gzipa wywołanego przez podproces była znacznie wyższa niż wydajność pakietu Pythona, którego używał. Ale na pewno nie, gdy mówimy o standardowych pakietach systemu operacyjnego emulujących standardowe polecenia systemu operacyjnego
źródło
%
używania zwykłego interpretera.time <path to script>
terminal, który poinformuje Cię o czasie rzeczywistym, użytkowniku i procesie. To znaczy, jeśli nie masz iPythona i masz dostęp do wiersza poleceń systemu Unix.Wywołanie powłoki jest specyficzne dla systemu operacyjnego, podczas gdy funkcje modułu os w Pythonie nie są w większości przypadków. I pozwala uniknąć tworzenia podprocesu.
źródło
Jest dużo bardziej wydajne. „Powłoka” to po prostu kolejny plik binarny systemu operacyjnego, który zawiera wiele wywołań systemowych. Po co ponosić koszty związane z tworzeniem całego procesu powłoki tylko dla tego pojedynczego wywołania systemowego?
Sytuacja jest jeszcze gorsza, gdy używasz
os.system
czegoś, co nie jest wbudowaną powłoką. Uruchamiasz proces powłoki, który z kolei uruchamia plik wykonywalny, który następnie (dwa procesy dalej) wykonuje wywołanie systemowe. Przynajmniejsubprocess
wyeliminowałoby potrzebę pośrednictwa powłoki.To nie jest specyficzne dla Pythona.
systemd
jest takim ulepszeniem czasów uruchamiania Linuksa z tego samego powodu: sam wykonuje niezbędne wywołania systemowe zamiast tworzyć tysiące powłok.źródło