# setup
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
Istotą języków programowania jest tworzenie zamkniętej całości - narzędzia ktróre można uruchamiać w celu realizacji zadań do którego to narzędzie zostało opracowane. Język Python jest językiem skryptowym, w związku z tym te narzędzia naywa się skryptami. Tworzenie własnych skryptów - programóœ jest istotą programowania. Jeżeli jednak kod zamknie sie w formie skryptu istnieje kolejność zrozumienia:
W najprostrzym modelu skrypt może być sekwencją kodu, w którym wpisano wszystkie zmienne sterujące są wpisane na sztwyno. Taki skrypt jest jednorazowego użytku i przeznaczony jest do zautomatyzowania procdur obliczeniowych. Zaletą takich rozwiązań jest że taki skrypt jest przeznaczony dla autora i nie wymaga dodatkowych procedur zabezpieczających czy sprawdzających.
Jeżeli skrypt jest przeznaczony do użytku przez osoby trzecie musi być wyposażony w narzędzia pozwalające na przekazywanie parametrów do skryptu. Parametry skryptu to wartości oddzielane spacjami, które występują po nazwie skryptu. Argumenty przekazane do skryptu są przechowywane w zmiennej sys.arg
w formie listy, której pierwszym elementem sys.arg[0] jest nazwa skryptu. Pozostałe elementy to przekazane parametry.
Zawartość pliku arg.py
#!/bin/python3
import sys
print(sys.argv)
print(len(sys.argv))
$ python3 arg.py dane 3 5 2000
['arg.py', 'dane', '3', '5', '2000']
5
Powyższe rozwiązanie jest półśrodkiem: wymaga znajomośc roli poszczególnych pozycji argumentów skryptu, ich ograniczeń, akceptowanych typów, nie zabezpiecza również przed sytuacją podania błędnych argumentów. Pozwala jednak przechwycić wartości, skonwertować je do wymaganego typu i przekazać do dalszych częśći skryptu.
import sys
dane=sys.argv[1]
liczba_wierszy = int(sys.argv[2])
liczba_kolumn = int(sys.argv[3])
prog = float(sys.argv[4])
print("dane: {0:%<s}, liczba wierszy: {1:%<d}, \
liczba kolumn: {2:%<d}, próg wartości: {3:%<f}".
format(dane,liczba_wierszy,liczba_kolumn,prog))
Narzędziem pozwalającym na zbudowanie uniwersalnego interface użytkownika (w trybie tekstowym) skryptu jest moduł argparse z biblioteki standardowej. Moduł ten pozwala zbudować parser argumentów i jednocześnie dostarczyć podstawowy system pomocy dla skryptu.
Polecenie utworzenia nowego parsera ma wiele opcji, z których na tym etapie istotne jest tylko jeden:
import argparse
# parser
parser = argparse.ArgumentParser(description='File process text file and print summary.')
args = parser.parse_args()
Ostatnim poleceniem parsera jest funkcja .parser_args()
, która analizuje porawność wprowadzonych argumentów
Parser nie ma sensu jeżeli nie przetwarza żadnych argumentów. Polecenie .add_argument(name/flags, [paramteres])
pozwala dodać argumenty wejściowe. Najważniejsze opcje to:
open()
)Więcej na temat definiowania argumentów można przeczytać w dokumentacji modułu.
[https://docs.python.org/3/library/argparse.html]
import argparse
# parser
parser = argparse.ArgumentParser(description='File process text file and print summary.')
parser.add_argument('file',
help='file to process')
parser.add_argument('--rows', default=0, type=int,
help='Numbers of rows to process, 0, to all')
parser.add_argument('--cols', default=-1, type=int,
help='Numbers of columns to process, 0 to all')
parser.add_argument('--thresh', default=0, type=float,
help='Threshold to accept values')
parse.add_argument('--ext', action='store_true',
help='Calculate extended statistics')
args = parser.parse_args()
print(args)
$ python3 arg.py --help
usage: arg.py [-h] [--rowskip ROWSKIP] [--cols COLS] [--thresh THRESH] file
File process text file and print summary.
positional arguments:
file file to process
optional arguments:
-h, --help show this help message and exit
--rows ROWS Numbers of rows to process, 0, to all
--cols COLS Numbers of columns to process, 0 to all'
--thresh THRESH Threshold to accept values
--ext Calculate extended statistics
Jeżeli nie wiemy jakie parametry możemy prekazać do skryptu możemy użyć flagi --help
. W tej sytuacji skrypt wyświetli nam jakie parametry możemy przekazać i jaka jest ich rola. Jeżeli parametry mają wartości domyślne należy to zaznaczyć w opisie.
$ python3 arg.py --rowskip=1 --thresh=10 --cols=20 dane.txt
Namespace(cols=20, file='dane.txt', rows=1, thresh=10.0)
Parametry, które mają wartości domyślne nie muszą być przekazywane do skryptu. Opcja typ sprawdza, czy przekazany argument jest odpowiedniego typu. Jeżeli nie będzie parser zgłosi błąd.
$ python3 arg.py --rowskip=1 --thresh=10 --cols=20.1 dane.txt
usage: arg.py [-h] [--rows ROWS] [--cols COLS] [--thresh THRESH] file
arg.py: error: argument --cols: invalid int value: '20.1'
Argumenty przekazywane do skryptu dzielą się na trzy grupy:
--
lub -
w wersji skkróconej, nie muszą być wymagane, ale można zaznaczyć że są, mogą posiadać wartości domyślne, odgórnie zdefinowaną listę wyboru, a w zaawansowanych opcjach liczbę argumentów, czy rodzaj akcji--ext
W pracy zawodowej programiści czy analitycy danych rzadko zajmują się bardzo szerokim spektrum zagadnień. Najczęściej ludzie specjalizują się w mniej lub bardziej wąskiej dziedzinie aktywności. Oznacza to, że wiele rozwiązań - kodu raz napisanego, przetestowanego i zapisanego w formie funkcji może być wielokrotnie wykorzystywanych również w innych skryptach. Z tego powodu w praktyce nie pisze się skryptów jako ciągu poleceń, ale dzieli się go na logicznie zdefiniowane funkcje, które następnie wywołuje się w części głównej skryptu. Prawidłowo napisany skrypt powinien mieć następującą strukturę:
if __name__ == "__main__":
jest to sprawdzenie czy zmienna wbudowana __name__
zawiera wartość __main__
oznaczającą że jest to główny blok skryptu.skrytpt skr.py:
#!/usr/bin/python3
def moja_funkcja(): #1
print("Moja funkcja została wykonana")
if __name__ == "__main__": #2
moja_funkcja() #3
print("Kolejne fragmenty kodu poza funkcją..") #4
>>> $ python3 skr.py
Moja funkcja została wykonana
Kolejne fragmenty kodu..
Jeżeli chcemy teraz użyć kodu moja_funkcja w innym skrypcie, wystarczy ją zaimportować i uruchomić:
skrytpt inny_skr.py:
#!/usr/bin/python3
from skr import moja_funkcja # bez rozszerzenia i nawiasów
if __name__ == "__main__":
moja_funkcja() # wywołanie
print("A to zupełnie inny sktypt..")
>>> $ python3 inny_skr.py
Moja funkcja została wykonana
to zupełnie inny sktypt..
Moduł jest zbiorem zmiennych oraz funcji, które zostały pogrupowane w jeden zbiór. W najprostrzej wersji, jeśli zapiszemy w jednym pliku utworzone przez nas funkcje, zmiene i klasy – stworzymy własny moduł. Do funkcji i zmiennych mamy dostęp taki sam jak do innych modułów - poprzez zaimportowanie całego modułu lub import pojedynczych funkcji. Listę dostępnych funkcji możemy uzyskać wykonując znane już polecenie dir na nazwie modulu:
import mojmodul
dir(mojmodul)
...
Jeżeli jednak nasz potencjalny moduł staje się rozbudowany, zasadnym jest podział go na kilka plików, z których każdy będzie miał zindywidualizowaną funkcjonalność. W takiej sytuacji tworzymy katalog, który będzie nazwą naszego modułu, następnie umieszczamy w nim plik __init.py__
oraz pliki z nazwami submodułów zawierających funkcje. Taki katalog możemy nazywać pakietem (ang. package):
.
└── mojpakiet
├── __init__.py
└── mojmodul.py
Dostęp do funkcji z takiego pakietu można zrealizować na trzy sposoby:
import mojpakiet
mojpakiet.mojmodul.moja_funckcja(...)
from mojpakiet import mojmodul
mojmodul.moja_funckcja(...)
from mojpakiet.mojmodul import moja_funkcja
moja_funckcja(...)
Jeżeli nasze moduły/pakiety przechowujemy w jednym miejscu i nie jest to biblioteka systemowa ani katalog z którego uruchamiamy skrypt należy w skrypcie wskazć lokalizację tego katalogu poprzez dołączenie ścieżki dostępu do modułów. Jeżeli jednak skrypt, który wykorzystuje nasze funkcje zamierzamy rozpowszechniać należy go rozpowszechniać wraz z naszym modułem.
sys.path.append(os.path.join(os.path.expanduser("~"),"moje_moduly")