(Niezbyt) oczywiste elementy Pythona

Niniejszy kurs zakłada podstawową znajomość języka Python. Czytelnik nie znajdzie tu opisu jak tworzyć pętle czy instrukcje warunkowe. Aby uzupełnić wiedzę w tym zakresie polecam lekturę moich notatek do Podstaw programowania w języku Python Na początku jednak przypomnę pewne mniej oczywiste elementy tego języka, które będą bardzo przydatne przy omawianiu programowania obiektowego.

args i kwargs

Jednym z ważnych mechanizmów programowania obiektowego jest przeciążenie funkcji. Zaczniemy to wykorzystywać już niedługo. Jedynym sposobem implementacji tego mechanizmu w Pythonie jest wykorzystanie args i kwargs. Opisano je na tej stronie

Zmienne istnieją od momentu pierwszego przypisania

To w zasadzie powinno być oczywiste, stanowi podstawę programowania w języku Python. Dla przypomnienia jednak powtórzmy: w odróżnieniu od języków kompilowanych takich jak Java czy C++, w Pythonie nie deklarujemy zmiennych. Zmienne tworzymy przez nadawanie wartości.

Zmienne globalne i lokalne

Zmienne mogą być lokalne lub globalne. Róznice między nimi opisano na tej stronie

Wszystko jest tym czym jest …

… no chyba, że jest referencją tego czegoś

Przeanalizuj poniższy przykład, który w zasadzie powinien stworzyć macierz 3x3 z elementami 1, 2 i 3:

Co ten program wydrukuje na ekranie? Dlaczego? Co się zmieni po odkomentowaniu linii nr 4?

Referencje bywają jednak bardzo przydatne. Dzięki temu zachowanie danego obiektu może zależeć od stanu innego obiektu. W poniższym przykładzie obiekt klasy LJ, obliczającego energię Lennard-Jonesa, śledzi położenia przemieszczających się atomów. Dzięki temu nie trzeba przekazywać ich jako argumentów funkcji przy każdym wywołaniu.

Funkcja tak jak zmienna

Funkcję w języku Python można przekazać jako argument, jak na przykład poniżej:

Funkcje można trzymać w listach i słownikach tak, jak inne zmienne. Dzięki temu możliwe jest np pokazane poniżej podejście do zorganizowania bloku decyzyjnego (ang dispatch). Najpierw “klasyczne” podejście, z mega-długim blokiem if ... else:

process_files_dumb.py
 1from sys import argv
 2
 3def process_files(file_name) :
 4
 5  if file_name.endswith(".pdb") :
 6  	print("processing a PDB file: ",file_name)
 7  	# ... many, many lines of code that are necessary to parse PDB
 8  elif file_name.endswith(".fasta") :
 9  	print("processing a FASTA file: ",file_name)
10  	# ... many, many lines of code that are necessary to parse FASTA
11  elif file_name.endswith(".aln") :
12  	print("processing MSA data in ALN format from file: ",file_name)
13  	# ... many, many lines of code that are necessary to parse ALN
14  else:
15  	print("Unknown file format: ", file_name)
16
17if __name__ == "__main__" :
18 	for fname in argv[1:] : process_files(fname)
19

A teraz ze słownikiem funkcji:

process_files.py
 1from sys import argv
 2from os.path import splitext
 3
 4# Actually, thi function may be impored from a separate module devised for PDB processing
 5def process_pdb(file_name) : 
 6  	print("processing a PDB file: ",file_name)
 7  	# ... many, many lines of code that are necessary to parse PDB
 8
 9def process_fasta(file_name) : # Also might be imported 
10  	print("processing a FASTA file: ",file_name)
11  	# ... many, many lines of code that are necessary to parse FASTA
12
13def process_aln(file_name) : # Also might be imported 
14  	print("processing MSA data in ALN format from file: ",file_name)
15  	# ... many, many lines of code that are necessary to parse ALN
16
17dispatch = { ".pdb" : process_pdb, ".fasta" : process_fasta, ".aln" : process_aln }
18
19if __name__ == "__main__" :
20 	for fname in argv[1:] : 
21 		name, extension = splitext(fname)
22 		if extension in dispatch : dispatch[extension](fname)
23 	else : print("Unknown file format: ",extension)
24