MateriaT1l y eCG IT Documentation

Transkrypt

MateriaT1l y eCG IT Documentation
Materiały eCG IT Documentation
Wydanie 1
Robert Bednarz
July 18 2015
Spis treści
1
Narz˛edzia
1.1 Geany . . . . . . . . . . . .
1.2 Kompilator C/C++ . . . . .
1.3 Biblioteka Qt . . . . . . . .
1.4 Interpreter Pythona . . . . .
1.5 Git . . . . . . . . . . . . .
1.6 ReStructuredText i Sphinx .
1.7 Serwer deweloperski WWW
1.8 Materiały . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
4
4
7
17
17
20
24
27
Linux Live USB
2.1 W Windows . . . . . .
2.2 W Linuksie . . . . . . .
2.3 Pierwsze uruchomienie .
2.4 Obsługa LxPupTahr . .
2.5 Materiały dodatkowe . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
29
29
30
32
33
47
3
Biblioteka Qt
3.1 Adresy (Qt5) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Zadania (Qt5) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Metryka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
79
91
93
4
Technologie WWW
95
4.1 GetSimple CMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.2 Materiały . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5
Python
5.1 Toto Lotek – Python od podstaw . .
5.2 Python kreśli . . . . . . . . . . . .
5.3 Czat (wersja rozszerzona) . . . . .
5.4 Pythonizmy . . . . . . . . . . . . .
5.5 Słownik Pythona . . . . . . . . . .
5.6 Słownik systemowy . . . . . . . .
5.7 Propozycja scenariuszy warsztatów
5.8 Metryka . . . . . . . . . . . . . . .
2
6
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
105
105
121
124
157
162
163
164
164
Gra robotów
165
6.1 Zasady i zaczynamy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
6.2 RG – klocki 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
i
6.3
6.4
6.5
6.6
6.7
RG – klocki 2A . . .
RG – klocki 2B . . .
RG – klocki 3B . . .
RG – dokumentacja
Słownik Pythona . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
170
176
181
186
200
7
Galerie
203
7.1 GetSimple CMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
7.2 Metryka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
8
Indeks
ii
205
Materiały eCG IT Documentation, Wydanie 1
Materiały zawarte w tym repozytorium zawieraja˛ ćwiczenia, poradniki oraz dokumentacj˛e zwiazan
˛ a˛ z zagadnieniami
technologii informacyjnej i informatyki.
Spis treści:
Spis treści
1
Materiały eCG IT Documentation, Wydanie 1
2
Spis treści
ROZDZIAŁ 1
Narzedzia
˛
Poniżej przedstawiamy zestaw przykładowych narz˛edzi do programowania, tworzenia skryptów i dokumentacji, stron
WWW itp. zadań.
Spis treści
• Narz˛edzia
– Geany
* Instalacja
– Kompilator C/C++
– Biblioteka Qt
* System i środowisko IDE
* Qt5 w systemie Windows
– Interpreter Pythona
– Git
* Konto
* Klient Gita
* Lokalne repozytorium
* Podstawy Gita
– ReStructuredText i Sphinx
* Instalacja Sphinksa
* Tworzenie dokumentacji
* Podstawy reST
· Nagłówki
· Dyrektywy
· Listy
· Linki
* Budowanie dokumentacji
* Dokumentacja online
– Serwer deweloperski WWW
* Linux
* Serwer2Go w Windows
– Materiały
* Słownik
* Metryka
Informacja: Przykłady poleceń wydawanych w terminalu b˛edziemy podawali dla systemu Debian i pochodnych
(np. (X)Ubuntu, Mint) oraz menedżera pakietów apt-get, poprzedzamy je symbolami ~$; a także dla system Arch
Linux i pochodnych (np. Bridge, Manjaro) korzystajacych
˛
z menedżera pacman, poprzedzamy je symbolami ~#.
3
Materiały eCG IT Documentation, Wydanie 1
Instalacja pakietów wymaga uprawnień roota. W wielu systemach używa si˛e polecenia sudo, które pozwala zwykłemu użytkownikowi uruchamiać programy z podwyższonymi uprawnieniami. Jeżeli Twój system nie ma skonfigurowanego domyślnie polecenia sudo (np. Debian lub Arch Linux), musisz zalogować si˛e na konto roota, np. wpisujac
˛
w terminalu su root.
1.1 Geany
Geany to proste i lekkie środowisko IDE dost˛epne na licencji GNU General Public Licence. Geany oferuje kolorowanie składni dla najpopularniejszych j˛ezyków, m.in. C, C++, C#, Java, PHP, HTML, Python, Perl i Pascal, wsparcie dla
kodowania w ponad 50 standardach, dopełnianie poleceń, mechanizmy automatycznego zamykanie tagów dla HTMLXML, auto-wci˛eć, pracy na kartach i wiele, wiele wi˛ecej. Podczas pisania kodu przydatny okazuje si˛e brudnopis,
pozwalajacy
˛ tworzyć dowolne notatki, a także możliwość kompilacji plików źródłowych bezpośrednio z poziomu
programu.
1.1.1 Instalacja
W systemie Linux korzystamy z dedykowanego menedżera pakietów, np. w Xubuntu (i innych debianopochodnych)
lub Archu wystarczy wpisać w terminalu:
~$ sudo apt-get install geany geany-plugins
~# pacman -S geany geany-plugins
W MS Windows ściagamy
˛
i instalujemy pełna˛ wersj˛e binarna˛ Geany przeznaczona˛ dla tych systemów. Pełna oznacza
tutaj, ze zawiera biblioteki GTK wykorzystywane przez program. Podczas standardowej instalacji można zmienić
katalog docelowy, np. na C:\Geany.
Zanim rozpoczniemy prac˛e w edytorze, warto dostosować kilka ustawień.
W menu Narz˛edzia/Menedżer wtyczek zaznaczamy pozycj˛e “Addons” (dost˛epna po zainstalowaniu wtyczek), a nast˛epnie “Przegladarka
˛
plików”. Zanim wyjdziemy z okna naciskamy przycisk “Preferencje” i na zakładce “Przegladarka
˛
plików” zaznaczamy opcj˛e “Poda˛żanie za ścieżka˛ do bieżacego
˛
pliku”. Dzi˛eki temu w panelu bocznym w zakładce
“Pliki” zobaczymy list˛e katalogów i plików, które łatwo możemy otwierać.
W menu Edycja/Preferencje CTRL+ALT+P w zakładce Edytor/Wci˛ecia jako “Typ” wci˛eć wybieramy opcj˛e “spacje”.
Warto zapami˛etać i stosować kilka użytecznych skrótów. Jeśli kodujemy w C/C++: F8 – uruchamia linker, F9 –
buduje plik wykonawczy. Klawisz F5 uruchamia z kolei pliki wykonywalne, skrypty Pythona lub otwiera strony
HTML w przegladarce.
˛
Wci˛ecia wstawiaja˛ si˛e automatycznie lub poprzez naciśni˛ecie klawisza TAB. Jeżeli chcemy
wciać
˛ od razu cały blok kodu, zaznaczamy go i również używamy TAB lub CTRL+I, zmniejszenie wci˛ecia uzyskamy
naciskajac
˛ CTRL+U.
Środowisko Geany nie zawiera narz˛edzi potrzebnych do kompilowania czy wykonywania programów pisanych w
różnych j˛ezykach. Wymagane narz˛edzia musimy doinstalować osobno.
1.2 Kompilator C/C++
W systemie Linux wystarczy zazwyczaj wydać jedno polecenie wykorzystujace
˛ używany w danej dystrybucji menedżer pakietów, np.:
~$ sudo apt-get install gcc
~# pacman -S gcc
4
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.2. Kompilator C/C++
5
Materiały eCG IT Documentation, Wydanie 1
6
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
W MS Windows instalujemy minimalistyczne środowisko deweloperskie dostarczajace
˛ wolne narz˛edzia GNU Compiler Collection, czyli MinGw. W tym celu pobieramy instalator mingw-get-setup.exe i uruchamiamy.
W oknie wyboru pakietów zaznaczamy widoczne poniżej paczki, w tym przede wszystkim mingw32-gcc-g++, a
nast˛epnie wybieramy polecenie Installation/Apply.
Po pobraniu i rozpakowaniu wskazanych narz˛edzi oraz zakończeniu instalatora (Close) trzeba dodać do ścieżki systemowej położenie kompilatora i linkera; dzi˛eki temu b˛edzie można korzystać z tych i innych narz˛edzi bezpośrednio
z Geany lub okienka konsoli tekstowej. W oknie “Uruchamianie” (WIN+R) wpisujemy polecenie wywołujace
˛ okno
“Zmienne środowiskowe” – można je również uruchomić z okna właściwości komputera:
Klikamy przycisk Nowa i tworzymy nowa˛ zmienna˛ użytkownika zgodnie z podanym zrzutem:
Wskazówka: Powyżej przedstawiliśmy instalacj˛e narz˛edzi MinGw z konta zwykłego użytkownika. Można w razie
potrzeby czynności te wykonać również z konta administratora, co pozwoli udost˛epnić narz˛edzia wszystkim użytkownikom. Podobnie ścieżk˛e do kompilatora itd. można dopisać do zmiennej systemowej PATH, dzi˛eki czemu wszyscy
użytkownicy b˛eda˛ mogli wywoływać narz˛edzia bez podawania pełnej ich lokalizacji.
1.3 Biblioteka Qt
Qt to zestaw bibliotek przeznaczonych dla j˛ezyka C++, QML i Java, który znakomicie ułatwia tworzenie graficznego
interfejsu użytkownika. Zawiera również klasy udost˛epniajace
˛ obsług˛e m.in. multimediów , sieci czy baz danych.
1.3. Biblioteka Qt
7
Materiały eCG IT Documentation, Wydanie 1
8
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.3. Biblioteka Qt
9
Materiały eCG IT Documentation, Wydanie 1
10
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.3. Biblioteka Qt
11
Materiały eCG IT Documentation, Wydanie 1
12
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.3. Biblioteka Qt
13
Materiały eCG IT Documentation, Wydanie 1
1.3.1 System i środowisko IDE
Bilioteka Qt jest przenośna z założenia, wi˛ec programować z jej wykorzystaniem można w wielu systemach i środowiskach. Proponujemy system Linux, np. dystrybucj˛e Debian (v. Jessie) lub Xubuntu 14.04. Instalacja wymaganych
narz˛edzi sprowadza si˛e do wydania prostych poleceń w terminalu:
~$ sudo apt-get update
~$ sudo apt-get install qtcreator qt5-qmake qt5-default qt4-qtconfig
Pierwsze polecenie zaktualizuje repoytoria, czyli wersje dost˛epnego oprogramowania; drugie zainstaluje dedykowane
środowisko IDE, które pozwala projektować interfejs graficzny, bardzo ułatwia edycj˛e kodu, pozwala budować, uruchamiać i debugować różne wersje tworzonych aplikacji.
1.3.2 Qt5 w systemie Windows
Instalacja jest bardzo prosta. Pobieramy Qt Online Installer for Windows i uruchamiamy. Nast˛epnie przeprowadzamy
standardowa˛ instalacj˛e z domyślnymi ustawieniami, podajac
˛ w razie potrzeby hasło administratora.
Wyglad
˛ i działanie aplikacji Qt Creator w systemie Linux i Windows sa˛ takie same.
14
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.3. Biblioteka Qt
15
Materiały eCG IT Documentation, Wydanie 1
16
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.4 Interpreter Pythona
W systemach Linux Python jest szeroko stosowany i dost˛epny jest w ramach standardowej instalacji wi˛ekszości
dystrybucji i to zarówno w wersji 2.x, jak i 3.x. Dla formalności polecenia instalacyjne to:
~$ sudo apt-get install python2 python3
~# pacman -S python python2
Informacja: Warto zauważyć, że w dystrybucjach opartych na Debianie polecenie python jest dowiazaniem
˛
do
wersji 2.x, a paczki nazywaja˛ si˛e odpowiednio python2-... lub python3-.... W Arch Linuksie i pochodnych
nazwa python domyślnie wskazuje wersj˛e 3.x (!), podobnie nazwy pakietów dodatkowych. Wersja i paczki z liniii
2.x maja˛ w nazwie python2.
Polecić natomiast można doinstalowanie dodatkowych narz˛edzi, w tym rozszerzonej konsoli:
~$ sudo apt-get install ipython2 ipython3
~# pacman -S python-pip ipython python2-pip ipython2
W MS Windows najprościej zainstalować Pythona przy użyciu skryptu konsoli PowerShell dost˛epnej w wersjach
Professional (oznaczona˛ niebieska˛ ikona˛ i niebieskiem tłem):
(new-object System.Net.WebClient).DownloadFile("https://www.python.org/ftp/python/2.7.8/python-2.7.8.
msiexec /i python-2.7.8.msi TARGETDIR=C:\Python27
[Environment]::SetEnvironmentVariable("Path", "$env:Path;C:\Python27\;C:\Python27\Scripts\", "User")
(new-object System.Net.WebClient).DownloadFile("https://raw.github.com/pypa/pip/master/contrib/get-pi
C:\Python27\python.exe get-pip.py virtualenv
Jeżeli w naszej wersji Windows nie ma PowerShella, ściagamy
˛
interpreter Pythona i instalujemy r˛ecznie, pami˛etajac
˛
o zaznaczeniu opcji “Add Python.exe to Path”.
Nast˛epnie instalujemy program pip do zarzadzania
˛
dodatkowymi bibliotekami za pomoca˛ polecenia:
python -c "exec('try: from urllib2 import urlopen \nexcept: from urllib.request import urlopen');f=ur
Aby uruchamiać skrypty bezpośrednio z poziomu Geany lub konsoli tekstowej bez podawania pełnej ścieżki warto
ja˛ dodać do zmiennej użytkownika lub systemu o nazwie PATH, tak jak pokazano wyżej dla narz˛edzi MinGw. Na
potrzeby pojedynczej sesji odpowiedni efekt osiagniemy
˛
wydajac
˛ polecenie w konsoli:
set PATH=%PATH%;c:\Python27\;c:\Python27\Scripts\
1.5 Git
Git Source Code Mirror – to rozproszony system wersjonowania kodów źródłowych napisany przez Linusa Torvaldsa,
twórc˛e jadra
˛ Linux. Skrót SCM bywa również rozwijany jako software configuration management, co oznacza “zarzadzanie
˛
konfiguracja˛ oprogramowania”. Gita można używać do rozwijania zarówno małych, jak i dużych projektów
(np. Arch Linux, GIMP, jQuery).
1.5.1 Konto
Przede wszystkim wchodzimy na stron˛e https://github.com/. Nast˛epnie wykonujemy poniższe instrukcje:
• Krok 1 – założenie konta; podajemy nazw˛e użytkownika, adres email i hasło, jako typ konta wybieramy free.
• Krok 2 – weryfikacja adresu e-mail
1.4. Interpreter Pythona
17
Materiały eCG IT Documentation, Wydanie 1
18
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
• Krok 3 – zakładamy repozytorium dla projektu, wybieramy typ Public (publiczne) oraz Initialize this repository
with a README (utwórz poczatkowy
˛
plik README.md).
To wszystko. Od tej pory można rozwijać projekt.
1.5.2 Klient Gita
Treść projektu można dodawać do repozytorium centralnego w serwisie github.com za pomoca˛ przegladarki.
˛
Cz˛eściej
jednak robi si˛e to offline, czyli pracuje si˛e na swoim repozytorium lokalnym za pomoca˛ jakiegoś programu.
Ze wzgl˛edu na szybkość działania polecamy środowisko Linux. Instalacja podstawowego klienta tekstowego w systemach debianopodobnych (poza samym Debianem :-), Ubuntu, Linux Mint, PepperMint itd.) i opartych na Arch
Linuksie (np. Bridge Linux) sprowadza si˛e do użycia odpowiedniego menedżera pakietów:
~$ sudo apt-get install git
~# pacman -S git
W systemach Windows tego samego klienta tekstowego pobieramy ze strony http://git-scm.com/download/win i instalujemy wybierajac
˛ domyślne opcje.
Po opanowaniu podstaw obsługi Gita można oczywiście zainstalować programy z graficznym interfejsem użytkownika, jednak w wi˛ekszości przypadków nie jest to konieczne.
1.5.3 Lokalne repozytorium
Pierwsza˛ rzecza˛ b˛edzie najcz˛eściej sklonowanie założonego repozytorium na nasz komputer. Uruchamiamy wi˛ec
terminal (wiersz poleceń czy też konsol˛e tekstowa)
˛ i wydajemy polecenie:
~$ git clone https://github.com/nazwa_użytkownika/nazwa_repozytorium.git
Jak widać argumentem jest tutaj Git URL, czyli schematyczny adres repozytorium, który możemy sprawdzić na stronie
github.com. Domyślnym protokołem transferu jest https, chociaż można wykorzystywać również inne, np. SSH. W
rezultacie w bieżacym
˛
folderze (zazwyczaj katalogu domowym użytkownika) utworzony zostanie katalog o nazwie
naszego projektu zawierajacy
˛ wszystkie dodane do tej pory materiały, np. plik README.md, oraz ukryty katalog
konfiguracyjny .git, którego nie należy usuwać.
Informacja:
Za pomoca˛ narz˛edzia git można również utworzyć zupełnie nowy projekt. Służy do tego
opcja init. Możliwe jest również sklonowanie istniejacego
˛
projektu do katalogu o narzuconej nazwie, np.:
https://github.com/koduj-z-klasa/python101.git.
1.5.4 Podstawy Gita
Informacja: Wszystkie poniższe polecenia wydajemy w głównym katalogu projektu. Warto poczytać polska˛ wersj˛e
1 podr˛ecznika Git SCM. Dost˛epna jest również wersja 2 podr˛ecznika Git, ale tylko w j. angielskim.
Codzienna˛ prac˛e projektem warto rozpoczać
˛ od zsynchronizowania wersji lokalnej z ewentualnymi zmiananami zapisanymi na serwerze:
~$ git pull
Bardzo cz˛esto b˛edziemy korzystać z polecenia:
~$ git status
1.5. Git
19
Materiały eCG IT Documentation, Wydanie 1
– które informuje nas o tym, jakie pliki zostały dodane do poczekalni, ale sa˛ nieśledzone (ang. Untracked files),
jakie zostały zmienione, ale nie zostały zatwierdzone (ang. Changes not staged for commit), a jakie czekaja˛ na
zatwierdzenie (ang. Changes to be committed). Komunikat On branch master informuje, że pracujemy na głównej
gał˛ezi (ang. master branch) projektu.
Zarówno nieśledzone, jak i niezatwierdzone pliki, które chcemy umieścić w projekcie, dodajemy poleceniem:
~$ git add ścieżka/nazwa_pliku
Można używać znaków specjalnych, np. git add *.jpg. Jeżeli mamy rozbudowana˛ struktur˛e katalogów w projekcie, przydatne jest polecenie dodajace
˛ nowe zmiany hurtowo i rekursywnie:
~$ find . -name "*.rst" -exec git add {} \;
Po dodaniu wszystkich nowych plików i zmian do poczekalni, trzeba je zatwierdzić:
~$ git commit -m "Opis zmian ..."
Jeżeli pominiemy opcjonalny przełacznik
˛
-m otwarty zostanie edytor, w którym opisujemy dokonywane zmiany.
Zatwierdzone zmiany prześlemy na serwer wydajac
˛ polecenie:
~$ git push
– które poprosi nas o podanie nazwy użytkownika (adres email) i hasła, a nast˛epnie prześle informacje na serwer.
Powyższy porzadek
˛
komend jest typowy dla sesji z gitem.
Informacja: Wskazówka: nie należy usuwać plików/katalogów lub zmieniać ich nazw w katalogu projektu za
pomoca˛ narz˛edzi systemowych, np. menedżera plików, ponieważ Git nie b˛edzie nic o tym wiedział i zasypie nas
wieloma komunikatami podczas sesji. Zamiast tego używamy poniższych poleceń:
~$ git rm plik
~$ git rm -rf katalog
~$ git mv stara_nazwa nowa_nazwa
1.6 ReStructuredText i Sphinx
Git dobrze nadaje si˛e do prowadzenia projektów nie tylko typowo programistycznych, ale również dokumentacyjnych
i szkoleniowych, a wi˛ec zawierajacych
˛
nie tylko kod, ale przede wszystkim instrukcje, poradniki, scenariusze, itp.
W katalogu naszego projektu zakładamy katalog podrz˛edny o nazwie np. docs, w którym tworzyć b˛edziemy nasza˛
dokumentacj˛e.
~/nazwa_projektu$ mkdir docs
Dokumenty zapisywane b˛eda˛ w formacie reStructuredText, czyli za pomoca˛ tekstowego j˛ezyka znaczników, w plikach
z rozszerzeniem .rst. Zawartość tych plików może być później przetworzona do postaci formatów docelowych,
takich jak HTML, PDF czy LaTeX. Zadanie to realizowane b˛edzie przez narz˛edzie Sphinx napisane w Pythonie i
służace
˛ m.in. do tworzenia dokumentacji tego j˛ezyka.
1.6.1 Instalacja Sphinksa
Przede wszystkim potrzebujemy interpretera Pythona i narz˛edzia instalacji modułów dodatkowych pip – zobacz w
sekcji Interpreter Pythona. Nast˛epnie wydajemy polecenia:
20
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
~$ sudo apt-get install mercurial
~$ sudo pip install sphinx_rtd_theme hg+https://bitbucket.org/birkenfeld/sphinx#sphinx
W Archu:
~# pacman -S mercurial
~# pip install sphinx_rtd_theme hg+https://bitbucket.org/birkenfeld/sphinx#sphinx
Informacja: Instalacja klienta systemu kontroli wersji Mercurial wynika z tego, że korzysta z niego projekt Sphinx.
Instalacja tematu sphinx_rtd_theme jest opcjonalna, domyślny temat wyglada
˛ tak, jak w dokumentacji Pythona.
Teraz możemy przejść do konfiguracji Sphinksa, która sprowadza si˛e do wygenerowania pliku z ustawieniami o nazwie
conf.py. W głównym katalogu tworzonej dokumentacji, czyli docs, wydajemy polecenie:
~$ sphinx-quickstart
Na wi˛ekszość pytań kreatora odpowiadamy naciśni˛eciem Enter, przyjmujac
˛ ustawienia domyślne. Zwrócić uwag˛e
należy na:
• Project name: – wpisujemy nazw˛e naszego projektu;
• Author name(s): – wpisujemy autora;
• Project version: – podajemy wersj˛e, np. 1;
• Project release: – podajemy wydanie, np. 0;
• Project langiage [en]: – określamy j˛ezyk jako pl;
• Please indicate... Sphinx extensions: – odpowiadajac
˛ y dołaczamy
˛
rozszerzenia, można
właczyć:
˛
autodoc, doctest, pngmath i viewcode – przydaja˛ si˛e w dokumentacji Pythona. Zobacz:
lista rozszerzeń Sphinksa;
• Create Makefile? – odpowiadamy y, dzi˛eki czemu budowanie dokumentacji sprowadzi si˛e do wydania
polecenia make html.
Po skonfigurowaniu Sphinksa w katalogu docs powinny znaleźć si˛e pliki: conf.py, Makefile, make.bat i
index.rst, a także katalogi _build, _static, _templates.
Jeżeli chcemy używać tematu sphinx_rtd_theme na końcu pliku conf.py dopisujemy:
try:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except:
pass
1.6.2 Tworzenie dokumentacji
Na poczatku
˛
warto dostosować plik główny, czyli index.rst. Jest on nasza˛ “strona˛ główna”,
˛ zawiera m. in.
dyrektyw˛e tworzac
˛ a˛ spis treści:
Welcome to Projekt ILO's documentation!
=======================================
Contents:
.. toctree::
:maxdepth: 2
1.6. ReStructuredText i Sphinx
21
Materiały eCG IT Documentation, Wydanie 1
Serwis eCG <http://ecg.vot.pl/>
cwiczenia/index
programowanie/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Jak widać domyślne komunikaty sa˛ w j˛ezyku angielskim, należy wi˛ec je spolszczyć zmieniaj
˛ ac
˛ treść według uznania.
Dyrektywa .. toctree:: generuje spis treści na podstawie wskazanych plików. W powyższym listingu dodano dwa przykładowe wpisy wskazujace
˛ pliki index.rst umieszczone we wskazanych podkatalogach. Sphinx
odczytuje nagłówki z tych plików i umieszcza w spisie. Domyślnie sczytywane sa˛ dwa poziomy zagnieżdżenia
(:maxdepth: 2). Gdybyśmy chcieli mieć numeracj˛e, dodalibyśmy opcj˛e: :numbered:. Pokazano również,
jak dodawać stałe linki w spisie (Serwis eCG ...).
Z sekcji indeksów (Indices ...) można usunać
˛ wszystkie spisy lub zostawić wybrane, np. genindex udost˛epnia indeks zdefiniowanych terminów i poj˛eć.
Dokumenty w katalogu docs warto kategoryzować i umieszczać w osobnych katalogach. Nazwy plików moga˛ być
dowolne, chociaż dobrze jest przyjać
˛ jakaś
˛ przejrzysta˛ konwencj˛e. Poszczególne pliki należy traktować jako kolejne
strony w wersji HTML.
1.6.3 Podstawy reST
Żeby zrozumieć proste w gruncie rzeczy zasady formatowania reST najlepiej podgladać
˛
kod gotowych stron! Wystarczy w nagłówku kliknać
˛ link View page source, skopiować, wkleić i wypełnić własna˛ treścia.˛ Zacznij od strony, która˛
czytasz...
Jeżeli chcesz rozumieć, czytaj dalej. Podstawowe zasady sa˛ nast˛epujace:
˛
• Wci˛ecia sa˛ ważne!
• Akapity itp. oddzielamy pustym wierszem.
• *pochylenie*, **pogrubienie**
• ‘‘przykład kodu‘‘
Nagłówki
Kolejne poziomy nagłówków tworzymy poprzez podkreślanie ich sekwencjami znaków:
Cz˛
eść 1
##############
Rozdział 2
**************
Sekcja 3
==============
Podsekcja 4
--------------
22
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
Podpodsekcja 5
^^^^^^^^^^^^^^
Akapit 6
""""""""""""""
Wybór znaków nie jest narzucony, ale najlepiej trzymać si˛e jednej konwencji, np. powyższej.
Dyrektywy
Ogólna postać dyrektyw to:
.. <nazwa>:: <argumenty>
:<opcja>: <wartość>
treść
Użyteczne dyrektywy:
• ..
image::
ścieżka/plik.jpg – pozwala wstawić obrazek
• ..
figure::
• ..
note:: – warte zauważenia
• ..
tip:: – wskazówka
• ..
warning:: – ostrzeżenie
• ..
highlight::
• ..
literalinclude::
• ..
code block::
• ..
raw::
• ..
include::
ścieżka/plik.jpg – pozwala wstawić obrazek z etykieta˛
cpp – formatuj kod jako cpp (lub python, bash, html itd.)
ścieżka/test.cpp – wstaw kod z podanego pliku
cpp – treść poniżej to kod w cpp (lub python, bash, html itd.)
html – interpretuj treść poniżej jako HTML
ścieżka/plik.rst – wstaw treść z innego pliku
Listy
Aby uzyskać list˛e wypunktowana˛ lub numerowana˛ stosujemy:
* punkt
* punkt drugi zawiera
dwie linie
1. punkt 1
2. punkt 2
#. automatyczne numerowanie
#. automatyczne numerowanie
Linki
• ‘Nagłówek‘_ – link do nagłówka w bieżacym
˛
dokumencie
• .. _Strona Pythona:
wstawienie linku
http:\\www.python.org – definicja linku, ‘Strona Pythona‘_ –
1.6. ReStructuredText i Sphinx
23
Materiały eCG IT Documentation, Wydanie 1
• ‘Strona Pythona <http:\\www.python.org>‘_ – tak też można
• .. _nazwa-linku: – definicja linku w dokumentacji, :ref:‘zobacz tutaj <nazwa-linku>‘
– wstawienie linku
Wskazówka: Powtórzmy, najlepsza˛ metoda˛ poznania składni reST jest przegladanie
˛
źródeł gotowych plików.
1.6.4 Budowanie dokumentacji
W katalogu głównym dokumentacji, czyli docs wydajemy polecenie:
~/projekt/docs$ make html
W terminalu zobaczymy komunikaty, niektóre z nich b˛eda˛ informacja˛ o bł˛edach w formatowaniu, które musimy
usunać.
˛ Gotowa wersja zostanie umieszczona w katalogu _build/html. Możemy go wgrać do sieci, możemy
spakować i udost˛epnić – po otwarciu pliku index.html w przegladarce
˛
zobaczymy efekt naszej pracy.
Od czasu do czasu, zwłaszcza po wielu zmianach położenia plików i katalogów, budowanie dokumentacji warto
poprzedzić usuni˛eciem poprzedniej wersji HTML:
~/projekt/docs$ make clean
1.6.5 Dokumentacja online
Projekty hostowane w serwisie GitHub łatwo podpiać
˛ do serwisu Read the Docs, który umożliwia automatyczne
generowanie wersji HTML, PDF, a nawet Epub (chociaż przy wykorzystaniu stabilnej, a nie testowej wersji Sphinksa)
i udost˛epnianie jej online.
W tym celu trzeba założyć konto na stronie Read the Docs – Sign Up. Po zalogowaniu importujemy projekt z GitHuba
(ang. Import a Project – Import from GitHub) i po potwierdzeniu domyślnych opcji możemy cieszyć wersja˛ online
dost˛epna˛ pod adresem typu: http://nazwa_projektu.readthedocs.org. Wersj˛e PDF ściagniemy
˛
po zalogowaniu, wejściu
na stron˛e projektu, wybraniu zakładki Downloads i linku latest PDF.
1.7 Serwer deweloperski WWW
Jeżeli chcemy tworzyć i testować aplikacje sieciowe wykorzystujace
˛ bazy danych za pomoca˛ j˛ezyków skryptowych,
np. PHP czy Python, potrzebujemy środowiska testowego, na które składa si˛e serwer WWW, interpreter j˛ezyka
skryptowego i system bazodanowy. Zestawy takiego oprogramowania określa si˛e skrótami WAMP lub LAMP w
zależności od wykorzystywanego systemu operacyjnego: W – Windows, L – Linux. Pozostałe litery rozwija si˛e
najcz˛eściej jako:
• A – Apache;
• M – MySQL, w linuksach raczej MariaDB;
• P – PHP, Perl lub Python.
Wymienionego oprogramowanie to najpopularniejsze, ale nie jedyne rozwiazania.
˛
Dost˛epnych jest wiele innych,
równie dobrych serwerów czy baz danych. Warto też wiedzieć, że instalacja i konfiguracja kompletu wymienionych
programów nie jest zazwyczaj konieczna. Np. jeżeli tworzymy aplikacje sieciowe w Pythonie wystarcza dedykowana
biblioteka (np. Flask) lub framework (np. Django), które zapewniaja˛ serwer HTTP i obsług˛e wbudowanej bazy
SQLite.
24
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
1.7.1 Linux
W systemach opartych na Debianie (Ubuntu, Linux Mint itd.) lub na Arch Linuksie można zainstalować serwer
Apache2 i interpreter PHP5 za pomoca˛ dedykowanych menedżerów pakietów, czyli odpowiednio:
~$ sudo apt-get install apache2 php5 php5-gd php5-sqlite php5-curl libapache2-mod-php5
~# pacman -S apache php php-gd php-sqlite php-curl libapache-mod-php5
Podstawowa konfiguracja sprowadza si˛e do uaktywnienia odpowiednich modułów:
~$ sudo a2enmod userdir rewrite
~$ sudo service apache2 restart
~# a2enmod userdir rewrite
~# systemctl restart httpd
– i odblokowania możliwości wykopnywania skryptów w katalogach domowych użytkowników poprzez zakomentowanie nast˛epujacych
˛
linii z pliku /etc/apache2/mods-available/php5.conf (Debian) lub
/etc/httpd/mods-available/php5.conf (Arch):
# To re-enable PHP in user directories comment the following lines
# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
# prevents .htaccess files from disabling it.
#<IfModule mod_userdir.c>
#
<Directory /home/*/public_html>
#
php_admin_flag engine Off
#
</Directory>
#</IfModule>
1.7. Serwer deweloperski WWW
25
Materiały eCG IT Documentation, Wydanie 1
Tworzone strony umieszczamy w podkatalogu public_html katalogu domowego. Wywołujemy je wpisujac
˛ w przegladarce
˛
adres: 127.0.0.1/~użytkownik – powinny zostać zwrócone pliki index.php
lub index.html, o ile istnieja.˛
Jeżeli mamy kilka projektów, umieszczamy je w podkatalogach, np.
public_html/projekt1 i wywołujemy: 127.0.0.1/~użytkownik/projekt1.
1.7.2 Serwer2Go w Windows
W systemie Microsoftu najłatwiej skorzystać z gotowego zestawu WAMP. Proponujemy Serwer2Go, ściagamy
˛
wersj˛e
exe Apache 1.3.35 + PHP 5.3.2, SQLite, czyli pierwsza˛ dost˛epna.˛ Nast˛epnie uruchamiamy i wskazujemy miejsce
instalacji, proponujemy główny katalog wybranego dysku, C:, D: itp.:
Po rozpakowaniu plików, wchodzimy do katalogu instalacyjnego, aby otworzyć w edytorze plik konfiguracyjny
pms_config.ini. M. in. dlatego, że Internet Explorer nie najlepiej współpracuje z serwerem, we wspomnianym pliku zmieniamy ustawienia:
26
Rozdział 1. Narzedzia
˛
Materiały eCG IT Documentation, Wydanie 1
ShowTrayIcon=1
StartLocal=1
BrowserType=FIREFOX
Oprogramowanie uruchamiamy za pomoca˛ pliku Server2Go, który uruchomi serwer WWW pod adresem
127.0.0.1:4001 w Firefoksie. Swoje strony umieszczamy w podkatalogu htdocs katalogu instalacyjnego.
1.8 Materiały
1. Edytor Geany
2. MinGw
3. J˛ezyk Python
4. Biblioteka Qt
5. Qt Creator
6. Strona projektu Git
7. First Steps with Sphinx
8. Wprowadzenie do składni Sphinx reST
9. Docutils
10. Składnia reST & Sphinx
1.8.1 Słownik
Qt zestaw bibliotek programistycznych ułatwiajacych
˛
tworzenie aplikacji z interfejsem graficznym w j˛ezykach C++,
QML i Java.
środowisko IDE zintegrowane środowisko programistyczne (ang. Integrated Development Environment, IDE), składajace
˛ si˛e z jednej lub wielu aplikacji, umożliwiajace
˛ tworzenie, testowanie, budowanie i uruchamianie kodu.
Qt Creator wieloplatformowe środowisko IDE dla aplikacji pisanych w j˛ezykach C++, JavaScript i QML. Zawiera
m.in. debugger i edytor GUI (graficznego interfejsu użytkownika).
MinGw ang. Minimalist GNU for Windows; minimalistyczne środowisko dostarczajace
˛ narz˛edzia GNU (linker,
kompilator itd.) pozwalajace
˛ na kompilacj˛e natywnych plików wykonywalnych dla Windows z kodu pisanego
w C/C++.
GNU Compiler Collection zestaw kompilatorów do różnych j˛ezyków programowania rozwijany w ramach projektu
GNU i udost˛epniany na licencji GPL oraz LGPL. Zob. hasło w Wikipedii.
GPL ang. GNU General Public License – licencja wolnego i otwartego oprogramowania stworzona w 1989 roku
przez Richarda Stallmana i Ebena Moglena na potrzeby Projektu GNU. Ostatnia wersja, trzecia, opublikowana
została 29 czerwca 2007 r. Zob. hasło w Wikipedii.
Debian jedna z najstarszych i wiad
˛ acych
˛
dystrybucji Linuksa, umożliwia elastyczna˛ konfiguracj˛e systemu i dostosowanie go do własnych potrzeb. Jak wi˛ekszość dystrybucji, umożliwia wybór wielu środowisk graficznych, np.
XFCE lub Gnome.
Xubuntu 14.04 odmiana jednej z najpopularniejszych dystrybucji Linuksa, Ubuntu, dostarczana z klasycznym, lekkim i konfigurowlanym środowiskiem graficznym XFCE.
1.8. Materiały
27
Materiały eCG IT Documentation, Wydanie 1
środowisko graficzne w systemach linuksowych zestaw oprogramowania tworzacy
˛ GUI, czyli graficzny interfejs
użytkownika, cz˛esto zawiera domyślny wybór aplikacji przeznaczonych do wykonywania typowych zadań. Najpopularnijesze środowiska to XFCE, Gnome, KDE, LXDE, Cinnamon, Mate.
serwer WWW (ang. web server) – oprogramowanie obsługujace
˛ protokół http, podstawowy protokół sieci WWW,
służacy
˛ przesyłaniu dokumentów hipertekstowych.
interpreter program, który analizuje kod źródłowy, a nast˛epnie go wykonuje. Interpretery sa˛ podstawowym składnikiem j˛ezyków wykorzystywanych do pisania skryptów wykonywanych po stronie klienta WWW (JavaScript)
lub serwera (np. Python, PHP).
system bazodanowy system zarzadzania
˛
baza˛ danych (ang. Database Management System, DBMS) – oprogramowanie służace
˛ do zarzadzania
˛
bazami danych, np. SQLite, MariaDB, MySQL, PostgreSQL.
framework (ang. framework – struktura) – oprogramowanie b˛edace
˛ zestawem narz˛edzi ułatwiajacych
˛
i przyśpieszajacych
˛
tworzenie aplikacji.
1.8.2 Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
28
Rozdział 1. Narzedzia
˛
ROZDZIAŁ 2
Linux Live USB
Scenariusze zawarte w naszym serwisie tworzone sa˛ w oparciu o system Linux, ale można je również realizować na
systemach Windows. Poniżej przedstawiamy, w jaki sposób przygotować w pełni funkcjonalna˛ dystrybucj˛e Linuksa
uruchamiana˛ z klucza USB. Może posłużyć nie tylko jako środowisko programistyczne, ale również jako podr˛eczny
sytem przenośny lub ratunkowy.
Spis treści
• Linux Live USB
– W Windows
– W Linuksie
– Pierwsze uruchomienie
– Obsługa LxPupTahr
˛
z internetem
* Połaczenie
˛
WWW
* Przegladarka
* Domyślne katalogi
* Instalacja programów
* Skróty klawiaturowe
* Konfiguracja LXDE
* Wskazówki
– Materiały dodatkowe
2.1 W Windows
Aby w systemie MS Windows przygotować bootowalny klucz USB z możliwościa˛ zapisu ustawień i dokumentów,
wykonaj nast˛epujace
˛ czynności:
1. Pobierz program Rufus – małe, szybkie i sprawdzone (:-)) narz˛edzie do tworzenia bootowalnych kluczy USB.
Narz˛edzie nie wymaga instalacji.
2. Pobierz plik kzkbox_20150716.iso, który udost˛epniamy pod adresem: Copy.com. Plik zawiera dostosowany obraz systemu LxPupTahr 15.05.01 z pulpitem LXDE.
3. Przygotuj pendrajwa o pojemności min. 2GB zawierajacego
˛
jedna,˛ główna,˛ aktywna˛ partycj˛e FAT32. Taka
partycja jest domyślna na wi˛ekszości kluczy. Pami˛etaj, że zostanie ona sformatowana! A wi˛ec zarchiwizuj
ewentualne dane. Podłacz
˛ nap˛ed do komputera i sprawdź, jaka˛ liter˛e przydzielił mu system.
4. Uruchom program Rufus z uprawnieniami administratora(!):
• z listy “Urzadzenie”
˛
wybierz pendrajwa kierujac
˛ si˛e oznaczeniem literowym i pojemnościa;
˛
29
Materiały eCG IT Documentation, Wydanie 1
Rys. 2.1: Pulpit LxPupTahr ze środowiskiem LXDE
• zaznacz w razie potrzeby opcj˛e “Szybkie formatowanie” (domyślna)
• zaznacz opcj˛e “Utwórz bootowalny dysk używajac”
˛ -> “Obraz ISO”, kliknij ikon˛e obok i wskaż ściagni˛
˛ ety
plik kzkbox_20150716.iso;
• wybierz “Opcje formatowania” i zaznacz “Dodaj łatk˛e dla starych biosów”;
• kliknij “Start” i po 4-5 min. powinieneś zobaczyć napis “Gotowe”.
Możesz już spróbować uruchomić komputer z wykorzystaniem tak przygotowanego pendrajwa. Wystarczy, że podczas
uruchamiania wciśniesz odpowiedni klawisz, najcz˛eściej F1, F2, F10, F12 lub DEL.
2.2 W Linuksie
• W Ubuntu i pochodnych instalujemy program Unetbootin poleceniami:
~$ sudo apt-add-repository ppa:gezakovacs/ppa
~$ sudo apt-get update
~$ sudo apt-get install unetbootin
• W Debianie Jessie 8 ściagamy
˛
pakiet unetbootin_608-1_i386.deb, a nast˛epnie w katalogu z pobranym plikiem
wydajemy polecenia jako root:
~# dpkg -i unetbootin_608-1_i386.deb
~# apt-get install -f
• W Arch Linuksie i pochodnych jako root wydajemy polecenia:
~# pacman -Syu
~# pacman -S unetbootin
30
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.2. W Linuksie
31
Materiały eCG IT Documentation, Wydanie 1
• Wpinamy pendrajwa o pojemności min. 4GB dla dystrybucji SRU (Xubuntu). Pendrajw powinien mieć przynajmniej jedna˛ główna˛ i aktywna˛ partycj˛e FAT32 – tak jest zazwyczaj.
• Po uruchomieniu programu “Unetbootin” zaznaczamy opcj˛e “Obraz dysku”, klikamy przycisk ”...” i wskazujemy pobrany obraz.
• Jeżeli wybraliśmy obraz Xubuntu, SRU lub FREE_DESKTOP, w polu “Przestrzeń używana do zachowania
plików...” wpisujemy min. 512. Jeżeli wybraliśmy obraz LxPupTahr przechodzimy do nast˛epnego punktu.
• Upewniamy si˛e, że w polu “Nap˛ed:” wyświetlona jest litera przydzielona właściwemu pendrajwowi i klikamy
“OK”. Czekamy w zależności od wybranej dystrybucji i pr˛edkości klucza USB od 1-20 minut.
2.3 Pierwsze uruchomienie
Po pierwszym uruchomieniu zatwierdź okno kreatora ustawień przyciskiem “Ok” i zamknij kreator połaczenia
˛
z internetem. Nast˛epnie:
• skonfiguruj typ klawiatury, aby działały skróty klawiszowe;
• zamknij system, aby zapisać ustawienia i utworzyć plik zapisu.
Po ponownym uruchomieniu system gotowy b˛edzie do pracy :-)
32
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4 Obsługa LxPupTahr
System w dostosowanej wersji zawiera:
• spolszczone prawie wszystkie elementy systemu;
• zaktualizowane listy oprogramowania;
• zaktualizowana˛ i spolszczona˛ przegladark˛
˛
e Pale Moon <https://www.palemoon.org/>_ (otwartoźrodłówa,
oparta na Firefoksie);
• fonty Ubuntu oraz podstawowe z Windows;
• pakiety python-pip, python-virtualenv, git oraz bibliotek˛e Pygame;
• skonfigurowane środowiska programistyczne Geany IDE oraz Sublime Text 3;
• możliwość łatwej instalacji środowiska PyCharm Proffesional;
• skonfigurowane elementy interfejsu LXDE;
• skonfigurowane skróty klawiszowe.
Wszystkie pozostałe biblioteki potrzebne do realizacji Szkolenia z Pythona Kzk zainstalujemy przy użyciu narz˛edzia
pip.
2.4.1 Połaczenie
˛
z internetem
System LxPupTahr domyślnie wczytuje si˛e w całości do pami˛eci RAM i uruchamia środowisko graficzne LXDE z
zalogowanym użytkownikiem root, czyli administratorem w systemach linuksowych. Na poczatku
˛
b˛edziesz chciał
nawiazać
˛ połaczenie
˛
z internetem.
Z menu “Start/Konfiguracja” uruchamiamy Internet kreator połaczenia,
˛
klikamy “Wired or wireless LAN”, w nast˛epnym oknie wybieramy narz˛edzie “Simple Network Setup”.
Po jego uruchomieniu powinniśmy zobaczyć list˛e wykrytych interfejsów, z której wybieramy eth0 dla połaczenia
˛
kablowego, wlan0 dla połaczenia
˛
bezprzewodowego. W przypadku eth0 połaczenie
˛
powinno zostać skonfigurowane
od razu, natomiast w przypadku wlan0 wskazujemy jeszcze odpowiednia˛ sieć, metod˛e zabezpieczeń i podajemy hasło.
Jeżeli uzyskamy połaczenie,
˛
w oknie “Network Connection Wizard/Kreator Połaczenia
˛
Sieci” zobaczymy aktywne
interfejsy. Sugerujemy kliknać
˛ “Cancel/Anuluj”, a w ostatnim oknie informacyjnym “Ok”.
2.4.2 Przegladarka
˛
WWW
Domyślna˛ przegladark
˛
a˛ jest PaleMoon, otwartoźródłowa odmiana oparta na Firefoksie. Od czasu do czasu warto ja˛
zaktualizować.
2.4.3 Domyślne katalogi
• /root/my-documents lub /root/Dokumenty
• /root/my-documents/clipart lub /root/Pobrane - tu zapisywane sa˛ pliki pobierane z internetu
• /root/my-documents/clipart lub /root/Obrazy
• /root/my-documents/tmp lub /root/tmp - katalogi tymczasowe
• /usr/share/fonts/default/TTF/ – dodatkowe czcionki TrueType, np. z MS Windows
2.4. Obsługa LxPupTahr
33
Materiały eCG IT Documentation, Wydanie 1
2.4.4 Instalacja programów
Jeżeli chcemy coś doinstalować, uruchamiamy Quickpet tahr z menu “Start/Konfiguracja”. Na poczatku
˛
klikamy
“tahrpup updates”, aby zaktualizować list˛e dost˛epnych aplikacji. Nast˛epnie restartujemy program i sprawdzamy, czy
w poszczególnych zakładkach znajdziemy potrzebne nam narz˛edzia, np.: Firefox, Chrome, Flash, Skype i inne.
Jeżeli w Quickpet tahr nie znajdziemy wymaganej aplikacji, uruchamiamy Puppy Package Manager/Puppy Manager Pakietów z menu “Start/Konfiguracja”. Aktualizujemy list˛e dost˛epnych aplikacaji: klikamy ikon˛e ustawień
obok koła ratunkowego, w nast˛epnym oknie zakładk˛e “Update database/Aktualizuj baz˛e danych” i przycisk “Update
now/Aktualizuj teraz”. Po uruchomieniu okna terminala naciskamy klawisze ENTER klika razy, aby potwierdzić aktualizacj˛e repozytoriów. Na koniec zamykamy okno aktualizacji przyciskiem “OK”, co zrestartuje menedżera pakietów.
Po ponownym uruchomieniu PPM, wpisujemy nazw˛e szukanego pakietu w pole wyszukiwania, nast˛epnie wybieramy
pakiet z wyświetlonej listy, co dodaje go do kolejki. W ten sposób możemy wyszukać i dodać kilka pakietów na raz.
Na koniec zatwierdzamy instalacj˛e przyciskiem “Do it!”
Wskazówka: Trzeba pami˛etać, że używamy dystrybucji okrojonej, wi˛ec nie wszystko warto instalować z repozytoriów, bo nie zawsze znajdziemy tam oprogramowanie odpowiednio dostosowane do naszej dystrybucji.
LxPup oferuje jednak dwa inne sposoby doinstalowywania oprogramowania na żadanie!
˛
Pierwszy to paczki w formacie PET, dost˛epne np. na stronie pet_packages-tahr <http://distro.ibiblio.org/puppylinux/pet_packages-tahr/>. Ścia˛
gamy je, a nast˛epnie instalujemy dwukrotnie klikajac
˛ (uruchomi si˛e narz˛edzie petget).
Drugim formatem stosowanym dla dużych pakietów, które używamy od czasu do czasu, jest format SFS. Spakowane
w ten sposób oprogramowanie możemy dodawać “w locie” w trakcie działania systemu. Korzystamy z narz˛edzia
SFS-Load w locie (Start/Konfiguracja).
Wskazówka:
Duże pliki SFS itp. zasoby warto przechowywać nie w katalogu domowym /root, ale
w katalogu głównym startowego pendrajwa. Jest on łatwo dost˛epny podczas pracy z systemem w ścieżce
/initrd/mnt/dev_save/, łatwo go również otworzyć z lewego panelu w menedżerze plików. Zazwyczaj ozna34
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
35
Materiały eCG IT Documentation, Wydanie 1
czony b˛edzie sdb1.
2.4.5 Skróty klawiaturowe
Uwaga: Poniższe skróty zadziałaja,˛ jeżeli ustawimy odpowiedni typ klawiatury. Procedura jest bardzo prosta.
Uruchamiamy “Ustawienia Puppy” (pierwsza ikona obok przycisku Start, lub Start/Konfiguracja/Wizard Kreator),
wybieramy “Mysz/Klawiatura”. W nast˛epnym oknie “Zaawansowana konfiguracja”, potwierdzamy “OK”, dalej
“Model klawiatury” i na koniec zaznaczamy “pc105”. Pozostaje potwierdzenie “OK” i jeszcze klikni˛ecie przycisku
“Tak” w poprzednim oknie, aby aktywować ustawienia.
Oznaczenia: C – Control, A – Alt, W - Windows (SuperKey).
• C+A+Left - puplpit lewy
• C+A+Right - pulpit prawy
• Alt + Space - menu okna
• C+Esc - menu start
• C+A+Del - menedżer zadań
• W+f - menedżer plików (pcmanfm)
• W+t - terminal (LXTerminal)
• W+e - Geany IDE
• W+s - Sublime Text 3
• W+p - PyCharm IDE
36
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
37
Materiały eCG IT Documentation, Wydanie 1
38
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
39
Materiały eCG IT Documentation, Wydanie 1
40
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
41
Materiały eCG IT Documentation, Wydanie 1
42
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
43
Materiały eCG IT Documentation, Wydanie 1
• W+w - przegladarka
˛
WWW (Palemoon)
2.4.6 Konfiguracja LXDE
• Wyglad,
˛ Ikony, Tapeta, Panel: Start/Pulpit/Zmiana wygladu.
˛
• Ekran(y): Start/System/System/Ustawienia wyświetlania.
• Czcionki: Start/Pulpit/Desktop/Manager Fontu.
• Menedżer plików: Edycja/Preferencje w programie.
• Ustawienia Puppy: Start/Konfiguracja/Wizard Kreator
• Internet kreator połaczenia:
˛
Start/Konfiguracja
• Zmiana rozmiaru pliku zapisu: Start/Akcesoria
• Puppy Manager Pakietów: Start/Konfiguracja
• Quickpet tahr: Start/Konfiguracja
• SFS-załadowanie w locie: Start/Konfiguracja/SFS-Załadowanie w locie
• QuickSetup ustawienia pierwszego uruchamiania: Start/Konfiguracja
• Restart menedżera okien (RestartWM): Start/Zamknij
• WM Switcher – switch windowmanagers:
• Startup Control – kontrola aplikacji startowych: Start/Konfiguracja
• Domyślne aplikacje: Start/Pulpit/Preferowane programy
• Terminale Start/Akcesoria
44
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.4. Obsługa LxPupTahr
45
Materiały eCG IT Documentation, Wydanie 1
46
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
• Ustawienie daty i czasu: Start/Pulpit
2.4.7 Wskazówki
1. Dwukrotne klikni˛ecie – menedżer plików PcManFm domyślnie otwiera pliki i katalogi po pojedynczym klikni˛eciu. Jeżeli chcielibyśmy to zmienić, wybieramy “Edycja/Preferencje”.
2.5 Materiały dodatkowe
Informacja: Win˛e za niebootujacy
˛ system z klucza USB cz˛eściej ponosi sprz˛et niż sam pendrajw czy nagrany na
nim system. Niestety, dotyczy to głównie przestarzałych maszyn oraz... najnowszych. Pierwsze maja˛ niedostosowany
BIOS, drugie zbyt “nowe” komponenty, do których może brakować sterowników. Problematyczne moga˛ być też
laptopy z biosem UEFI, plus SecureBoot, z preinstalowanym “jedynym słusznym” systemem... Przeczytaj rozdział
“Problemy”.
2.5.1 Puppy Linux
LxPupTahr to wersja systemu Puppy Linux 6.0.3 tahrpup CE opartego na systemie Ubuntu Tahr 14.04 LTS. Puppy
Linux to dystrybucja zaprojektowanych specjalnie do pracy w trybie live, ale z możliwościa˛ przechowywania dokonywanych zmian, takich jak dodawanie/usuwanie oprogramowanie, zmienianie ustawień, tworzenie dokumentów.
LxPupTahr
Zaproponowana przez nas wersja jest dostosowana do potrzeb szkoleń z Pythona. Bez problemu można jednak przygotować swoja˛ wersj˛e. Wystarczy pobrać oryginalny obraz LxPupTahr-15.05.1-pae.iso (251 MB) i wgrać go na pendrajwa.
TahrPup
W systemie TahrPup domyślne środowisko graficzne jest połaczeniem
˛
menedżera okien JVM z pulpitem ROX Desktop i menedżerem plików ROX-Filer. Łatwo je wypróbować. Wystarczy pobrać plik tahr-6.0.2_PAE.iso (ok. 201
MB). W wersji tej łatwo doinstalować środowisko XFCE.
Plik zapisu
Jeżeli omawiane systemy uruchamiany po raz pierwszy (w zasadzie wtedy, kiedy nie ma żadnego pliku zapisu), wita
nas kreator konfiguracji, a system ma interfejs w j˛ezyku angielskim. Dostosowywanie systemu i tworzenie pliku
zapisu omówione zostały w rozdziale Konfiguracja Można tego uniknać,
˛ jeżeli dysponujemy jakimś przygotowanym
plikiem zapisu (ang. savefile).
W serwisie Copy.com udost˛epniliśmy plik lxtahrsave-lxde.2fs oraz tahrsave-xfce.2fs. Pierwszy
przeznaczony jest dla LxPupTahr, drugi dla TahrPup. Należy wgrać je do głównego katalogu pendrajwa. Trzeba
również pobrać pakiet jre1.7.0_65_5.7.0.sfs i umieścić go w tym samym miejscu co plik zapisu.
Plik zapisu zawiera konfiguracj˛e systemu, czyli:
• zaktualizowane listy oprogramowania;
2.5. Materiały dodatkowe
47
Materiały eCG IT Documentation, Wydanie 1
Rys. 2.2: Pulpit LxPupTahr ze środowiskiem LXDE
Rys. 2.3: Pulpit PupThar ze środowiskiem JVM/ROX
48
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
Rys. 2.4: Pulpit PupTahr ze środowiskiem XFCE
• zaktualizowana˛ i spolszczona˛ domyślna˛ przegladark˛
˛
e Pale Moon <https://www.palemoon.org/>_ (otwartoźrodłówa, oparta na Firefoksie);
• fonty Droid, Ubuntu oraz podstawowe z Windows;
• pakiety python-pip, python-virtualenv oraz bibliotek˛e pygame;
• skonfigurowane mini środowisko programistyczne IDE – Geany.
• środowisko PyCharm IDE Educational
• skonfigurowane elementy interfejsu LXDE lub JVM/ROX i XFCE
Uwaga: Na pendrajwie nie może znajdować si˛e żaden inny plik o nazwie rozpoczynajacej
˛ si˛e na (lx)tahrsave.
Ewentualne utworzone wcześniej pliki zapisu trzeba albo skasować, albo zmienić im nazwy.
ZALECAMY powi˛ekszyć rozmiar pliku zapisu do 1024 MB za pomoca˛ narz˛edzia: Zmiana rozmiaru pliku
osobistego przechowywania (Start/Setup).
Informacja: Nazwa pliku pupsave zawsze zaczyna si˛e “(lx)tahrsave-”, np.: lxtahrsave-lxde.2fs. Położenie jest... dowolne, tzn. można go zapisać na kluczu USB, ale równie dobrze może być zapisany na dowolnej partycji
szybkiego dysku stacjonarnego. Podczas uruchamiania system potrafi odnaleźć ten plik na wszystkich dost˛epnych
partycjach i załadować go!
Wskazówka: Pracujac
˛ w systemie, mamy dost˛ep do głównego katalogu naszego pendrajwa (zazwyczaj oznaczonego
w menedżerze plików sdb1). Możemy w nim tworzyć dowolne foldery i zapisywać pliki, np. pet i sfs, z których
b˛edziemy korzystać w miar˛e potrzeb. Dzi˛eki temu unikniemy zb˛ednego rozrastania si˛e pliku zapisu. Należy uważać,
aby z katalogu głównego nie usunać
˛ plików systemowych.
Przechowywanie ustawień i dokumentów w pliku zapisu ma swoje zalety:
2.5. Materiały dodatkowe
49
Materiały eCG IT Documentation, Wydanie 1
• wystarczy usunać
˛ omawiany plik, a system uruchomi si˛e w wersji domyślnej; b˛edzie można skonfigurować go
od podstaw;
• można udost˛epniać innym pliki zapisu; wystarczy, że wgraja˛ go na pendrajwa przygotowanego zgodnie z nasza˛
instrukcja,˛ a dostana˛ skonfigurawane środowisko i programy, a nawet ewentualne dokumenty.
Ostatecznie zawartość katalogu głównego pendrajwa przedstawiać powinna si˛e nast˛epujaco:
˛
Rys. 2.5: Katalog główny pendrajwa z systemem LXPupTahr
Nazwa pliku zapisu (persystencji) w systemie TahrPup zaczyna si˛e zawsze od tahrsave-. Przykładowy plik udost˛epniamy udost˛epniamy w serwisie Copy.com pod nazwa˛ tahrsave-xfce.2fs. Zawiera on wst˛epna˛ konfiguracj˛e oraz nast˛epujace
˛ dostosowania:
W systemie TahrPup pulpit JVM/ROX uruchomić można przy użyciu narz˛edzia WM Switcher – przełaczanie
˛
menedżerów okien.
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
2.5.2 Konfiguracja
Jeżeli nie chcesz używać udost˛epnionych przez nas plików zapisu, możesz sam skonfigurować swój system. Poniżej
wskazówki.
50
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
Ustawienia wstepne
˛
Okno QuickSetup ustawienia pierwszego uruchamiania konfigurujemy wg zrzutu i klikamy “Ok”, dalej potwierdzamy
konieczność doinstalowania pakietu j˛ezykowego, a w trzecim oknie klikamy “Exit” – bo niczego jeszcze nie doinstalowaliśmy.
Internet
Uruchamia si˛e Internet kreator połaczenia,
˛
jeśli jesteśmy podpi˛eci do sieci kablem i dostajemy parametry przez DHCP,
powinniśmy zobaczyć komunikat “Congratulations, you are connected”. W przeciwnym razie klikamy “Wired or wireless LAN”, w nast˛epnym oknie wybieramy na poczatek
˛ narz˛edzie “Simple Network Setup”. Po jego uruchomieniu
powinniśmy zobaczyć list˛e wykrytych interfejsów, z której wybieramy wlan0 dla połaczenia
˛
bezprzewodowego. Nast˛epnie w razie potrzeby wskazujemy odpowiednia˛ sieć, metod˛e zabezpieczeń i podajemy hasło.
Jeżeli uzyskamy połaczenie,
˛
w oknie “Network Connection Wizard” zobaczymy aktywne interfejsy. Sugerujemy
kliknać
˛ “Cancel”, a w ostatnim oknie informacyjnym “Ok”. Na koniec zamykamy okno Welcome kreatora.
Przegladarka
˛
WWW
Domyślna˛ przegladark˛
˛
e Pale Moon należy od czasu do czasu aktualizować.
Start/Internet/Palemoon-updater, zaznaczamy “Update Pale Moon” i klikamy OK.
W tym celu wybieramy
Jeśli po aktualizacji przywita nas angielskoj˛ezyczny interfejs, na stronie powitalnej klikamy link “Language Packs”,
pobieramy plik tłumaczeń pl.xpi i instalujemy. Na koniec wpisujemy polu adresu polecenie “about:config”, w pole
wyszukiwania “useragent” i zmieniamy opcj˛e “general.useragent.locale” na “pl-PL” (o ile potrzeba).
2.5. Materiały dodatkowe
51
Materiały eCG IT Documentation, Wydanie 1
52
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
53
Materiały eCG IT Documentation, Wydanie 1
54
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
55
Materiały eCG IT Documentation, Wydanie 1
Dotakowe ustawienia sa˛ opcjonalne, ale wskazane. Wybieramy “Edycja/Preferencje”, aby skonfigurować stron˛e domyślna,˛ i katalog pobieranych plików, np. root/Pobrane (trzeba go utworzyć), wreszcie opcje śledzenia i historii.
Te ostatnie ustawienia wpływaja˛ na rozmiar wolnego miejsca w pliku zapisu.
Na koniec można zainstalować blocker reklam wybierajac
˛ odpowiedni dodatek, np. AdBlockEdge, albo korzystajac
˛ z narz˛edzia Pup-Advert-Blocker (Start/Internet/), w którym wybieramy serwis “Mvps.org” i klikamy ikon˛e
koła z˛ebatego. Ściagni˛
˛ eta lista zawierajaca
˛ adresy IP oraz nazwy serwerów reklamowych zostanie dodana do pliku
/etc/hosts i przekierowana na adres lokalny, co uniemożliwi jakakolwiek
˛
z nimi komunikacj˛e ;-)
Plik zapisu
Podczas pierwszego zamkni˛ecia system prosi o utworzenie pliku zapisu (ang. savefile, dodatkowe informacje zob.
w Puppy Linux), w którym zapisywane b˛eda˛ wprowadzane przez nas zmiany: konfiguracja, instalacja programów,
utworzone dokumenty.
Na poczatku
˛ może pojawić si˛e pytanie o przetłumaczenie informacji rozruchowych, wybieramy “Yes” i potwierdzamy
kolejny komunikat. Gdyby pytanie to pojawiło si˛e nast˛epnym razem, wybierz “No”.
W nast˛epnym oknie klikamy “Zapisz”, nast˛epnie “administrator”. Wybieramy partycj˛e oznaczajac
˛ a˛ pendrajwa: w
konfiguracjach z 1 dyskiem twardym b˛edzie ona oznaczona najcz˛esciej sdb1 (kierujemy si˛e rozmiarem i typem plików:
vfat).
Nast˛epnie wybieramy ewentualnie szyfrowanie i system plików. Sugerujemy ext2 – najszybszy. Minimalny rozmiar
to 32MB, zalecamy 512MB lub wi˛ecej.
Opcjonalnie rozszerzamy domyślna˛ nazw˛e i potwierdzamy zapis.
56
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
57
Materiały eCG IT Documentation, Wydanie 1
58
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
59
Materiały eCG IT Documentation, Wydanie 1
60
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
61
Materiały eCG IT Documentation, Wydanie 1
62
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
Należy spokojnie poczekać na utworzenie pliku i wyłacznie
˛
komputera.
Czcionki
Czcionki ttf wystarczy wgrać do katalogu /usr/share/fonts/default/TTF. Można użyć narz˛edzia Manager
fontów (Start/Desktop/Desktop).
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
2.5.3 JVM
Menedżer JVM wykorzystywany jest domyślnie w systemie TahrPup.
• Wyglad:
˛ Menu/Pulpit/Chtheme wybór motywu GTK; Menu/Pulpit/JVM konfiguracja/Wybierz motyw JVM.
• Tapeta: umieść plik graficzny w /root/my-documents/clipart, kliknij prawym klawiszem myszy i
wybierz “set background”.
• Ikony pulpitu i menu: Menu/Pulpit/Desktop zmiana ikony
• Czcionki: Menu/Pulpit/Manager fontu -> Wyglad,
˛ zaznaczamy wszystkie opcje, styl hintingu ustawiamy na 1.
• Menedżer plików ROX-Filer: prawy klawisz myszy w pustym oknie, wybierz “Ustawienia”; otwieranie elmentów dwukrotnym klikni˛eciem – sekcja Biurko, ikony menedżera – sekcja Typy/Style.
2.5. Materiały dodatkowe
63
Materiały eCG IT Documentation, Wydanie 1
64
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
65
Materiały eCG IT Documentation, Wydanie 1
66
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
67
Materiały eCG IT Documentation, Wydanie 1
68
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
69
Materiały eCG IT Documentation, Wydanie 1
Ustawienia i programy
• Ustawienia Puppy: [JVM] Menu/Ustawienia/Wizard Kreator
• Internet kreator połaczenia:
˛
[JVM] Menu/Ustawienia
• Zmiana rozmiaru pliku osobistego przechowywania: [JVM] ...
• Puppy Manager Pakietów: [JVM] Menu/Ustawienia
• Quickpet tahr: [JVM] ...
• SFS-załadowanie w locie: [JVM] ...
• QuickSetup ustawienia pierwszego uruchamiania: [JVM] Menu/Ustawienia
• Restart menedżera okien (RestartWM): [JVM] Menu/Wyjście
• WM Switcher – switch windowmanagers: [JVM] Menu/Pulpit
• Startup Control – kontrola aplikacji startowych: [JVM] Menu/Ustawienia
• Domyślne aplikacje: [JVM] Menu/Ustawienia/Wybór domyślnych aplikacji
• Terminale: [JVM] Menu/Narz˛edzia
• Ustawienie daty i czasu: [JVM] ...
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
2.5.4 XFCE
Jeżeli nie przypadnie nam do gustu domyślne środowisko systemu TahrPup, czyli JVM/ROX Desktop/ROX-Filer, lub
LXPupTahr – LXDE, wystarczy zaktualizować pakiety w narz˛edziu quickpet-tahr, zrestartować je, a nast˛epnie zainstalować pulpit XFCE z kategorii “desktops”. Po zakończeniu instalacji wybieramy narz˛edzie przełaczania
˛
menedżerów
okien WM Switcher (Menu/Pulpit/), zaznaczamy XFCE i klikamy przycisk “Restart X”.
• Menu “Start”: domyślnie sa˛ na pasku zadań dwa menu, tradycyjny aplet “Programy” i nowszy “Menu Whisker”.
Niepotrzebne kliknij prawym klawiszem i wybierz “Usuń”.
• Menu Whisker: prawy klawisz na ikonie i “Właściwości”; wpisywanie pierwszych liter programu wyszukuje
go w menu.
• Wyglad:
˛ Programy/Ustawienia/Wyglad
˛
• Ekran: Programy/Ustawienia/Ekran
• Tapeta i ikony pulpitu: prawy klawisz na pulpicie i “Ustawienia”; zakładka “Tło”, opcja “Katalog” pozwala
wskazać inny niż domyślny katalog z tapetami, zkładka “Ikony”, “Domyślne” – jakie ikony pokazywać.
• Czionki: Start/Ustawienia/Wyglad
˛ -> Czcionki, zaznacz “Antyaliasing”, przyciaganie
˛
“Lekkie”, podpiksele
“RGB”.
• Menedżer plików Thunar: Programy/Ustawienia/Menedżer plików lub Edycja/Preferencje w programie; zaznaczanie elementów dwukrotnym klikni˛eciem -> zakładka “Zachowanie”
• Montowanie: Programy/Ustawienia/Nap˛edy i nośniki wymienne; zaznacz “Montowanie nap˛edów...”, “Montowanie nośników...”, “Przegladanie
˛
nośników...”
• Panele (pasek zadań itp.): Programy/Ustawienia/Panel; zakładka “Aplety” pozwala dodawać, usuwać aplety,
warto dodać “Wyświetlanie pulpitu”; warto dodać również aktywatory do uruchamiania aplikacji; po zaznaczeniu aktywatora wybierz okno preferencji (druga od dołu ikona z prawej), a nast˛epnie wybierz aplikacj˛e, np.
70
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
Menedżer plików, Emulator terminala, Przegladark˛
˛
e internetu. Koniecznie dodaj aktywator dla PopShutdown
Manager. Kolejność elementów ustal przeciagaj
˛ ac
˛ je mysza.˛
• Obszary robocze: Start/Ustawienia/; ilość – 2.
• Powiazania
˛
plików z domyślnymi aplikacjami: prawy klawisz na pliku, “Właściwości” -> “Otwieranie za pomoca”,
˛ wybieramy z listy lub “Inny program”.
Ustawienia i programy
• Ustawienia Puppy: [XFCE] Programy/Puppy Setup/Puppy Setup
• Internet kreator połaczenia:
˛
[XFCE] Programy/Puppy Setup/Internet Connection Wizard
• Zmiana rozmiaru pliku osobistego przechowywania: [XFCE] Programy/Akcesoria/Resize personal storage
file
• Puppy Manager Pakietów: [XFCE] Programy/Puppy Setup/Puppy Package Manager
• Quickpet tahr: [XFCE] Programy/Puppy Setup
• SFS-załadowanie w locie: [XFCE] Programy/SFS...
• QuickSetup ustawienia pierwszego uruchamiania: [XFCE] Programy/Puppy Setup/QuickSetup...
• WM Switcher – switch windowmanagers: [XFCE] Programy/Ustawienia
• Startup Control – kontrola aplikacji startowych: [XFCE] Programy/Ustawienia/Sesja i uruchamianie
• Domyślne aplikacje: [XFCE] Programy/Ustawienia/Preferowane programy
• Terminale: [XFCE] Programy/Akcesoria
• Ustawienie daty i czasu: [XFCE] Programy/Ustawienia/Set date and time
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
2.5.5 Problemy
Jeśli nie da si˛e uruchomić komputera za pomoca˛ przygotowanego klucza, przeczytaj poniższe wskazówki.
1. Zanim uznasz, że pendrajw nie działa, przetestuj go na innym sprz˛ecie!
2. W niektórych komputerach możliwość uruchamiania z nap˛edu USB trzeba odblokować w BIOS-ie. Odpowiedniego ustawienia poszukaj w np. w opcji “Boot order”.
3. Starsze komputery stacjonarne moga˛ wymagać wejścia do ustawień BIOSU (zazwyczaj klawisz F1, F2 lub
DEL) i ustawienia pendrajwa (o ile zostanie wykryty) jako urzadzenia
˛
startowego zamiast np. dysku twardego
czy cdromu. Opuszczajac
˛ BIOS zmiany należy zapisać! Komputer restartujemy bez usuwania klucza USB.
4. W przypadku komputerów stacjonarnych, jeżeli nie działaja˛ frontowe gniazda USB, podłacz
˛ klucz z tyłu!
5. Niebootujacy
˛ pendrajw można sformatować za pomoca˛ narz˛edzia HP-USB-Disk-Storage-Format-Tool, a nast˛epnie nagrać jeszcze raz obraz (Lx)PupTahr.
6. Można wypróbować narz˛edzie Linux Live USB Creator. Użyj go do nagrania obrazu (Lx)PupTahr:
7. Spróbuj z innym pendrajwem.
8. Zmień maszyn˛e, być może jest za stara lub za nowa!
2.5. Materiały dodatkowe
71
Materiały eCG IT Documentation, Wydanie 1
72
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
73
Materiały eCG IT Documentation, Wydanie 1
9. Jeżeli masz bios UEFI z właczonym
˛
mechanizmem SecureBoot, co stanowi norm˛e dla laptopów z preinstalowanym Windows 7/8/... Spróbuj wyłaczyć
˛
zabezpieczenie w biosie, możesz zajrzeć do instrukcji:
• pomoc Ubuntu
• pomoc Microsoft
• wsparcie HP
Inne narzedzia
˛
Wskazówka: Cz˛eść narz˛edzi udost˛epnia serwis dobreprogramy.pl, niestety sugeruje użycie dodatkowej aplikacji do pobierania, ukrytej pod przycieskiem “Pobierz program”. Sugerujemy używanie przycisku “Linki bezpośrednie” i wybór odpowiedniej wersji (32-/64-bitowej), jeżeli jest dost˛epna.
• USB Image Tool – narz˛edzie do robienia obrazów dysków USB i nagrywania ich na inne pendrajwy.
• Image USB – świetny program do tworzenia obrazów nap˛edów USB i nagrywania ich na wiele pendrajwów
jednocześnie.
• Bootice – opcjonalne narz˛edzie do różnych operacji na dyskach. Za jego pomoca˛ można np. utworzyć, a
nast˛epnie odtworzyć kopi˛e MBR pendrajwa.
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
74
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
75
Materiały eCG IT Documentation, Wydanie 1
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
76
Rozdział 2. Linux Live USB
Materiały eCG IT Documentation, Wydanie 1
2.5. Materiały dodatkowe
77
Materiały eCG IT Documentation, Wydanie 1
78
Rozdział 2. Linux Live USB
ROZDZIAŁ 3
Biblioteka Qt
Poniżej przedstawiamy realizacj˛e przykładowej aplikacji w Qt 5.
3.1 Adresy (Qt5)
Niniejszy scenariusz pokazuje, jak zaczać
˛ programowanie z wykorzystaniem biblioteki Qt w wersji 5 przy użyciu
dedykowanego środowiska IDE Qt Creator. Celem jest stworzenie prostej 1-okienkowej ksia˛żki adresowej, w której
można dodawać dane adresowe powiazane
˛
z określona˛ nazwa,˛ np. imieniem i nazwiskiem.
•
•
•
•
•
•
•
•
Nowy projekt
Tworzenie interfejsu
Deklaracje i implementacje
Sygnały i sloty
Dodawanie adresów
Tryb nawigacji
Edycja i usuwanie
Materiały
3.1.1 Nowy projekt
Po uruchomieniu aplikacji Qt Creator wybieramy przycisk “New Project”, który uruchamia kreatora aplikacji.
W pierwszym oknie “Applications” i “Qt Widget Applications”, co oznacza, że chcemy utworzyć program z interfejsem graficznym oparty na klasie QWidget. W nast˛epnym oknie podajemy nazw˛e projektu, np, “adresy”, oraz
wskazujemy ścieżk˛e do katalogu, w którym b˛eda˛ zapisywane pliki wchodzace
˛ w skład projektu. W nast˛epnym oknie
wybieramy tzw. “kit”, czyli zestaw definiujacy
˛ docelowe środowisko, kompilator itp. ustawienia. Dost˛epne zestawy
musza˛ być wcześniej określone w ustawieniach Qt Creatora
Kolejne okno pozwala definiować nazw˛e klasy głównej i klas˛e podstawowa,˛ podajemy “adresy” i wybieramy “QWidget”. W nast˛epnym ostatnim oknie niczego nie zmieniamy, kończymy klikni˛eciem przycisku “Finish”.
Efektem działania kreatora b˛edzie utworzenie nast˛epujacych
˛
plików:
1) adresy.h - plik nagłówkowy, tutaj b˛edziemy deklarować wszystkie używane w programie obiekty
(elementy interfejsu), a także publiczne sloty, czyli funkcje powiazanie
˛
z określonymi sygnałami (zdarzeniami).
2) adresy.cpp - plik źródłowy, tu znajdzie si˛e kod tworzacy
˛ obiekty interfejsu, łacz
˛ acy
˛ sygnały ze
slotami, a wreszcie implementacja slotów.
79
Materiały eCG IT Documentation, Wydanie 1
3) main.cpp - plik źródłowy, w którym tworzona i uruchamiana jest instancja naszej aplikacji.
4) adresy.ui - jak wskazuje rozszerzenie (“ui” - ang. user interface), plik zawierać b˛edzie opis graficznego interfejsu aplikacji zapisany za pomoca˛ znaczników XML.
3.1.2 Tworzenie interfejsu
Zaczniemy od utworzenia głównego okna naszej aplikacji. W tym celu dwa razy klikamy plik adresy.ui i przechodzimy
do tworzenia formularza.
Na poczatku
˛
klikamy obiekt “Grid Layout” z kategorii “Layouts” i rysujemy prostokat
˛ na formularzu tak, aby nie
wypełniał go w całości. Dodana kontrolka umożliwia porzadkowanie
˛
innych elementów tworzacych
˛
interfejs w prostokatnej
˛
siatce. Dalej dodamy dwie etykiety, czyli obiekty “Label” z kategorii “Display Widgets”. Staramy si˛e je
umieścić jedna nad druga˛ w dodanej przed chwila˛ siatce.
Wskazówka: Po wybraniu obiektu i najechaniu na Grid Layout należy obserwować niebieskie podświetlenia, które
pojawiaja˛ si˛e w pionie i poziomie, wskazuja˛ one, gdzie umieszczony zostanie dodawany obiekt.
Po dwukrotnym klikni˛eciu na dodane etykiety możemy zmienić treść przez nie wyświetlana.˛ Modyfikujemy w ten
sposób właściwość text danego obiektu. Etykieta górna powinna zawierać tekst “Nazwa”, dolna - “Adresy”.
Informacja: Lista wszystkich obiektów wyświetlana jest po prawej stronie na górze w oknie Hierarchia obiektów.
W kolumnie Obiekt widzimy tam nazwy dodanych obiektów, a w kolumnie Klasa nazwy klas, które reprezentuja.˛
Po wskazaniu mysza˛ dowolnego obiektu możemy edytować wszystkie jego właściwości poniżej. Np. nazw˛e obiektu
zmienimy w polu objectName.
Nazw˛e etykiety górnej ustalamy na “nazwaLbl”, dolnej - na “adresyLbl”.
Wskazówka: Konwencji nazywania obiektów jest wiele, ważne żeby konsekwentnie trzymać si˛e wybranej. Tutaj
proponujemy uwzgl˛ednianie w nazwie typu obiektu przy użyciu skrótu pisanego z dużej litery, np. “nazwaLbl”.
Po prawej stronie etykiety “Nazwa” dodajemy kontrolk˛e Line Edit z grupy Input Widgets o nazwie “nazwaLine”.
Poniżej, czyli w drugiej kolumnie, tworzymy obiekt Text Edit z tej samej grupy, co poprzedni o nazwie “adresText”.
Powinniśmy uzyskać poniższy układ:
Czas na dodanie przycisków pozwalajacych
˛
inicjować działanie aplikacji. Dodajemy wi˛ec 5 przycisków PushButton z
kategorii Buttons po prawej stronie i poza(!) obiektem GridLayouts jeden pod drugim. Na samym dole umieszczamy
kontrolk˛e Vertical Spacer z kategorii Spacers. Nast˛epnie zaznaczamy wszystkie dodane obiekty, obrysowujac
˛ je
myszka,˛ i klikamy ikon˛e Rzmieść w pionie (CTRL+L) na pasku narz˛edziowym. Teraz stworzona˛ grup˛e przeciagamy
˛
na siatk˛e jako 3. kolumn˛e.
Musimy zmienić nazwy i tekst dodanych przycisków. Od góry ustawiamy kolejne właściwości (nazwa/tekst): “dodajBtn/Dodaj”, “zapiszBtn/Zapisz”, “anulujBtn/Anuluj”, “edytujBtn/Edytuj”, “usunBtn/Usuń”. W efekcie powinniśmy uzyskać nast˛epujac
˛ a˛ formatk˛e:
Musimy dodać jeszcze 3 przyciski pozwalajace
˛ na nawigacj˛e mi˛edzy adresami i wyjście z programu. Poniżej obiektu
siatki umieszczamy wi˛ec 2 przyciski (PushButton), zaznaczamy je i klikamy ikon˛e Rozmieść poziomo w splitterze,
nast˛epnie przeciagamy
˛
grup˛e na dół 2. kolumny siatki. Na koniec dodajemy jeszcze jeden przycisk na dole 3. kolumny. Dodanym obiektom zmieniamy właściwości (nazwa/tekst): “poprzBtn/Porzedni”, “nastBtn/Nast˛epny”, “koniecBtn/Koniec”.
Na koniec zaznaczamy formularz główny, na którym znajduja˛ si˛e wszystkie elementy interfejsu i klikamy przycisk
Rozmieść w siatce (CTRL+G). Dzi˛eki temu kontrolki b˛eda˛ skalowane wraz ze zmiana˛ rozmiaru okna.
W sumie uzyskujemy poniższy projekt:
80
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
3.1. Adresy (Qt5)
81
Materiały eCG IT Documentation, Wydanie 1
Możemy uruchomić nasza˛ aplikacj˛e, wybierajac
˛ Budowanie/Uruchom (CTRL+R) lub klikajac
˛ trzecia˛ od dołu ikon˛e
zielonego trójkata
˛ w lewej kolumnie Qt Creatora. Powinniśmy zobaczyć podobne do poniższego okno:
3.1.3 Deklaracje i implementacje
Po dodaniu elementów interfejsu musimy zadeklarować zmienne, za pomoca˛ których b˛edziemy mogli nimi manipulować. Przechodzimy do pliku adresy.h i wprowadzamy poniższe zmiany:
1
2
#ifndef ADRESY_H
#define ADRESY_H
3
4
5
6
7
8
#include
#include
#include
#include
#include
<QWidget>
<QLineEdit>
<QTextEdit>
<QPushButton>
<QTextCodec>
9
10
11
12
namespace Ui {
class adresy;
}
13
14
15
16
class adresy : public QWidget
{
Q_OBJECT
17
18
19
20
public:
explicit adresy(QWidget *parent = 0);
~adresy();
21
82
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
22
23
24
25
26
27
28
29
30
31
32
33
34
private:
Ui::adresy *ui;
QPushButton *dodajBtn;
QPushButton *zapiszBtn;
QPushButton *anulujBtn;
QPushButton *poprzBtn;
QPushButton *nastBtn;
QPushButton *edytujBtn;
QPushButton *usunBtn;
QPushButton *koniecBtn;
QLineEdit *nazwaLine;
QTextEdit *adresText;
};
35
36
#endif // ADRESY_H
Na poczatku
˛
musimy zaimportować klasy, z których skorzystaliśmy przy budowie interfejsu. Najważniejsza˛ jest
klasa podstawowa wszystkich elementów interfejsu, czyli QWidget. Kolejne trzy odpowiadaja˛ wykorzystanym przez
nas kontrolkom edycyjnym i przyciskom. Dodatkowa klasa QTextCodec pozwoli poprawnie wyświetlać polskie
znaki. W wewnatrz
˛ naszej klasy głównej, której deklaracja rozpoczyna si˛e w linii 14., deklarujemy prywatne (private)
właściwości, których nazwy odpowiadaja˛ nazwom wcześniej dodanych elementów interfejsu graficznego. Formalnie
każda zmienna jest wskaźnikiem do obiektu odpowiedniego typu.
W pliku adresy.cpp korzystamy ze zadekarowanych zmiennych, aby ustawić poczatkowe
˛
właściwości obiektów
składajacych
˛
si˛e na interfejs użytkownika.
1
2
#include "adresy.h"
#include "ui_adresy.h"
3.1. Adresy (Qt5)
83
Materiały eCG IT Documentation, Wydanie 1
3
4
5
6
7
8
adresy::adresy(QWidget *parent) :
QWidget(parent),
ui(new Ui::adresy)
{
ui->setupUi(this);
9
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
10
11
nazwaLine = new QLineEdit;
nazwaLine = ui->nazwaLine;
nazwaLine->setReadOnly(true);
12
13
14
15
adresText = new QTextEdit;
adresText = ui->adresText;
adresText->setReadOnly(true);
16
17
18
19
dodajBtn = new QPushButton;
dodajBtn = ui->dodajBtn;
20
21
22
zapiszBtn = new QPushButton;
zapiszBtn = ui->zapiszBtn;
zapiszBtn->hide();
23
24
25
26
anulujBtn = new QPushButton;
anulujBtn = ui->anulujBtn;
anulujBtn->hide();
27
28
29
30
nastBtn = new QPushButton;
nastBtn = ui->nastBtn;
nastBtn->setEnabled(false);
31
32
33
34
poprzBtn = new QPushButton;
poprzBtn = ui->poprzBtn;
poprzBtn->setEnabled(false);
35
36
37
38
edytujBtn = new QPushButton;
edytujBtn = ui->edytujBtn;
edytujBtn->setEnabled(false);
39
40
41
42
usunBtn = new QPushButton;
usunBtn = ui->usunBtn;
usunBtn->setEnabled(false);
43
44
45
46
koniecBtn = new QPushButton;
koniecBtn = ui->koniecBtn;
koniecBtn->setEnabled(true);
47
48
49
50
setWindowTitle(trUtf8("Prosta ksia˛żka adresowa"));
51
52
}
53
54
55
56
57
adresy::~adresy()
{
delete ui;
}
W obr˛ebie konstruktora głównej klasy naszej aplikacji o nazwie adresy, którego definicja rozpoczyna si˛e w linii
4., tworzymy instancje klas użytych w interfejsie graficznym. Do zmiennych zadeklarownych w pliku adresy.h
84
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
przypisujemy obiekty utworzone za pomoca˛ operatora new, a nast˛epnie definiujemy ich poczatkowe
˛
właściwości.
Konstruktorowi odpowiada zawzwyczaj destruktur, a wi˛ec działanie, które usuwa stworzony obiekt, w tym wypadku
interfejs użytkownika: adresy::~adresy().
Aby określić stan elementów interfejsu wykorzystujemy odpowiednie właściwości i metody reprezentujacych
˛
je obiektów.
Np.
właściwość setReadOnly(true) blokuje edycj˛e danego elementu, a właściwość
setEnabled(false) uniemożliwia klikni˛ecie danego przycisku. Metoda hide() ukrywa obiekt.
Instrukcja QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")) określa
kodowanie komunikatów w standardzie “UTF-8” używanych w aplikacji, które wprowadzane sa˛ dalej za pomoca˛
funkcji trUtf8(). Tak dzieje si˛e np. podczas określania tytułu okna w wywołaniu setWindowTitle().
Wskazówka: W środowisku MS Windows kodowanie powinno zostać ustawione na Windows-1250.
Dzi˛eki powyższym uzupełnieniom po uruchomieniu aplikacji pola nazwy i adresu b˛eda˛ nieaktywne, b˛edziemy mogli
natomiast użyć przycisków Dodaj, aby utworzyć nowy wpis, lub Koniec, aby zakończyć aplikacj˛e.
3.1.4 Sygnały i sloty
Działanie aplikacji z interfejsem graficznym polega w uproszczeniu na reagowaniu na działania użytkownika, takie
jak np. klikni˛ecie, naciśni˛ecie klawisza, przeciagni˛
˛ ecie itp. Wszystkie zdarzenia generowane z poziomu interfejsu
użytkownika w terminologii biblioteki Qt emituja˛ tzw. sygnały. Programista decyduje o tym, które z nich i jak sa˛
obsługiwane, definiujac
˛ tzw. sloty, czyli funkcje powiazane
˛
z określonymi zdarzeniami. Mechanizm sygnałów i
slotów umożliwia komunikacj˛e mi˛edzy obiektami aplikacji.
Każda z funkcji obsługujacych
˛
zdarzenia musi zostać najpierw zadeklarowana w pliku adresy.h w sekcji public
slots:, ich implementacj˛e musimy dopisać później do pliku adresy.cpp.
3.1. Adresy (Qt5)
85
Materiały eCG IT Documentation, Wydanie 1
18
19
20
public:
explicit adresy(QWidget *parent = 0);
~adresy();
21
enum Tryb { nawigujT, dodajT, edytujT };
22
23
24
25
26
public slots:
void dodajKontakt();
void koniec();
27
28
29
30
31
32
33
34
35
36
37
38
39
private:
Ui::adresy *ui;
QPushButton *dodajBtn;
QPushButton *zapiszBtn;
QPushButton *anulujBtn;
QPushButton *poprzBtn;
QPushButton *nastBtn;
QPushButton *edytujBtn;
QPushButton *usunBtn;
QPushButton *koniecBtn;
QLineEdit *nazwaLine;
QTextEdit *adresText;
40
Tryb aktTryb;
void aktGui(Tryb tryb);
QString staraNazwa;
QString staryAdres;
QMap<QString,QString> kontakty;
41
42
43
44
45
46
47
};
48
49
#endif // ADRESY_H
Oprócz deklaracji slotów w liniach 24-26 dopisujemy deklaracje kilku potrzebnych zmiennych. Definiujemy wi˛ec
typ wyliczeniowy Tryb, z którego korzystamy deklarujac
˛ zmienna˛ aktTryb oraz prywatna˛ funkcj˛e pomocnicza˛
aktGui. Posłuża˛ one do określania 1 z 3 stanów działania aplikacji, takich jak: przegladanie
˛
wpisów, dodawanie i
ich edycja.
Dalej dopisujemy deklaracje zmiennych pomocniczych staraNazwa i staryAdres. Korzystamy tu z typu
QString oznaczajacego
˛
dane tekstowe. Na końcu deklarujemy specjalna˛ zmienna˛ kontakty, która posłuży do
przechowywania nazw i skojarzonych z nimi adresów w postaci słownika typu QMap. Poszczególne elementy takiej
listy maja˛ postać skojarzonych ze soba˛ par (klucz, wartość).
connect(dodajBtn, SIGNAL(clicked()), this, SLOT(dodajKontakt()));
connect(koniecBtn,SIGNAL(clicked()),this, SLOT(koniec()));
53
54
55
}
56
57
58
59
60
adresy::~adresy()
{
delete ui;
}
61
62
63
64
void adresy::dodajKontakt() {
staraNazwa = nazwaLine->text();
staryAdres = adresText->toPlainText();
65
nazwaLine->clear();
adresText->clear();
66
67
86
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
68
aktGui(dodajT);
69
70
}
71
72
73
74
75
76
77
78
79
void adresy::aktGui(Tryb tryb) {
aktTryb=tryb;
switch (aktTryb) {
case dodajT:
case edytujT:
nazwaLine->setReadOnly(false);
nazwaLine->setFocus(Qt::OtherFocusReason);
adresText->setReadOnly(false);
80
dodajBtn->setEnabled(false);
edytujBtn->setEnabled(false);
usunBtn->setEnabled(false);
81
82
83
84
zapiszBtn->show();
anulujBtn->show();
85
86
87
nastBtn->setEnabled(false);
poprzBtn->setEnabled(false);
break;
case nawigujT:
if (kontakty.isEmpty()) {
nazwaLine->clear();
adresText->clear();
}
nazwaLine->setReadOnly(true);
adresText->setReadOnly(true);
dodajBtn->setEnabled(true);
88
89
90
91
92
93
94
95
96
97
98
99
int ile=kontakty.size();
edytujBtn->setEnabled(ile >= 1);
usunBtn->setEnabled(ile >=1 );
nastBtn->setEnabled(ile > 1);
poprzBtn->setEnabled(ile > 1);
100
101
102
103
104
105
zapiszBtn->hide();
anulujBtn->hide();
break;
106
107
108
}
109
110
}
111
112
113
114
void adresy::koniec() {
adresy::close();
}
Powiazania
˛
mi˛edzy sygnałami i slotami ustalamy w pliku adresy.cpp za pomoca˛ poleceń typu:
connect(dodajBtn, SIGNAL(clicked()), this, SLOT(dodajKontakt()));.
Funkcja
conect() jako pierwszy argument wymaga zmiennej wskazujacej
˛ obiekt, który emituje sygnał określony w 2.
argumencie (np. SIGNAL(clicked()), czyli klikni˛ecie), 3. argument określa obiekt, który zostaje powiadomiony
o zdarzeniu, w ostatnim argumencie podajemy funkcj˛e, która ma zostać wykonana (SLOT(dodajKontakt())).
Jak widać powyżej, na końcu konstruktora naszej klasy adresy wia˛żemy klikni˛ecia przycisków dodajBtn i
koniecBtn z funkcjami dodajKontakt() i koniec().
Funkcja dodajKontakt() przygotowuje aplikacj˛e do przełaczenia
˛
w stan dodawania nowych danych. W tym celu
najpierw zapami˛etujemy dotychczasowa˛ nazw˛e i adres, a nast˛epnie wywołujemy funkcj˛e pomocnicza˛ z argumentem
3.1. Adresy (Qt5)
87
Materiały eCG IT Documentation, Wydanie 1
typu Tryb oznaczajacym
˛
wymagany stan aplikacji: aktGui(dodajT).
Działanie funkcji aktGui(), obsługujacej
˛ stany aplikacji, polega na uaktywnianiu lub wyłaczaniu
˛
określonych elementów interfejsu w zależności od przeprowadzanej przez użytkownika czynności. Np. w trybie dodawania i edycji odblokowujemy możliwość wprowadzania tekstu w polach nazwy (nazwaLine->setReadOnly(false);)
i adresu (adresText->setReadOnly(false);), pokazujemy przyciski pozwlajace
˛ na zapis lub anulowanie wywołujac
˛ metod˛e show(). Wyłaczamy
˛
również nawigacj˛e, blokujac
˛ odpowiednie przyciski (metoda
setEnabled(false)). Po wejściu w tryb nawigacji czyścimy (clear()) zawartość pól nazwy i adresu, o
ile lista kontaktów jest pusta (if (kontakty.isEmpty())). Nast˛epnie uaktywniamy przyciski edycji, usuwania i przegladania,
˛
jeżeli mamy jakieś kontakty. Ilość kontaktów zapisujemy wcześniej w osobnej zmiennej (int
ile=kontakty.size();). Na koniec przyciski zapisu i anulowania zostaja˛ zablokowane.
Slot koniec() wywoływany jest po klikni˛eciu przycisku Koniec i powoduje zamkni˛ecie aplikacji przy użyciu metody close(). Wywołuje ona m.in. destruktor klasy, co powoduje – w naszym przypadku – usuni˛ecie instancji
obiektu interfejsu graficznego (delete ui;).
3.1.5 Dodawanie adresów
Pora zaimplementować obsług˛e trybu dodawania danych adresowych. Najpierw do pliku nagłówkowego dopisujemy
deklaracje odpowiednich slotów:
25
26
27
28
29
public slots:
void dodajKontakt();
void koniec();
void zapiszKontakt();
void anuluj();
Musimy też na poczatku
˛ pliku dodać import klasy QMessageBox pozwalajacej
˛ wyświetlać informacje użytkownikowi.
Nast˛epnie przechodzimy do pliku adresy.cpp, w którym trzeba powiazać
˛
sloty zapiszKontakt() i
anuluj() ze zdarzeniem klikni˛ecia przycisków zapiszBtn i anulujBtn. Zadanie to proponujemy wykonać
samodzielnie :-).
Na końcu pliku musimy dopisać definicje powiazanych
˛
funkcji:
118
119
120
void adresy::zapiszKontakt() {
QString nazwa = nazwaLine->text();
QString adres = adresText->toPlainText();
121
if (nazwa == "" || adres == "") {
QMessageBox::information(this, trUtf8("Puste pole"),trUtf8("Prosz˛
e wpisać nazw˛
e i adres."));
return;
}
122
123
124
125
126
if (aktTryb == dodajT) {
if (!kontakty.contains(nazwa)) {
kontakty.insert(nazwa, adres);
QMessageBox::information(this, trUtf8("Dodano wpis"),
trUtf8("Kontakt \"%1\" dodano do ksia˛żki adresowej.").arg(nazwa)
} else {
QMessageBox::information(this, trUtf8("Nie dodano wpisu"),
trUtf8("Przykro, ale kontakt \"%1\" jest już w ksia˛żce adresowej
}
}
127
128
129
130
131
132
133
134
135
136
137
aktGui(nawigujT);
138
139
}
88
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
140
141
142
143
144
145
void adresy::anuluj() {
nazwaLine->setText(staraNazwa);
adresText->setText(staryAdres);
aktGui(nawigujT);
}
Funkcja zapiszKontakt() pobiera tekst wpisany w pola edycyjne za pomoca˛ metod text() oraz
toPlainText() i zapisuje je w zmiennych tekstowych. Nast˛epnie sprawdza, czy użytkownik wprowadził obydwie
informacje. Jeżeli nie, wyświetla odpowiedni komunikat przy użyciu metody QMessageBox::information().
Pierwszy tekst, który przekazujemy do tej funkcji to tytuł okna dialogowego, drugi – właściwy komunikat. Nast˛epnie, jeżeli aplikacja jest w trybie dodawania, sprawdza, czy podana nazwa nie została zapisana wcześniej na liście kontakty. Jeśli nie (if (!kontakty.contains(nazwa))), dodaje nowe dane
(kontakty.insert(nazwa, adres);) i wyświetla potwierdzenie. W przeciwnym razie informuje użytkownika o duplikacie. Na końcu aktywuje tryb nawigacji (aktGui(nawigujT);).
Jeżeli użytkownik rozmyśli si˛e i kliknie odpowiedni przycisk, wywoływana jest funkcja anuluj(). Jak widać,
przywraca ona w polach edycyjnych poprzednio wprowadzane dane i również aktywuje tryb nawigacji.
3.1.6 Tryb nawigacji
Obsługa nawigacji wymaga napisania funkcji obsługujacych
˛
naciśni˛ecie przycisków Nast˛epny i Poprzedni, które staja˛
si˛e aktywne, jeżeli mamy wi˛ecej niż 1 dodany adres. Jak zwykle, zaczynamy od zadeklarowania publicznych slotów
nast() i poprz() w pliku nagłówkowym. Dopisanie tych 2 linijek pozostawiamy do samodzielnego wykonania. Podobnie powiazanie
˛
zadeklarowanych slotów z sygnałami (klikni˛eciami) obiektów nastBtn i poprzBtn w
konstruktorze klasy adresy.
Nast˛epnie dopisujemy implementacj˛e zadeklarowanych funkcji na końcu pliku adresy.cpp:
Na końcu pliku musimy dopisać definicje powiazanych
˛
funkcji:
149
150
151
152
153
154
155
156
void adresy::nast() {
QString nazwa = nazwaLine->text();
QMap<QString, QString>::iterator i = kontakty.find(nazwa);
if (i != kontakty.end()) i++;
if (i == kontakty.end()) i = kontakty.begin();
nazwaLine->setText(i.key());
adresText->setText(i.value());
}
157
158
159
160
161
162
163
164
165
void adresy::poprz() {
QString nazwa = nazwaLine->text();
QMap<QString, QString>::iterator i = kontakty.find(nazwa);
if (i == kontakty.begin()) i = kontakty.end();
i--;
nazwaLine->setText(i.key());
adresText->setText(i.value());
}
Wyświetlajac
˛ kolejna˛ par˛e powiazanych
˛
danych, tzn. nazw˛e i przypisany jej adres(y), musimy sprawdzić w fukcji nast(), czy mamy kolejny wpis, czy też aktualny jest ostatni. Wtedy należałoby wyświetlić wpis pierwszy. W tym celu pobieramy nazw˛e aktualnie wyświetlonego wpisu i tworzymy obiekt tzw. iteratora inicjowanego przez metod˛e find() i przypisanego do zmiennej i: QMap<QString, QString>::iterator i =
kontakty.find(nazwa);. Iterator umożliwia łatwe poruszanie si˛e po liście słowników zapisanych w zmiennej
kontakty. Metoda i.key() zwraca nam klucz, a i.value() przypisana˛ mu wartość.
Jeżeli bieżacy
˛ wpis nie jest ostatnim inkrementujemy wartość iteratora (if (i != kontakty.end()) i++;).
3.1. Adresy (Qt5)
89
Materiały eCG IT Documentation, Wydanie 1
W przeciwnym wypadku ustawiamy go na pierwszy wpis (i = kontakty.begin();); Na koniec pozostaje
wczytanie nazwy (i.key()) i przypisanych jej danych (i.value()) do odpowiednich pól interfejsu.
Funkcja poprz() zaczyna si˛e tak samo jak poprzednia, czyli od utworzenia iteratora wskazujacego
˛
na bieżacy
˛ wpis.
Jeżeli jesteśmy na poczatku
˛
listy, ustawiamy iterator na element końcowy. Nast˛epnie przechodzimy do elementu
końcowego (i--) i wyświetlamy odpowiednie dane.
Informacja: Metoda .end() klasy QMap zwraca iterator wskazujacy
˛ na wirtualny (!) element po ostatnim elemencie listy. Dlatego, aby uzyskać dost˛ep do niego, musimy iterator dekrementować (i--).
3.1.7 Edycja i usuwanie
Do oprogramowania zostay jeszcze dwa przyciski: btnEdytuj, którego klikni˛ecie powinno wywołać funkcj˛e
edytujKontakt(), oraz btnUsun, który wywołuje funkcj˛e usunKontakt(). Samodzielnie dopisujemy deklaracje funkcji do pliku nagłówkowego, a ich powiazania
˛
z sygnałami umieszczamy w pliku źródłowym.
Nast˛epnie implementujemy funkcje:
185
186
187
188
189
void adresy::edytujKontakt() {
staraNazwa = nazwaLine->text();
staryAdres = adresText->toPlainText();
aktGui(edytujT);
}
190
191
192
193
void adresy::usunKontakt() {
QString nazwa = nazwaLine->text();
QString adres = adresText->toPlainText();
194
if (kontakty.contains(nazwa)) {
int button = QMessageBox::question(this,trUtf8("Potwierdź usuni˛
ecie"),
trUtf8("Czy na pewno usunać
˛ kontakt \"%1\"?").arg(nazwa),
QMessageBox::Yes|QMessageBox::No);
if (button == QMessageBox::Yes) {
poprz();
kontakty.remove(nazwa);
QMessageBox::information(this,trUtf8("Usuni˛
eto"),
trUtf8("Usuni˛
eto kontakt \"%1\".").arg(nazwa));
}
}
aktGui(nawigujT);
195
196
197
198
199
200
201
202
203
204
205
206
207
}
Przejście do trybu edycji, czyli działanie funkcji edytujKontak(), polega na zapisaniu aktualnie wyświetlanych
danych (przydatne, jeżeli użytkownik anuluje zmiany) i uaktywnieniu trybu (aktGui(edytujT);), tzn. odblokowaniu pól tekstowych i odpowiednich przycisków.
Usuwanie kontaktów również jest proste. Na poczatku
˛
pobieramy nazw˛e i zwiazany
˛
z nim adres(y). Metoda
.contains(nazwa) pozwala sprawdzić, czy lista kontaktów zawiera słownik o podanym kluczu. Nat˛epnie prosimy użytkownika o potwierdzenie operacji. Po jego uzyskaniu najpierw wyświetlamy w aplikacji dane poprzedniego
wpisu dzi˛eki wywołaniu zdefiniowanej wcześniej funkcji poprz(), później dopiero usuwamy wpis za pomoca˛ metody .remove(nazwa) i wyświetlamy potwierdzenie. Na koniec aktywujemy tryb nawigacji.
Poćwicz sam
Spróbuj rozszerzyć napisana˛ aplikacj˛e o możliwość przechowywania danych w pliku lub w bazie na
dysku.
90
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
3.1.8 Materiały
1. Projekt Qt
2. Biblioteka Qt 5
3. Qt Creator
4. Dokumentacja Qt 5
5. Qt Developer Wiki (pl)
Pojecia
˛
Qt zestaw bibliotek programistycznych ułatwiajacych
˛
tworzenie aplikacji z interfejsem graficznym w j˛ezykach C++,
QML i Java.
plik nagłówkowy w j˛ezyku C/C++ plik z rozszerzeniem .h zawierajacy
˛ deklaracje używanych struktur danych, np.
klas, zmiennych i funkcji. Implementacja klas i funkcji umieszczana jest w plikach źródłowych. Wi˛ecej o pliku
żródłowym:
plik źródłowy w j˛ezyku C/C++ plik z rozszerzeniem .c/.cpp zawierajacy
˛ implementacj˛e zadeklarowanych typów
złożonych (np. klas) i używanych funkcji, w tym funkcji głównej (main()).
Klasa program komputerowy.
Obiekt zestaw komponentów i bibliotek wykorzystywany do budowy aplikacji, przykładem jest biblioteka Pythona
Flask.
public operator widoczności, pola (właściwości) i metody (funkcje) klasy deklarowne po nim sa˛ dost˛epne z każdeg
miejsca programu.
private operator widoczności, pola (właściwości) i metody (funkcje) klasy deklarowne po nim sa˛ dost˛epne tylko w
jej obr˛ebie.
Qt Creator wieloplatformowe środowisko IDE (zintegrowane środowisko programistyczne) dla aplikacji pisanych
w j˛ezykach C++, JavaScript i QML. Zawiera m.in. debugger i edytor GUI (graficznego interfejsu użytkownika).
sygnały zdarzenia generowane za pomoca˛ graficznego interfejsu użytkownika, takie jak klikni˛ecie elementu, edycja,
przeciagni˛
˛ ecie itp.
sloty funkcje przypisane sygnałom, definiuja˛ działania podejmowane w przypadku zastnienia danego zdarzenia.
Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
3.2 Zadania (Qt5)
Po zrealizowaniu scenariusza “Adresy” powinieneś być w stanie tworzyć przy użyciu biblioteki Qt proste prohgramy
z interfejsem graficznym. Poniżej zamieszczamy kilka propozycji do samodzielnego opracowania.
3.2. Zadania (Qt5)
91
Materiały eCG IT Documentation, Wydanie 1
•
•
•
•
•
•
•
Kalkulator
Konwerter liczb
Konwerter jednostek
Równanie kwadratowe
Szyfr
Twój pomysł
Materiały
3.2.1 Kalkulator
Stwórz kalkulator pozwalajacy
˛ na wykonywania co najmniej podstawowych działań. Rozwijajac
˛ go, możesz pomyśleć
o zaimplementowaniu historii obliczeń.
3.2.2 Konwerter liczb
Napisz program pozwalajacy
˛ na konwersj˛e liczb wprowadzanych w systemach liczbowych o podstawie 2, 6, 8, 10 i
16.
3.2.3 Konwerter jednostek
Napisz program pozwalajacy
˛ na konwersj˛e jednostek używanych w informatyce, np. bity na kilobajty, megabity na
kilobajty itp.
3.2.4 Równanie kwadratowe
Napisz program, który po wprowadzeniu wymaganych danych wyświetla i rozwiazuje
˛
równanie kwadratowe.
3.2.5 Szyfr
Napisz program, który szyfruje i deszyfruje wprowadzony tekst wybrana˛ metoda,˛ np. szyfrem Cezara lub Vigenère’a.
3.2.6 Twój pomysł
Wymyśl i zaimplementuj program własnego pomysłu.
3.2.7 Materiały
1. Projekt Qt
2. Biblioteka Qt 5
3. Qt Creator
4. Dokumentacja Qt 5
5. Qt Developer Wiki (pl)
92
Rozdział 3. Biblioteka Qt
Materiały eCG IT Documentation, Wydanie 1
Pojecia
˛
Qt zestaw bibliotek programistycznych ułatwiajacych
˛
tworzenie aplikacji z interfejsem graficznym w j˛ezykach C++,
QML i Java.
plik nagłówkowy w j˛ezyku C/C++ plik z rozszerzeniem .h zawierajacy
˛ deklaracje używanych struktur danych, np.
klas, zmiennych i funkcji. Implementacja klas i funkcji umieszczana jest w plikach źródłowych. Wi˛ecej o pliku
żródłowym:
plik źródłowy w j˛ezyku C/C++ plik z rozszerzeniem .c/.cpp zawierajacy
˛ implementacj˛e zadeklarowanych typów
złożonych (np. klas) i używanych funkcji, w tym funkcji głównej (main()).
Klasa program komputerowy.
Obiekt zestaw komponentów i bibliotek wykorzystywany do budowy aplikacji, przykładem jest biblioteka Pythona
Flask.
public operator widoczności, pola (właściwości) i metody (funkcje) klasy deklarowne po nim sa˛ dost˛epne z każdeg
miejsca programu.
private operator widoczności, pola (właściwości) i metody (funkcje) klasy deklarowne po nim sa˛ dost˛epne tylko w
jej obr˛ebie.
Qt Creator wieloplatformowe środowisko IDE (zintegrowane środowisko programistyczne) dla aplikacji pisanych
w j˛ezykach C++, JavaScript i QML. Zawiera m.in. debugger i edytor GUI (graficznego interfejsu użytkownika).
sygnały zdarzenia generowane za pomoca˛ graficznego interfejsu użytkownika, takie jak klikni˛ecie elementu, edycja,
przeciagni˛
˛ ecie itp.
sloty funkcje przypisane sygnałom, definiuja˛ działania podejmowane w przypadku zastnienia danego zdarzenia.
Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
3.3 Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
3.3. Metryka
93
Materiały eCG IT Documentation, Wydanie 1
94
Rozdział 3. Biblioteka Qt
ROZDZIAŁ 4
Technologie WWW
WWW (ang. World Wide Web – ogólnoświatowa sieć) w celu dostarczania użytkownikom hipertekstowych dokumentów wykorzytuje wiele technologii, do których należa˛ m. in.: protokół HTTP(S), j˛ezyki opisu stron HTML, XML,
j˛ezyki generujace
˛ strony PHP, Python, arkusze stylów CSS, j˛ezyk skryptowy JavaScript czy technika AJAX.
4.1 GetSimple CMS
GetSimple jest przykładem popularnych od dłuższego czasu systemu zarzadzania
˛
treścia˛ (ang. Content Management
System, CMS). Zadaniem CMS-ów jest wspomaganie tworzenia serisów intenetowych WWW i wspomaganie zarza˛
dzania nimi przy wykorzystaniu przyjaznych dla użytkownika interfejsów, dzi˛eki czemu nie musi on być specjalista˛
od wspomnianych na wst˛epie technologii WWW. Inne przykłady popularnych CMS-ów to: Drupal, Joomla! czy
WordPress.
4.1.1 Pobranie archwium
Informacja: GetSimple wymaga działajacego
˛
serwera WWW, przy czym serwery bazodanowe typu MySQL itp. nie
sa˛ koniecznie, ponieważ GS przechowuje pliki w formacie XML. W rozdziale narz˛edzia omówiono instalacj˛e instalacj˛e
środowiska LAMP (dla Linuksa) i WAMP (Serwer2Go dla Windowsa).
Najnowsza˛ wersj˛e GS pobieramy ze strony Download GetSimple CMS. Ściagni˛
˛ ete archiwum zip umieszczamy w
podkatalogu public_html katalogu domowego użytkownika Linuksa lub w podkatalogu htdocs folderu instalacyjnego Serwer2Go. Rozpakowujemy je, a nast˛epnie nazw˛e utworzonego katalogu zmieniamy na gs.
Informacja: W środowisku Linux folderowi gs musimy nadać uprawnienia do zapisu i odczytu nie tylko dla właściciela, ale i dla grupy oraz innych. Można to zrobić z poziomu menedżera plików po klikni˛eciu prawym klawiszem
myszy nazwy katalogu i wybraniu “Właściwości/Uprawnienia” (zob. zrzut poniżej). Uwaga: na pytanie typu “Zastosować rekursywnie” odpowiadamy twierdzaco.
˛ Można też w katalogu public_html wydać polecenie w terminalu
chmod -R 777 gs.
Nast˛epnie przechodzimy do przegladarki
˛
(w Windows Serwer2Go musi być uruchomiony!) i rozpoczynamy
instalacj˛e wpisujac
˛ w polu adresu: http://127.0.0.1/~nazwa_użytkownika/gs/admin (Linux) lub
http://127.0.0.1:4001/gs/admin (Windows).
Informacja: W środowisku Linux ewentualne bł˛edy chmod ignorujemy.
95
Materiały eCG IT Documentation, Wydanie 1
96
Rozdział 4. Technologie WWW
Materiały eCG IT Documentation, Wydanie 1
4.1. GetSimple CMS
97
Materiały eCG IT Documentation, Wydanie 1
98
Rozdział 4. Technologie WWW
Materiały eCG IT Documentation, Wydanie 1
Spolszczenie
Jak widać, domyślnie dost˛epny jest j˛ezyk angielski. Można to łatwo zmienić już podczas instalacji (później również). W nowej karcie przegladarki
˛
otwieramy link Download Languages, a na otwartej stronie wchodzimy do
sekcji Extend. W polu wyszukiwania wpisujemy polish, po wyświetleniu znalezionych zasobów klikamy link
Polish language (spolszczenie) 1.3.7. Ściagamy
˛
spakowane archiwum na dysk. Przenosimy je do
folderu gs/admin/lang i tam rozpakowujemy.
4.1.2 Instalacja
Wracamy do prz˛egladarki,
˛
odświeżamy stron˛e instalacyjna,˛ np. klawiszem F5, i wybieramy polska˛ wersj˛e j˛ezykowa.˛
Po klikni˛eciu przycisku “Kontynuuj instalacj˛e” na nast˛epnej stronie wpisujemy nazw˛e strony, login i hasło administratora.
Po naciśni˛eciu “Instaluj!” może zostać wyświetlona strona z bł˛edem (pod Windowsem) ze wzgl˛edu na brak możliwości wysłania wiadomości e-mail z danymi logowania. Jest to normalne. Wyświetlone hasło możemy ewentualnie
zapisać, po czym kilkamy link “Logowanie”. Zobaczymy panel administracyjny, w którym b˛edziemy mogli zmienić
hasło klikajac
˛ po prawej stronie “Ustawienia”, a nast˛epnie “Profil użytkownika”.
Domyślnie dodana zostanie demonstracyjna strona główna widoczna w panelu “Strony”, która˛ wyświetlimy w przegladarce,
˛
jeżeli klikniemy nazw˛e serwisu w panelu administracyjnym lub wpiszemy
4.1. GetSimple CMS
99
Materiały eCG IT Documentation, Wydanie 1
http://127.0.0.1/~nazwa_użytkownika/gs/ (Linux) lub http://127.0.0.1:4001/gs/ (Windows) w polu adresu.
Zobacz galeri˛e Instalacja GetSimple CMS.
4.1.3 Wtyczki
Jak wi˛ekszość CMS-ów, GetSimple oferuje mechanizm wtyczek, pozwalajacy
˛ rozszerzać w miar˛e potrzeb funkcjonalność zarówno od strony użytkownika, jak i administratora serwisu. Instalacja wtyczek polega na pobraniu ich ze
strony Extend Repository <http://get-simple.info/extend/>, a nast˛epnie rozpakowaniu archiwum zip w podfolderze
gs/plugins. Wtyczkami zarzadzamy
˛
w sekcji “Wtyczki” panelu administracyjnego. Tam można je m. in. właczać
˛
lub wyłaczać.
˛
Przykładowe wtyczki
• I18N – dodaje wsparcie dla stron w różnych j˛ezykach oraz bardzo użyteczne hierarchiczne menu;
• I18N Gallery – dodaje możliwość wygodnego tworzenia galerii zdj˛eć i umieszczania ich na stronach;
• I18N Search – umożliwia m. in. wyszukiwanie tekstu na stronach serwisu, ale również tworzenie list zasobów
oznaczonych tymi samymi tagami.
• I18N Special Pages – pozwala tworzyć strony specjalne typu newsy, artykuły, karty produktów itp.
Informacja: W Linuksie po umieszczeniu archiwów zip w podkatalogu gs/plugins wygodnie je rozpakujesz
wydajac
˛ w terminalu polecenie typu: unzip nazwa_archiwum.zip.
Uwaga: użycie polecenia “Rozpakuj tutaj” w menedżerze plików umieści pliki w dodatkowym i niepotrzebnym podfolderze (o nazwie wtyczki), z którego trzeba je b˛edzie przenieść do folderu nadrz˛ednego (plugins).
100
Rozdział 4. Technologie WWW
Materiały eCG IT Documentation, Wydanie 1
4.1. GetSimple CMS
101
Materiały eCG IT Documentation, Wydanie 1
102
Rozdział 4. Technologie WWW
Materiały eCG IT Documentation, Wydanie 1
Zawartość przykładowego folderu plugins powinna wygladać
˛
nast˛epujaco:
˛
4.2 Materiały
1. GetSimple
2. GetSimple – dodatki
4.2.1 Słownik
WWW (ang. World Wide Web) – ogólnoświatowa sieć, jedna z najważniejszych usług sieciowych; hipertekstowy,
internetowy sposób udost˛epniania informacji.
HTTP(S) (ang. Hypertext Transfer Protocol) – protokół przesyłania dokumentów hipertekstowych, protokół sieci
WWW za pomoca˛ którego przesyłane sa˛ żadania
˛
udost˛epnienia lub modyfikacji zasobów, określa reguły komunikacji mi˛edzy klientem (np. przegladark
˛
a)
˛ a serwerem, który zwraca odpowiedzi. Zalecane jest używanie
wersji szyfrowanej tego protokołu oznaczanego https.
HTML HTML (ang. HyperText Markup Language) – hipertekstowy j˛ezyk znaczników, wykorzystywany do tworzenia stron internetowych. Aktualnie zalecana wersja to HTML5.
4.2. Materiały
103
Materiały eCG IT Documentation, Wydanie 1
XML XML (ang. Extensible Markup Language) – rozszerzalny j˛ezyk znaczników, przeznaczony do strukturalnego
i semantycznego opisu danych.
PHP obiektowy, skryptowy j˛ezyk programowania, służacy
˛ m. in. do generowania po stronie serwera dynamicznych
stron internetowych.
Python obiektowy j˛ezyk programowania wysokiego poziomu służacy
˛ m. in. do tworzenia aplikacji internetowych,
oferuje przyjazna˛ składni˛e, czytelność i klarowność kodu.
CSS (ang. Cascading Style Sheets, CSS) – kaskadowe arkusze stylów, j˛ezyk opisu wygladu
˛ stron internetowych,
stanowi dopełnienie HTML-a.
JavaScript skryptowy j˛ezyk programowania służacy
˛ m. in. do tworzenia aktywnych właściwości stron internetowych, działa po stronie klienta (tj. w przegladarce).
˛
AJAX AJAX (ang. Asynchronous JavaScript and XML) – asynchroniczny JavaScript i XML, sposób tworzenia
stron internetowych, które oferujac
˛ dynamiczna˛ zmian˛e zawartości, nie wymagaja˛ przeładowywania, ponieważ
komunikuja˛ si˛e z serwerm asynchronicznie.
CMS (ang. Content Management System, CMS) – system zarzadzania
˛
treścia,˛ wykorzystujace
˛ różne technologie
internetowe, służacy
˛ do tworzenia serwisów internetowych i zarzadzania
˛
nimi.
serwer WWW (ang. web server) – oprogramowanie obsługujace
˛ protokół http, podstawowy protokół sieci WWW,
służacy
˛ przesyłaniu dokumentów hipertekstowych.
interpreter program, który analizuje kod źródłowy, a nast˛epnie go wykonuje. Interpretery sa˛ podstawowym składnikiem j˛ezyków wykorzystywanych do pisania skryptów wykonywanych po stronie klienta WWW (JavaScript)
lub serwera (np. Python, PHP).
system bazodanowy system zarzadzania
˛
baza˛ danych (ang. Database Management System, DBMS) – oprogramowanie służace
˛ do zarzadzania
˛
bazami danych, np. SQLite, MariaDB, MySQL, PostgreSQL.
framework (ang. framework – struktura) – oprogramowanie b˛edace
˛ zestawem narz˛edzi ułatwiajacych
˛
i przyśpieszajacych
˛
tworzenie aplikacji.
4.2.2 Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
104
Rozdział 4. Technologie WWW
ROZDZIAŁ 5
Python
Poniżej przedstawiamy materiał “Toto Lotek” wprowadzajacy
˛ do programowania w j˛ezyku Python, “Python kreśli” to
krótkie wprowadzenie do biblioteki matplotlib, w “Czacie” – realizujemy aplikacj˛e internetowa˛ w wersji rozszerzonej
przy użyciu frameworka Django.
5.1 Toto Lotek – Python od podstaw
W Toto Lotku trzeba zgadywać liczby. Napiszmy prosty program, w którym b˛edziemy mieli podobne zadanie. Użyjemy j˛ezyka Python.
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Mały Lotek
Losowanie liczby
Zgadywanie
Sprawdzanie
Do 3 razy sztuka
Duży Lotek
Losowanie wielu liczb
Nasze typy
Ile trafiliśmy
Uwaga: bł˛edne dane!
Funkcje i moduły
Ustawienia
Historia losowań
Wydruk historii
5.1.1 Mały Lotek
Zaczynamy od utworzenia pliku o nazwie toto.py w dowolnym katalogu za pomoca˛ dowolnego edytora, np. Geany.
Zapis ~$ poniżej oznacza katalog domowy użytkownika. Obowiazkowa
˛
zawartość pliku:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
Pierwsza linia to ścieżka do interpretera Pythona (zob. interpreter), druga linia deklaruje sposób kodowania znaków,
dzi˛eki czemu możemy używać polskich znaków.
105
Materiały eCG IT Documentation, Wydanie 1
5.1.2 Losowanie liczby
Musimy wylosować liczby, ale zaczniemy od jednej. Potrzebujemy funkcji randint(a, b) z modułu random.
Zwróci nam ona liczb˛e całkowita˛ z zakresu <a; b>. Do naszego pliku dopisujemy:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5
6
7
liczba = random.randint(1, 10)
print "Wylosowana liczba:",liczba
Wylosowana liczba zostanie zapami˛etana w zmiennej liczba (zob. zmienna ). Instrukcja print wydrukuje ja˛
razem z komunikatem na ekranie. Program możemy już uruchomić w terminalu (zob. terminal), wydajac
˛ w katalogu
z plikiem polecenie:
~$ python toto.py
Efekt działania naszego skryptu:
5.1.3 Zgadywanie
Liczb˛e mamy, niech gracz, czyli użytkownik ja˛ zgadnie. Pytanie tylko, na ile prób mu pozwolimy. Zacznijmy od
jednej! Dopisujemy zatem:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5
6
7
liczba = random.randint(1, 10)
#print "Wylosowana liczba:",liczba
8
9
odp = raw_input("Jaka˛ liczb˛
e od 1 do 10 mam na myśli? ")
Na poczatku
˛
zakomentowujemy znakiem # instrukcj˛e drukujac
˛ a˛ wylosowana˛ liczb˛e. Nie b˛edzie wykonywana :) Liczb˛e podana˛ przez użytkownika pobieramy za pomoca˛ instrukcji raw_input() i zapami˛etujemy w zmiennej
odp.
Uwaga: Zakładamy na razie, że gracz wprowadza poprawne dane, czyli liczby całkowite!
Ćwiczenie 1
Dopisz odpowiednie polecenie, które wyświetli liczb˛e podana˛ przez gracza. Przetestuj jego działanie.
106
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.1.4 Sprawdzanie
Mamy wylosowana˛ liczb˛e i typ gracza, musimy sprawdzić, czy trafił. Uzupełniamy nasz program:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5
6
7
liczba = random.randint(1, 10)
#print "Wylosowana liczba:",liczba
8
9
10
odp = raw_input("Jaka˛ liczb˛
e od 1 do 10 mam na myśli? ")
#print "Podałeś liczb˛
e: ",odp
11
12
13
14
15
if liczba == int(odp):
print "Zgadłeś! Dostajesz długopis!"
else:
print "Nie zgadłeś. Spróbuj jeszcze raz."
Używamy instrukcji warunkowej if, która sprawdza prawdziwość warunku liczba == int(odp) (zob. instrukcja warunkowa). Jeżeli wylosowana i podana liczba sa˛ sobie równe (==), wyświetlamy informacj˛e o wygranej,
w przeciwnym razie (else:) zach˛et˛e do ponownej próby. Dodatkowa funkcja int() zamienia podana˛ przez gracza
wartość na liczb˛e całkowita.˛
Informacja: Instrukcja raw_input() wszystkie pobrane dane zwraca jako tekst, dlatego jeżeli wprowadzone wartości chcemy wykorzystywać jako liczby, musimy używać funkcji int(), która próbuje podany tekst przekształcić
na typ całkowity (integer). Jeżeli nie jest w stanie tego zrobić, zgłasza wyjatek
˛ ValueError. Ich obsług˛e omówimy
później.
Przetestuj kilkukrotnie działanie programu.
5.1.5 Do 3 razy sztuka
Trafienie za pierwszym razem wylosowanej liczby jest bardzo trudne, spróbujmy dać graczowi 3 szanse. Zmieniamy
i uzupełniamy kod:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
5.1. Toto Lotek – Python od podstaw
107
Materiały eCG IT Documentation, Wydanie 1
4
import random
5
6
7
liczba = random.randint(1, 10)
#print "Wylosowana liczba:",liczba
8
9
10
11
for i in range(3):
odp = raw_input("Jaka˛ liczb˛
e od 1 do 10 mam na myśli? ")
#print "Podałeś liczb˛
e: ",odp
12
if liczba == int(odp):
print "Zgadłeś! Dostajesz długopis!"
break
else:
print "Nie zgadłeś. Spróbuj jeszcze raz."
print
13
14
15
16
17
18
Pobieranie i sprawdzanie kolejnych liczb wymaga powórzenia zakodowanych wcześniej operacji. Do tego celu używamy p˛etli for (zob. p˛etla). Umieszczamy w niej blok poprzednio napisanego kodu odpowiednio wci˛ety (zob.
formatowanie kodu).
Ilość powtórzeń określa wyrażenie i in range(3). Zmienna iteracyjna i to “licznik” powtórzeń. B˛edzie si˛e on
zmieniał tyle razy, ile wartości zwróci funkcja range(n). Funkcja ta generuje list˛e liczb całkowitych od 0 do n-1.
Ćwiczenie 2
Zamiast si˛e domyślać, sprawdźmy działanie omawianej funkcji w trybie interaktywnym interpretera Pythona. W
terminalu wpisz polecenia:
~$ python
>>> range(3)
>>> for i in range(3)
...
print i
...
>>> exit()
Jak wynika z powyższego, zmienna i przyjmie wartość 0, 1 i 2, czyli p˛etla for wykona si˛e 3 razy. Wszystkie
polecenia znajdujace
˛ si˛e wewnatrz
˛ p˛etli również 3 razy, chyba że... Właśnie, a jeżeli użytkownik trafi za 1 lub 2
razem? Wtedy warunek w instrukcji if stanie si˛e prawdziwy, wyświetli si˛e informacja o nagrodzie, a polecenie
break przerwie działanie p˛etli. Przetestuj działanie programu, ale wcześniej przeczytaj jeszcze poniższa˛ uwag˛e:
Informacja: W kodzie Pythona bardzo ważna˛ rol˛e pełnia˛ wci˛ecia. W obr˛ebie całego pliku musza˛ one być równe
(najcz˛eściej 4 spacje i ich wielokrotności), służa˛ bowiem wydzielaniu bloków kodu. Wskazuja˛ wi˛ec, które polecenia,
którym sa˛ podporzadkowane.
˛
W naszym przypadku linie 10, 13 i 16 musza˛ mieć wci˛ecia pojedyncze (np. 4 spacje), a
linie 14-15, 17-18 podwójne (np. 8 spacji). Inaczej pojawia˛ si˛e bł˛edy IndentationError.
Ćwiczenie 3
Uzupełnij kod, tak aby program wyświetlał informacj˛e “Próba 1”, “Próba 2” itd. przed podaniem liczby. Wskazówki:
Wykorzystaj zmienna˛ i i sprawdź również w trybie interaktywnym, co si˛e dzieje, kiedy wpiszesz:
~$ python
>>> i = 0
>>> print i
>>> i = i + 1
>>> print i
108
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Ćwiczenie 4
Po 3 bł˛ednej próbie program ponownie wyświetla komunikat: “Nie zgadłeś... Spróbuj jeszcze raz.” Użyj intrukcji
if z odpowiednim warunkiem i wci˛eciami (!), aby po 3 nieudanej próbie wyświetlić komunikat: “Miałem na myśli
liczb˛e: liczba”.
Ostateczny wynik działania naszego programu prezentuje si˛e tak:
5.1.6 Duży Lotek
Jedna liczba to za mało, wylosujmy ich wi˛ecej! Zasady dużego lotka to typowanie 6 liczb z 49. Ponieważ trafienie jest
tu bardzo trudne, napiszemy program w taki sposób, aby można było łatwo dostosować poziom jego trudności. Na
poczatku
˛ utwórz nowy plik toto2.py i uzupełnij go wymaganymi liniami wskazujacymi interpreter pythona i użyte
kodowanie.
Ćwiczenie 5
Niech użytkownik określi ile liczb chce typować i z jakiego zakresu. Pobierz od użytkownika ilość typowanych
liczb, podana˛ wartość przechowaj w zmiennej ileliczb. Podobnie pobierz i zapisz maksymalna˛ losowana˛ liczb˛e w
zmiennej maksliczba. Na koniec wyświetl komunikat “Wytypuj x z y liczb: ”. Zamiast x i y powinny wyświetlić
si˛e podane przez użytkownika wartości.
Wskazówka: Skorzystaj z instrukcji raw_iput(), której użyj jako argumentu funkcji int().
5.1.7 Losowanie wielu liczb
Ćwiczenie 6
Jedna˛ wylosowana˛ liczb˛e zapami˛etywaliśmy w jednej zmiennej, ale przechowywanie wielu wartości w osobnych
zmiennych nie jest dobrym pomysłem. Najwygodniej byłoby mieć jedna˛ zmienna,˛ w której można zapisać wiele
wartości. W Pythonie takim złożonym typem danych jest lista.
Przetestuj w interpreterze nast˛epujace
˛ polecenia:
~$ python
>>> liczby = []
>>> liczby
>>> liczby.append(1)
5.1. Toto Lotek – Python od podstaw
109
Materiały eCG IT Documentation, Wydanie 1
>>>
>>>
>>>
>>>
>>>
>>>
>>>
liczby.append(2)
liczby.append(4)
liczby.append(4)
liczby
liczby.count(1)
liczby.count(4)
liczby.count(0)
Wskazówka: Zamiast wpisywać w terminalu powtarzajace
˛ si˛e lub podobne polecenia, użyj klawiszy kursora (góra,
dół) do przywoływania poprzednich poleceń. Każde przywołane polecenie możesz przed zatwierdzeniem zmienić
używajac
˛ klawiszy lewo, prawo, del i backspace.
Jak widać po zadeklarowaniu pustej listy (liczby = []), metoda .append() pozwala dodawać do niej wartości,
a metoda .count() podaje, ile razy dana wartość wystapiła
˛
w liście. To si˛e nam przyda ;-)
Wróćmy do programu i pliku toto2.py. Losowanie wielu liczb to... powtarzajace
˛ si˛e losowanie jednej liczby, czyli
p˛etla. Spróbuj użyć poznanej wcześniej instrukcji for, aby dopisać kod losujacy
˛ ileliczb z zakresu ograniczonego przez maksliczba. Wylosowane wartości wydrukuj w terminalu... Przetestuj program, powinien wypisywać
kolejne losowane liczby.
Kontynuujemy ćwiczenie. Przed p˛etla˛ zadeklaruj pusta˛ list˛e. Wewnatrz
˛ p˛etli umieść polecenie dodajace
˛ wylosowane
liczby do listy. Na końcu programu (uwaga na wci˛ecia) wydrukuj zawartość listy. Wielokrotnie przetestuj program;
czy lista zawsze zawiera akceptowalne wartości?
P˛etla for nie nadaje si˛e do losowania liczb, ponieważ wykonuje si˛e określona˛ ilość razy, a nie możemy zagwarantować, że losowane liczby b˛eda˛ za każdym razem inne. Do wylosowania podanej ilości liczb wykorzystamy wi˛ec p˛etl˛e
while wyrażenie_logiczne:, która powtarza kod dopóki podane wyrażenie jest prawdziwe. Uzupełniamy
Kod w pliku toto2.py:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5
6
7
8
ileliczb = int(raw_input("Podaj ilość typowanych liczb: "))
maksliczba = int(raw_input("Podaj maksymalna˛ losowana˛ liczb˛
e: "))
#print "Wytypuj",ileliczb,"z",makliczba," liczb: "
9
10
11
12
13
14
15
16
liczby = []
#for i in range(ileliczb):
i = 0
while i < ileliczb:
liczba = random.randint(1, maksliczba)
if liczby.count(liczba) == 0:
liczby.append(liczba)
110
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
17
i = i + 1
18
19
print "Wylosowane liczby:",liczby
Losowane liczby zapami˛etujemy w liście liczby (zob. lista). Zmienna i to licznik unikalnych wylosowanych liczb, korzystamy z niej w wyrażeniu warunkowym i < ileliczb, które kontroluje powtórzenia p˛etli. W instrukcji warunkowej wykorzystujemy funkcj˛e zliczajac
˛ a˛ wystapienia
˛
wylosowanej wartości w liście
(liczby.count(liczba)), aby dodawać (liczby.append(liczba)) do listy liczby wcześniej niepodane.
5.1.8 Nasze typy
Przy pobieraniu typów użytkownika użyjemy podobnie jak przed chwila˛ p˛etli while, ale typy zapisywać b˛edziemy
w zbiorze, który z założenia nie może zawierać duplikatów (zob. zbiór).
Ćwiczenie 7
W interpreterze Pythona przetestuj nast˛epujace
˛ polecenia:
~$ python
>>> typy = set()
>>> typy.add(1)
>>> typy.add(2)
>>> typy
>>> typy.add(2)
>>> typy
>>> typy.add(0)
>>> typy.add(9)
>>> typy
Pierwsza instrukcja deklaruje pusty zbiór (typy = set()). Metoda .add() dodaje do zbioru elementy, ale nie
da si˛e dodać dwóch takich samych elementów. Druga˛ cecha˛ zbiorów jest to, że ich elementy nie sa˛ w żaden sposób
uporzadkowane.
˛
Wykorzystajmy poznany typ, aby pobrać od użytkownika typy liczb. W pliku toto2.py dopisujemy:
20
21
22
23
24
25
26
27
print "Wytypuj",ileliczb,"z",maksliczba," liczb: "
typy = set()
i = 0
while i < ileliczb:
typ = raw_input("Podaj liczb˛
e "+str(i+1)+": ")
if typ not in typy:
typy.add(typ)
i = i + 1
W powyższym kodzie warto zwrócić uwag˛e na sposób sprawdzania, czy podanej liczby nie ma już w zbiorze: if
typ not in typy:. Gdybyśmy chcieli sprawdzić, czy liczba jest w zbiorze, użylibyśmy wyrażenia typ in
typy. Przetestuj program.
5.1.9 Ile trafiliśmy
Określenie ilości trafień w wi˛ekszości j˛ezyków programowania wymagałoby przeszukiwania listy wylosowanych liczb
dla każdego podanego typu. W Pythonie możemy użyć arytmetyki zbiorów: wyznaczymy cz˛eść wspólna.˛
5.1. Toto Lotek – Python od podstaw
111
Materiały eCG IT Documentation, Wydanie 1
Ćwiczenie 8
W interpreterze przetestuj poniższe instrukcje:
~$ python
>>> liczby = [1,3,5,7,9]
>>> typy = set([2,3,4,5,6])
>>> set(liczby) | typy
>>> set(liczby) - typy
>>> trafione = set(liczby) & typy
>>> len(trafione)
Polecenie set(liczby) przekształca list˛e na zbiór. Kolejne operatory zwracaja˛ sum˛e (|), różnic˛e (-) i iloczyn (&),
czyli cz˛eść wspólna˛ zbiorów. Ta ostania operacja bardzo dobrze nadaje si˛e do sprawdzenia, ile liczb trafił użytkownik.
Funkcja len() zwraca ilość elementów m.in. listy i zbioru.
Do pliku toto2.py dopisujemy:
31
32
33
34
35
36
trafione = set(liczby) & typy
if trafione:
print "\nIlość trafień: ",len(trafione)
print "Trafione liczby: ",trafione
else:
print "Brak trafień. Spróbuj jeszcze raz!"
Instrukcja if trafione: sprawdza, czy cz˛eść wspólna zawiera jakiekolwiek elementy. Jeśli tak, drukujemy liczb˛e
trafień i trafione liczby.
Ćwiczenie 9
Przetestuj program dla 5 typów z 10 liczb. Działa? Jeśli masz watpliwości,
˛
wpisz wylosowane i wytypowane liczby
w interpreterze, np.:
>>>
>>>
>>>
>>>
...
...
>>>
liczby = [1,4,2,6,7]
typy = set([1,2,3,4,5])
trafione = set(liczby) & typy
if trafione:
print len(trafione)
print trafione
Wnioski? Logika kodu jest poprawna, czego dowodzi test w terminalu, ale program nie działa. Dlaczego?
Wskazówka: Przypomnij sobie, jakiego typu wartości zwraca funkcja raw_input().
Ćwiczenie 10
Zmodyfikuj program tak, aby wynik jego działania wygladał
˛ nast˛epujaco:
˛
Ćwiczenie 11
Zmień program tak, aby użytkownik mógł 3 razy typować liczby z tej samej serii liczb wylosowanych. Wynik działania
programu powinien przypominać poniższy zrzut:
Wskazówka: Wykorzystaj p˛etl˛e for.
112
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.1. Toto Lotek – Python od podstaw
113
Materiały eCG IT Documentation, Wydanie 1
5.1.10 Uwaga: błedne
˛
dane!
Kod naszego programu do tej pory przedstawia si˛e mniej wi˛ecej tak:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5
6
7
ileliczb = int(raw_input("Podaj ilość typowanych liczb: "))
maksliczba = int(raw_input("Podaj maksymalna˛ losowana˛ liczb˛
e: "))
8
9
10
11
12
13
14
15
16
liczby = []
i = 0
while i < ileliczb:
liczba = random.randint(1, maksliczba)
print "Wylosowane liczba:",liczba
if liczby.count(liczba) == 0:
liczby.append(liczba)
i = i + 1
17
18
19
20
21
22
23
24
25
26
for i in range(3):
print "Wytypuj",ileliczb,"z",maksliczba," liczb: "
typy = set()
i = 0
while i < ileliczb:
typ = int(raw_input("Podaj liczb˛
e "+str(i+1)+": "))
if typ not in typy:
typy.add(typ)
i = i + 1
27
trafione = set(liczby) & typy
if trafione:
print "\nIlość trafień: ",len(trafione)
print "Trafione liczby: ",trafione
else:
print "Brak trafień. Spróbuj jeszcze raz!"
28
29
30
31
32
33
34
print "\n"+"x"*40+"\n" # wydrukuj 40 znaków x
35
36
37
print "Wylosowane liczby:",liczby
Uruchom powyższy program i podaj ilość losowanych liczb wi˛eksza˛ od maksymalnej losowanej liczby. Program
wpada w nieskończona˛ p˛etl˛e! Po chwili zastanowienia dojdziemy do wniosku, że nie da si˛e wylosować np. 6 unikalnych liczb z zakresu 1-5.
Ćwiczenie 12
Dodaj odpowiednia˛ instrukcj˛e warunkowa,˛ która w przypadku gdy zmienna ileliczb b˛edzie mniejsza od zmiennej
maksliczba wyświetli komunikat “Bł˛edne dane!” i przerwie wykonywanie programu – użyj funkcji exit().
Sprawdź działanie programu.
Tetsujemy dalej. Uruchom program i zamiast liczby podaj tekst. Co si˛e dzieje? Uruchom jeszcze raz, ale tym razem
jako typy podaj wartości spoza zakresu <0;maksliczba>. Da si˛e to zrobić?
114
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Jak pewnie zauważyłeś, w pierwszym wypadku zgłoszony zostaje wyjatek
˛ “ValuError” (zob.: wyjatki)
˛
i komunikat
invalid literal for int() with base 10, który informuje, że fukncja int() nie jest w stanie przekształcić podanego ciagu
˛ znaków na liczb˛e całkowita.˛ W drugim wypadku podanie nielogicznych typów jest możliwe.
Spróbujmy zmodyfikować program tak, aby był nieco odporniejszy na niepoprawne dane:
6
try:
7
ileliczb = int(raw_input("Podaj ilość typowanych liczb: "))
maksliczba = int(raw_input("Podaj maksymalna˛ losowana˛ liczb˛
e: "))
if ileliczb > maksliczba:
print "Bł˛
edne dane!"
exit()
except:
print "Bł˛
edne dane!"
exit()
8
9
10
11
12
13
14
Do przechwytywania wyjatków
˛
używamy konstrukcji try: ... except: ..., czyli spróbuj wykonać kod
w bloku try, a w razie bł˛edów przechwyć wyjatek
˛ ValueError i wykonaj podporzadkowane
˛
instrukcje. W powyższym przypadku wyświetlamy odpowiedni komunikat i kończymy działanie programu (exit()).
28
29
30
31
32
33
while i < ileliczb:
try:
typ = int(raw_input("Podaj liczb˛
e "+str(i+1)+": "))
except ValueError:
print "Bł˛
edne dane!"
continue
34
35
36
37
if 0 < typ <= maksliczba and typ not in typy:
typy.add(typ)
i = i + 1
Pobierajac
˛ typy od użytkownika również musimy spróbować przekształcić podane znaki na liczb˛e (int()) i w razie
bł˛edu przechwycić wyjatek
˛ (try...except). Poza tym jednak trzeba sprawdzić, czy użytkownik podaje sensowane
typy. Odpowiada za to warunek 0 < typ <= maksliczba. Jest to skrócony zapis wyrażenia: typ > 0 and
typ <= maksliczba.
Na koniec warto zauważyć, co dzieje si˛e, kiedy przechwytujemy wyjatek.
˛
Nie kończymy programu (exit()), ani
nie przerywamy p˛etli (break()), zamiast tego pomijamy dalsze polecenia i wznawiamy wykonywanie p˛etli kolejny
raz. Tak działa polecenie continue.
5.1.11 Funkcje i moduły
Tam, gdzie w programie wyst˛epuja˛ powtarzajace
˛ si˛e operacje lub zestaw poleceń realizujacy
˛ wyodr˛ebnione zadanie,
wskazane jest używanie funkcji. Sa˛ to nazwane bloki kodu, które można grupować w ramach modułów (zob. funkcja,
zob. moduł). Funkcje zawarte w modułach można importować do różnych programów. Do tej pory korzystaliśmy np.
z funkcji randit() zawartej w module random.
Wyodr˛ebnienie funkcji ułatwia sprawdzanie i poprawianie kodu, ponieważ wymusza podział programu na logicznie
uporzadkowane
˛
kroki. Jeżeli program korzysta z niewelu funkcji, można umieszczać je na poczatku
˛ pliku programu
głównego.
Tworzymy wi˛ec nowy plik totomodul.py rozpoczynajacy
˛ si˛e liniami wskazujacymi
˛
interpreter i kodowanie.
Umieszczamy w nim nast˛epujacy
˛ kod:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random
5.1. Toto Lotek – Python od podstaw
115
Materiały eCG IT Documentation, Wydanie 1
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def ustawienia():
"""Funkcja pobiera ilość losowanych liczb, maksymalna˛ losowana˛ wartość
oraz ilość prób. Pozwala określić stopień trudności gry."""
while 1:
try:
ile = int(raw_input("Podaj ilość typowanych liczb: "))
maks = int(raw_input("Podaj maksymalna˛ losowana˛ liczb˛
e: "))
if ile > maks:
print "Bł˛
edne dane!"
continue
ilelos = int(raw_input("Ile losowań: "))
return (ile, maks, ilelos)
except:
print "Bł˛
edne dane!"
continue
21
22
23
24
25
26
27
28
29
30
31
def losujliczby(ile, maks):
"""Funkcja losuje ile unikalnych liczb całkowitych od 1 do maks"""
liczby = []
i = 0
while i < ile:
liczba = random.randint(1, maks)
if liczby.count(liczba) == 0:
liczby.append(liczba)
i = i + 1
return liczby
32
33
34
35
36
37
38
39
40
41
42
43
44
def pobierztypy(ile, maks):
"""Funkcja pobiera od użytkownika jego typy wylosowanych liczb"""
print "Wytypuj",ile,"z",maks," liczb: "
typy = set()
i = 0
while i < ile:
try:
typ = int(raw_input("Podaj liczb˛
e "+str(i+1)+": "))
except ValueError:
print "Bł˛
edne dane!"
continue
45
if 0 < typ <= maks and typ not in typy:
typy.add(typ)
i = i + 1
return typy
46
47
48
49
Kod odpowiedzialny za ustawienia gry, losowanie liczb i pobieranie typów użytkownika umieszczony został w osobnych funkcjach sygnalizowanych słowem kluczowym def i wci˛eciami. Funkcje moga˛ przyjmować definiowane w
nawiasach dane wejściowe, np. losujliczby(ile, maks), które podajemy jako argumenty w momencie wywołania funkcji. Funkcje moga˛ zwracać dane wyjściowe za pomoca˛ instrukcji return.
Warto zauważyć, że można zwracać wi˛ecej niż jedna˛ wartość naraz, np. w postaci tupli (ile, maks, ilelos).
Tupla to rodzaj listy, w której nie możemy zmieniać wartości (zob. tupla), jest cz˛esto stosowana do przechowywania
i przekazywania stałych danych.
Nazwy zmiennych lokalnych w funkcjach sa˛ niezależne od nazw zmiennych w programie głównym, ponieważ definiwane sa˛ w różnych zasi˛egach czy też przestrzeniach nazw. Możliwe jest modyfikowanie zmiennych globalnych
dost˛epnych w całym programie, w funkcji musimy tylko umieścić polecenie: global nazwa_zmiennej.
116
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Wiele wartości zwracanych w tupli przez funkcj˛e ustawienia() można jednocześnie przypisać kilku zmiennym
dzi˛eki operacji tzw. rozpakowania tupli: ileliczb, maksliczba, ilerazy = ustawienia().
Dwie pozostałe funkcje zwracaja˛ list˛e wylosowanych liczb i zbiór typów.
Program główny po zmianach przedstawia si˛e nast˛epujaco:
˛
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
from totomodul import ustawienia, losujliczby, pobierztypy
5
6
# program główny
7
8
9
# ustalamy trudność gry
ileliczb, maksliczba, ilerazy = ustawienia()
10
11
12
# losujemy liczby
liczby = losujliczby(ileliczb, maksliczba)
13
14
15
16
17
18
19
20
21
22
# trzy razy pobieramy typy użytkownika i sprawdzamy, ile liczb trafił
for i in range(ilerazy):
typy = pobierztypy(ileliczb, maksliczba)
trafione = set(liczby) & typy
if trafione:
print "\nIlość trafień: ",len(trafione)
print "Trafione liczby: ",trafione
else:
print "Brak trafień. Spróbuj jeszcze raz!"
23
24
print "\n"+"x"*40+"\n" # wydrukuj 40 znaków x
25
26
print "Wylosowane liczby:",liczby
Na poczatku
˛
z modułu totomodul, którego nazwa jest taka sama jak nazwa pliku, importujemy potrzebne funkcje. Później wywołujemy je podajac
˛ nazw˛e i ewentualne argumenty. W efekcie zwracane przez nie wartości zostaja˛
przypisane podanym zmiennym. Jak widać, program stał si˛e czytelniejszy.
Informacja: W rozbudowanych programach dobra˛ praktyka˛ ułatwiajac
˛ a˛ późniejsze przegladanie
˛
i poprawianie kodu
jest opatrywanie jego fragmentów komentarzami. Można je umieszczać po znaku #. Z kolei funkcje opatruje si˛e krótkim opisem działania i/lub wymaganych argumentów, ograniczanym potrójnymi cudzysłowami. Notacja """..."""
lub ’’’...’’’ pozwala zamieszczać teksty wielowierszowe.
Ćwiczenie 13
Użytkownik może typować liczby kilka razy w ramach jednego uruchomienia programu. Powtarzany w p˛etli for kod
warto przenieść do funkcji zapisanej w module programu i nazwanej np. wyniki(). Zastanów si˛e, jakie argumenty
należy jej przekazać i co powinna zwracać.
5.1.12 Ustawienia
Uruchamiajac
˛ wielokrotnie program, musimy podawać wiele danych, aby zadziałał. Dodamy wi˛ec możliwość zapami˛etywania ustawień i ich zmiany. Dane zapisywać b˛edziemy w zwykłym pliku tekstowym. W pliku toto2.py
uzupełniamy tylko jedna˛ lini˛e:
5.1. Toto Lotek – Python od podstaw
117
Materiały eCG IT Documentation, Wydanie 1
8
9
# ustawienia gry
nick, ileliczb, maksliczba, ilerazy = ustawienia()
W pliku totomodul.py zmieniamy funkcj˛e ustawienia() oraz dodajemy dwie nowe: czytaj_ust() i
zapisz_ust().
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import random, os
5
6
7
8
def ustawienia():
"""Funkcja pobiera nick użytkownika, ilość losowanych liczb, maksymalna˛
losowana˛ wartość oraz ilość typowań. Ustawienia zapisuje."""
9
nick = raw_input("Podaj nick: ")
nazwapliku = nick + ".ini"
gracz = czytaj_ust(nazwapliku)
odp = None
if gracz:
print "Twoje ustawienia:"
print "Liczb:",gracz[1]
print "Z Maks:",gracz[2]
print "Losowań:",gracz[3]
odp = raw_input("Zmieniasz (t/n)? ")
10
11
12
13
14
15
16
17
18
19
20
if not gracz or odp.lower() == "t":
while 1:
try:
ile = int(raw_input("Podaj ilość typowanych liczb: "))
maks = int(raw_input("Podaj maksymalna˛ losowana˛ liczb˛
e: "))
if ile > maks:
print "Bł˛
edne dane!"
continue
ilelos = int(raw_input("Ile losowań: "))
break
except:
print "Bł˛
edne dane!"
continue
gracz = zapisz_ust(nazwapliku, [nick, str(ile), str(maks), str(ilelos)])
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
return gracz[0:1] + map(lambda x: int(x), gracz[1:4])
36
37
38
39
40
41
42
43
44
def czytaj_ust(nazwapliku):
if os.path.isfile(nazwapliku):
plik = open(nazwapliku, "r")
linia = plik.readline()
if linia:
return linia.split(";")
return False
45
46
47
48
49
50
def zapisz_ust(nazwapliku, gracz):
plik = open(nazwapliku, "w")
plik.write(";".join(gracz))
plik.close()
return gracz
W funkcji ustawienia() pobieramy nick użytkownika i tworzymy nazw˛e pliku z ustawieniami, nast˛epnie próbujemy je odczytać wywołujac
˛ funkcj˛e czytaj_ust(). Funkcja ta sprawdza, czy podany plik istnieje na dysku i
118
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
otwiera go do odczcytu: plik = open(nazwapliku, "r"). Plik powinien zawierać 1 lini˛e, która przechowuje
ustawienia w formacie: nick;ile_liczb;maks_liczba;ile_prób. Po jej odczytaniu za pomoca˛ metody
.readline() i rozbiciu na elementy zwracamy ja˛ jako list˛e gracz.
Jeżeli uda si˛e odczytać zapisane ustawienia, drukujemy je, a nast˛epnie pytamy, czy użytkownik chce je zmienić.
Jeżeli nie znaleźliśmy zapisanych ustawień lub użytkownik nacisnał
˛ klawisz “t” lub “T” wykonujemy poprzedni kod.
Na koniec zmiennej gracz przypisujemy list˛e ustwień przekazana˛ do zapisu funkcji zapisz_ust(). Funkcja ta
zapisuje dane złaczone
˛
za pomoca˛ średnika w jedna˛ lini˛e do pliku: plik.write(";".join(gracz)).
W powyższym kodzie widać, jakie operacje można wykonywać na tekstach, tj.:
• operator +: łaczenie
˛
tekstów,
• linia.split(";") – rozbijanie tekstu wg podanego znaku na elementy listy,
• ";".join(gracz) – złaczanie
˛
elementów listy za pomoca˛ podanego znaku,
• odp.lower() – zmiana wszystkich znaków na małe litery,
• str(arg) – przekształcanie podanego argumentu na typ tekstowy.
Na szczególna˛ uwag˛e zasługuje konstrukcja return gracz[0:1] + map(lambda x: int(x),
gracz[1:4]), której używamy, aby zwrócić odczytane/zapisane ustawienia do programu głównego. Dane
w pliku przechowujemy, a także pobieramy od użytkownika jako znaki. Natomiast program główny oczekuje 4
wartości typu: znak, liczba, liczba, liczba. Stosujemy wi˛ec notacj˛e wycinkowa˛ (ang. slice), aby wydobyć nick
użytkownika: gracz[0:1]. Pierwsza wartość mówi od którego elementu, a druga do którego elementu wycinamy
wartości z listy (przećwicz w konsoli Pythona!). Funkcja map() pozwala zastosować do pozostałych 3 elementów
– gracz[1:4] – funkcj˛e, która zamienia je w wartości liczbowe. Wykorzystujemy tu wyrażenia lambda, czyli
skrócony zapis 1-argumentowej funkcji (zob. mapowanie funkcji).
5.1.13 Historia losowań
Skoro umiemy już zapami˛etywać wst˛epne ustawienia programu, możemy również zapami˛etywać losowania użytkownika, tworzac
˛ rejestr do celów informacyjnych i/lub statystycznych. Zadanie wymaga po pierwsze zdefiniowania jakieś
struktury, w której b˛edziemy przechowywali dane, po drugie zapisu danych albo w plikach, albo w bazie danych.
Na poczatku
˛ dopiszemy kod w programie głównym toto2.py:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
5
6
from totomodul import ustawienia, losujliczby, pobierztypy, wyniki
from totomodul import czytaj_json, zapisz_json
import time
7
8
# program główny
9
10
11
# ustalamy trudność gry
nick, ileliczb, maksliczba, ilerazy = ustawienia()
12
13
14
nazwapliku = nick + ".json"
losowania = czytaj_json(nazwapliku)
15
16
17
# losujemy liczby
liczby = losujliczby(ileliczb, maksliczba)
18
19
20
21
# pobieramy typy użytkownika i sprawdzamy, ile liczb trafił
for i in range(ilerazy):
typy = pobierztypy(ileliczb, maksliczba)
5.1. Toto Lotek – Python od podstaw
119
Materiały eCG IT Documentation, Wydanie 1
trafione = wyniki(set(liczby), typy)
22
23
24
25
26
27
28
29
losowania.append({
"czas": time.time(),
"dane": (ileliczb, maksliczba),
"wylosowane": liczby,
"ile": trafione
})
30
31
zapisz_json(nazwapliku, losowania)
32
33
34
print "Wylosowane liczby:",liczby
print "\n",losowania
Dane graczy zapisywać b˛edziemy w plikach nazwanych nickiem użytkownika z rozszerzeniem ”.json”:
nazwapliku = nick + ".json". Informacje o grach umieścimy w liście losowania, która˛ na poczatku
˛
zainicjujemy danymi o grach zapisanymi wcześniej: losowania = czytaj(nazwapliku).
Każda gra w liście losowania to słownik. Struktura ta pozwala przechowywać dane w parach “klucz: wartość”,
przy czym indeksami moga˛ być napisy:
• "czas" – b˛edzie indeksem daty gry (potrzebny import modułu time!),
• "dane" – b˛edzie wskaywał tupl˛e z ustawieniami,
• "wylosowane" – list˛e wylosowanych liczb,
• "ile" – ilość trafień.
Na koniec dane ostatniej gry dopiszemy do listy (losowania.append()), a cała˛ list˛e zapiszemy do pliku:
zapisz(nazwapliku, losowania).
Teraz zobaczmy, jak wygladaj
˛ a˛ funkcje czytaj_json() i zapisz_json() w module totomodul.py:
92
import json
93
94
95
96
97
98
99
100
def czytaj_json(nazwapliku):
"""Funkcja odczytuje dane w formacie json z pliku"""
dane = []
if os.path.isfile(nazwapliku):
with open(nazwapliku, "r") as plik:
dane = json.load(plik)
return dane
101
102
103
104
105
def zapisz_json(nazwapliku, dane):
"""Funkcja zapisuje dane w formacie json do pliku"""
with open(nazwapliku, "w") as plik:
json.dump(dane, plik)
Kiedy czytamy i zapisujemy dane, ważna˛ sprawa˛ staje si˛e ich format. Najprościej zapisywać dane jako znaki, tak
jak zrobiliśmy to z ustawieniami, jednak cz˛esto programy użytkowe potrzebuja˛ zapisywać złożone struktury danych,
np. listy, zbiory czy słowniki. Znakowy zapis wymagałby wtedy wielu dodatkowych manipulacji, aby możliwe
było poprawne odtworzenie informacji. Prościej jest skorzystać z serializacji, czyli zapisu danych obiektowych (zob.
serializacja). Jednym z szerzej stosowanych jest prosty format tekstowy JSON.
W funkcji czytaj() zawartość podanego pliki dekodujemy do listy: dane = json.load(plik). Funkcja
zapisz() oprócz nazwy pliku wymaga listy danych. Po otwarciu pliku w trybie zapisu "w", co powoduje wyczyszczenie jego zawartości, dane sa˛ serializowane i zapisywane formacie JSON: json.dump(dane, plik).
Dobra˛ praktyka˛ jest zwalnianie uchwytu do otwartego pliku i przyddzielonych mu zasobów poprzez jego zamkni˛ecie:
plik.close(). Tak robiliśmy w funkcjach czytajacych
˛
i zapisujacych
˛
ustawienia. Teraz jednak pliki otworzy-
120
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
liśmy przy użyciu konstrukcji typu with open(nazwapliku, "r") as plik:, która zadba o ich własciwe
˛
zmakni˛ecie.
Przetestuj, przynajmniej kilkukrotnie, działanie programu.
Ćwiczenie 14
Załóżmy, że jednak chcielibyśmy zapisywać histori˛e losowań w pliku tekstowym, którego poszczególne linie zawierałyby dane jednego losowania, np.:
wylosowane:[4, 5, 7];dane:(3,
10);ile:0;czas:1434482711.67
Funkcja zapisujaca
˛ dane mogłaby wygladać
˛
np. tak:
Napisz funkcj˛e czytaj_str() odczytujac
˛ a˛ tak zapisane dane. Funkcja powinna zwrócić list˛e słowników.
5.1.14 Wydruk historii
[todo]
5.2 Python kreśli
Jedna˛ z pot˛eżniejszych biliotek Pythona jest matplotlib, która służy do tworzenia różnego rodzaju wykresów. Pylab to
API ułatwiajace
˛ korzystanie z omawianej biblioteki na wzór środowiska Matlab. Poniżej pokazujemy, jak łatwo przy
użyciu Pythona wizualizować wykresy różnych funkcji.
Najłatwiej zainstalować wymagana˛ bibliotek˛e wydajac
˛ polecenie z uprawnieniami roota w terminalu:
~# pip install matplotlib
• Funkcja liniowa
• Dwie funkcje
5.2.1 Funkcja liniowa
Zabw˛e zacznijmy w konsoli Pythona:
import pylab
x = [1,2,3]
y = [4,6,5]
pylab.plot(x,y)
pylab.show()
Tworzenie wykresów jest proste. Musimy mieć zbiór wartości x i odpowiadajacy
˛ im zbiór wartości y. Obie listy
przekazujemy jako argumenty funkcji plot(), a nast˛epnie rysujemy funkcja˛ show().
Spróbujmy zrealizować bardziej złożone zadanie.
ZADANIE: wykonaj wykres funkcji f(x) = a*x + b, gdzie x = <-10;10> z krokiem 1, a = 1, b = 2.
W pliku pylab01.py umieszczamy poniższy kod:
5.2. Python kreśli
121
Materiały eCG IT Documentation, Wydanie 1
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import pylab
5
6
7
8
a = 1
b = 2
x = range(-10,11) # lista argumentów x
9
10
11
12
y = [] # lista wartości
for i in x:
y.append(a*i + b)
13
14
15
16
17
pylab.plot(x,y)
pylab.title('Wykres f(x) = a*x - b')
pylab.grid(True)
pylab.show()
Na poczatku
˛ dla ułatwienia importujemy interfejs pylab. Nast˛epnie post˛epujemy wg omówionego schematu: zdefiniuj dziedzin˛e argumentów funkcji, a nast˛epnie zbiór wyliczonych wartości. W powyższym przypadku generujemy
list˛e wartości x za pomoca˛ funkcji range() – co warto przetestować w interaktywnej konsoli Pythona. Wartości y
wyliczamy w p˛etli i zapisujemy w liście.
Dodatkowe metody: title() ustawia tytuł wykresu, grid() włacza
˛
wyświetlanie pomocniczej siatki. Uruchom
program.
Ćwiczenie 1
Można ułatwić użytkownikowi testowanie funkcji, umożliwiajac
˛ mu podawanie współczynników a i b. Zastap
˛ odpowiednie przypisania instrukcjami pobierajacymi
˛
dane od użytkownika. Nie zapomnij przekonwertować danych
tekstowych na liczby całkowite. Przetestuj zmodyfikowany kod.
Ćwiczenie 2
W konsoli Pythona wydajemy nast˛epujace
˛ polecenia:
>>>
>>>
>>>
...
>>>
>>>
a = 2
x = range(11)
for i in x:
print a + i
y = [a + i for i in range(11)]
y
Powyższy przykład pokazuje kolejne ułatwienie dost˛epne w Pythonie, czyli wyrażenie listowe, które zwi˛eźle zast˛epuje
p˛etl˛e i zwraca list˛e wartości. Jego działanie należy rozumieć nast˛epujaco:
˛
dla każdej wartości i (nazwa zmiennej
dowolna) w liście x wylicz wyrażenie a + i i umieść w liście y.
Wykorzystajmy wyrażenie listowe w naszym programie:
6
7
8
a = int(raw_input('Podaj współczynnik a: '))
b = int(raw_input('Podaj współczynnik b: '))
x = range(-10,11) # lista argumentów x
9
10
11
# wyrażenie listowe wylicza dziedzin˛
e y
y = [a*i + b for i in x] # lista wartości
122
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.2.2 Dwie funkcje
ZADANIE: wykonaj wykres funkcji f(x), gdzie x = <-10;10> z krokiem 0.5, f(x) = x*x/3 dla x < 1 i x > 0, f(x) = x/(-3)
+ a dla x <= 0. Współczynnik a podaje użytkownik.
Ćwiczenie 2
Zanim zrealizujemy zadanie przećwiczmy w konsoli Pythona nast˛epujacy
˛ kod:
>>>
>>>
>>>
>>>
>>>
import pylab
x = pylab.frange(-10, 11, 0.5)
x
y = [i**2 for i in x if i <= 0]
len(y)
Wykonanie zadania wymaga umieszczenia na wykresie dwóch funkcji. Wykorzystamy funkcj˛e frange, która zwraca
list˛e wartości zmiennoprzecinkowych (zob. typ typy danych) z zakresu określonego przez dwa pierwsze argumenty i
z krokiem wyznaczonym przez argument trzeci. Druga˛ przydatna˛ konstrukcja˛ b˛edzie wyrażenie listowe uzupełnione
o instrukcj˛e warunkowa,˛ która ogranicza wartości, dla których obliczane jest podane wyrażenie.
W pliku pylab02.py umieszczamy poniższy kod:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
5
6
# ZADANIE: wykonaj wykres funkcji f(x), gdzie x = <-10;10> z krokiem 1
# f(x) = x*x/3 dla x < 1 i x > 0
# f(x) = x/-3 + a dla x <= 0
7
8
import pylab
9
10
11
x = pylab.frange(-10, 11, 0.5) # lista argumentów x
y1 = [i**2/3 for i in x if i < 1 or i > 0]
12
13
14
15
16
pylab.plot(x,y1)
pylab.title('Wykres f(x)')
pylab.grid(True)
pylab.show()
Uruchom program. Udało si˛e nam zrealizować pierwsza˛ cz˛eść zadania. Spróbujmy zakodować cz˛eść druga.˛ Dopisujemy:
13
14
a = int(raw_input("Podaj współczynnik a: "))
y2 = [i/-3 + a for i in x if i <= 0]
15
16
pylab.plot(x,y1,x,y2)
Po pobraniu współczynnika a od użytkownika tworzymy wyrażenie listowe wyliczajace
˛ druga˛ dziedzin˛e wartości.
Nast˛epnie do argumentów przekazywanych funkcji plot() dodajemy drug˛e par˛e list. Spróbuj uruchomić program.
Nie działa, dostajemy komunikat ValueError: x and y must have same first dimension, czyli listy wartości x i y w
którejś z par nie zawieraja˛ tyle samo elementów.
Ćwiczenie 3
Przetestujmy kod w konsoli Pythona:
5.2. Python kreśli
123
Materiały eCG IT Documentation, Wydanie 1
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
import pylab
x = pylab.frange(-10, 11, 0.5)
y1 = [i**2/3 for i in x if i < 1 or i > 0]
len(x) == len(y1)
a = 2
y2 = [i/-3 + a for i in x if i <= 0]
len(x) == len(y2)
len(x)
len(y2)
Uwaga: nie zamykaj tej sesji konsoli, zaraz si˛e nam jeszcze przyda.
Szybko zauważymy, że lista y2 zawiera mniej wartości niż dziedzina x. Co należy z tym zrobić? Jak wynika z
warunków zadania, wartości y2 obliczane sa˛ tylko dla argumentów mniejszych od zera. Zatem trzeba ograniczyć list˛e
x, tak aby zawierała tylko wartości z odpowiedniego przedziału. Wróćmy do konsoli Pythona:
Ćwiczenie 4
>>>
>>>
>>>
>>>
>>>
>>>
x
x[0]
x[0:5]
x[:5]
x[:len(y2)]
len(x[:len(y2)])
Z pomoca˛ przychodzi nam wydobywanie z listy wartości wskazywanych przez indeksy liczone od 0. Jednak prawdziwym ułatwieniem jest notacja wycinania (ang. slice), która pozwala podać pierwszy i ostatni indeks interesujacego
˛
nas zakresu. Zmieniamy wi˛ec wywołanie funkcji plot():
pylab.plot(x,y1,x[:len(y2)],y2)
Uruchom i przetestuj działanie programu.
Ćwiczenie 5
Spróbuj samodzielnie przygotować wykres funkcji kwadratowej: f(x) = a*x^2 + b*x + c, gdzie x = <-10;10> z krokiem
1, przyjmij nast˛epujace
˛ wartości współczynników: a = 1, b = -3, c = 1.
Uzyskany wykres powinien wygladać
˛
nast˛epujaco:
˛
Jeżli masz ochot˛e na wi˛ecej, daj znać!
5.3 Czat (wersja rozszerzona)
Zastosowanie Pythona i frameworka Django do stworzenia aplikacji internetowej Czat; prostego czata, w którym
zarejestrowani użytkownicy b˛eda˛ mogli wymieniać si˛e krótkimi wiadomościami.
124
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3. Czat (wersja rozszerzona)
125
Materiały eCG IT Documentation, Wydanie 1
•
•
•
•
•
•
•
•
•
•
•
•
•
Projekt i aplikacja
Model – Widok – Kontroler
Model danych i baza
Panel administracyjny
Widoki i szablony
Rejestrowanie użytkowników
Logowanie i wylogowywanie
Widoki ogólne
Obsługa wiadomości
Wiadomości jeszcze raz
Szablony
Style, skrpyty, pliki
Materiały
5.3.1 Projekt i aplikacja
Tworzymy nowy projekt Django, a nast˛epnie uruchamiamy lokalny serwer, który pozwoli śledzić post˛ep pracy. W
katalogu domowym wydajemy polecenia w terminalu:
~$ django-admin.py startproject czat
~$ cd czat
~/czat$ python manage.py runserver
Powstanie katalog projektu czat i podkatalog aplikacji o takiej samej nazwie chatter. Po wpisaniu w przegladarce
˛
adresu 127.0.0.1:8000 zobaczymy stron˛e powitalna.˛
Informacja: Domyślnie serwer nasłuchuje na porcie 8000, można go jednak uruchomić na innyn, jeżeli domyślny
byłby zaj˛ety. Wystarczy, że do polecenia dodamy np.: 127.0.0.1:8080.
W systemach Linux możemy kliknać
˛ w terminalu prawym klawiszem adres http://127.0.0.1:8000/ i wybrać
polecenie “Otwórz link”, aby szybko otworzyć domyślna˛ przegladark˛
˛
e. Lokalny serwer deweloperski zatrzymujemy
za pomoca˛ skrótu Ctrl+C.
Jeden projekt może zawierać wiele aplikacji zapisywanych w osobnych podkatalogach katalogu projektu.
126
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Rozpoczynamy od modyfikacji ustawień projektu, tak aby korzystał z polskiej wersji j˛ezykowej oraz lokalnych ustawień daty i czasu. Musimy również zarejestrować nasza˛ aplikacj˛e w projekcie. W pliku setting.py zmieniamy
nast˛epujace
˛ linie:
# czat/czat/settings.py
# rejestrujemy aplikacje
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'czat', # rejestrujemy aplikacj˛
e
)
LANGUAGE_CODE = 'pl' # ustawienie j˛
ezyka
TIME_ZONE = 'Europe/Warsaw' # ustawienie strefy czasowej
Ostrzeżenie: Uwaga: jeżeli w plikach Pythona chcemy stosować polskie znaki, m.in. w komentarzach, na
poczatku
˛ każdego pliku powinna znaleźć si˛e linia definiujaca
˛ kodowanie: # -*- coding: utf-8 -*-.
5.3.2 Model – Widok – Kontroler
W projektowaniu aplikacji internetowych za pomoca˛ Django odwołujemy si˛e do wzorca M(odel)V(iew)C(ontroller),
czyli Model–Widok–Kontroler 1 , co pozwala na oddzielenie danych od ich prezentacji oraz logiki aplikacji. Funkcje
kolejnych elementów sa˛ nast˛epujace:
˛
• Modele – model w Django reprezentuje źródło informacji; sa˛ to klasy Pythona odwzorowujace
˛ pojedyncze tabele w bazie danych 2 ; każda klasa zawiera właściwości odpowiadajace
˛ polom tabeli, może też zawierać funkcje
wykonujace
˛ operacje na danych. Instancja takiej klasy odpowiada rekordowi danych. Modele definiujemy w
pliku models.py.
• Widoki – widok w Django to funkcja czy klasa Pythona, która na podstawie żadań
˛
www (dla danych adresów
URL) zwraca odpowiedź, najcz˛eściej w postaci kodu HTML generowanego w szablonach (templates); odpowiedzia˛ może być również przekierowanie na inny adres, jakiś dokument lub obrazek. Django zawiera wiele
widoków wbudowanych. Widoki modyfikujemy lub definiujemy w pliku views.py.
• Kontroler – kontroler to mechanizm kierujacy
˛ kolejne żadania
˛
do odpowiednich widoków na podstawie wzorców adresów URL zawartych w pliku urls.py.
5.3.3 Model danych i baza
Pisanie aplikacji zaczynamy od zdefiniowania modelu, czyli klasy opisujacej
˛ tabel˛e zawierajac
˛ a˛ wiadomości. Instancje
tej klasy b˛eda˛ konkretnymi wiadomościami utworzonymi przez użytkowników systemu. Każda wiadomość b˛edzie
zwierała treść, dat˛e dodania oraz autora wiadomości (użytkownika).
W pliku ~/czat/czat/models.py, który musimy utworzyć, wpisujemy:
1 Twórcy Django traktuja˛ jednak ten wzorzec elastycznie, mówiac
˛ że ich framework wykorzystuje wzorzec MTV, czyli model (model), szablon
(template), widok (view).
2 Takie odwzorowanie nosi nazw˛
e mapowania obiektowo-relacyjnego (ORM). ORM odwzorowuje struktur˛e bazy na obiekty Pythona.
5.3. Czat (wersja rozszerzona)
127
Materiały eCG IT Documentation, Wydanie 1
1
2
# -*- coding: utf-8 -*# czat/czat/models.py
3
4
5
from django.db import models
from django.contrib.auth.models import User
6
7
8
9
10
11
class Wiadomosc(models.Model):
"""Klasa reprezentujaca
˛
wiadomość w systemie"""
tekst = models.CharField(max_length=250)
data_pub = models.DateTimeField()
autor = models.ForeignKey(User)
Jak widać, podczas opisywania klasy Wiadomosc podajemy nazwy poszczególnych właściwości (pól) oraz typy
przechowywanych w nich danych. Po zdefiniowaniu przynajmniej jednego modelu możemy utworzyć baz˛e danych
dla naszej aplikacji, czyli wszystkie potrzebne tabele. Podczas tworzenia bazy Django pyta o nazw˛e, email i hasło
administratora. Podajemy te dane po wydaniu w katalogu projektu w terminalu polecenia:
~/czat $ python manage.py syncdb
Informacja: Domyślnie Django korzysta z bazy SQLite, która przechowywana jest w jednym pliku db.sqlite3
w katalogu aplikacji. Warto zobaczyć, jak wyglada.
˛
Potrzebny b˛edzie jednak interpreter, który w razie potrzeby
doinstalujemy poleceniem apt-get install sqlite3. Nast˛epnie W terminalu wydajemy polecenie python
manage.py dbshell, które uruchamia interpreter bazy. Nast˛epnie możemy wylistować utworzone tabele poleceniem .tables. Możemy również zobaczyć jakie instrukcje SQL-a zostały użyte do utworzenia naszej tabeli:
.schema czat_wiadomosc. Z interpretera wychodzimy poleceniem .quit.
128
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3.4 Panel administracyjny
Django pozwala szybko utworzyć panel administratora dla projektu, dzi˛eki czemu b˛edziemy mogli zaczać
˛ dodawać
użytkowików i wprowadzać dane. Tworzymy wi˛ec plik ~/czat/czat/admin.py i rejestrujemy w nim nasz
model jako element panelu administracyjnego:
1
2
# -*- coding: utf-8 -*# czat/czat/admin.py
3
4
5
from django.contrib import admin
from czat.models import Wiadomosc # importujemy nasz model
6
7
8
# rejestrujemy model Wiadomosc w panelu administracyjnym
admin.site.register(Wiadomosc)
Ostrzeżenie: Jeżeli korzystamy z Django w wersji 1.6 przed skorzystaniem z panelu administratora jako superużytkownik, musimy dodać lini˛e: admin.autodiscover() w pliku urls.py przed deklaracja˛ zmiennej
urlpatterns. (Zobacz kod nr 7 poniżej.)
Po ewentualnym ponownym uruchomieniu serwera wchodzimy na adres 127.0.0.1:8080/admin/. Logujemy si˛e podajac
˛ dane wprowadzone podczas tworzenia bazy. Otrzymamy dost˛ep do panelu administracyjnego, w którym możemy
dodawać nowych użytkowników i wiadomości 3 .
W panelu administratora widać, że etykiety oznaczajace
˛ pojedyncza˛ wiadomość jak i wiele wiadomości nie sa˛ spolszczone, podobnie pole daty oznaczone jest etykieta˛ “Data pub”. Aby w pełni spolszczyć nasz model, w pliku
models.py dopisujemy:
1
2
# -*- coding: utf-8 -*# czat/czat/models.py
3
4
5
from django.db import models
from django.contrib.auth.models import User
3 Bezpieczna aplikacja powinna dysponować osobnym mechanizmem rejestracji użytkowników i dodawania wiadomości, tak by nie trzeba było
udost˛epniać panelu administracyjnego osobom postronnym.
5.3. Czat (wersja rozszerzona)
129
Materiały eCG IT Documentation, Wydanie 1
130
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
6
7
8
9
10
11
class Wiadomosc(models.Model):
"""Klasa reprezentujaca
˛
wiadomość w systemie"""
tekst = models.CharField(u'wiadomość', max_length=250)
data_pub = models.DateTimeField(u'data publikacji')
autor = models.ForeignKey(User)
12
13
14
15
16
class Meta: # ustawienia dodatkowe
verbose_name = u'wiadomość' # nazwa obiektu w j˛
ezyku polskim
verbose_name_plural = u'wiadomości' # nazwa obiektów w l.m.
ordering = ['data_pub'] # domyślne porzadkowanie
˛
danych
Jak widać, w definicjach każdego pola jako pierwszy argument możemy dopisać spolszczona˛ etykiet˛e, np. u’data
publikacji’. W podklasie Meta podajemy natomiast nazwy modelu w liczbie pojedynczej i mnogiej. Po odświeżeniu panelu adminitracyjnego (np. klawiszem F5) nazwy zostana˛ spolszczone.
Informacja: Prefix u przed łańcuchami znaków oznacza kodowanie unikod (ang. unicode) umożliwiajace
˛ wyświetlanie m.in. znaków narodowych.
Ćwiczenie 1
Po zalogowaniu na konto administratora dodajemy użytkownika “adam”. Na stronie szczegółów, która wyświetli si˛e
po jego utworzeniu, zaznaczamy opcj˛e “W zespole”, nast˛epnie w panelu “Dost˛epne uprawnienia” zaznaczmy opcje
dodawania (add), zmieniania (change) oraz usuwania (del) wiadomości (wpisy typu: “czat | wiadomosc | Can add
wiadomosc”) i przypisujemy je użytkownikowi naciskajac
˛ strzałk˛e w prawo.
Przelogowujemy si˛e na konto “adam” i dodajemy kilka przykładowych wiadomości.
Jak można zauważyć, dodane wiadomości wyświetlaja˛ si˛e na liście jako “Wiadomosc object”. Aby to poprawić,
5.3. Czat (wersja rozszerzona)
131
Materiały eCG IT Documentation, Wydanie 1
uzupełniamy definicj˛e naszego modelu o funkcj˛e, której zadaniem jest “autoprezentacja”, czyli wyświetlenie treści
wiadomości. W pliku models.py dopisujemy zachowujac
˛ wci˛ecia (!):
def __unicode__(self):
return self.tekst # "autoprezentacja"
18
19
5.3.5 Widoki i szablony
Panel administracyjny już mamy, ale po wejściu na stron˛e główna˛ zwykły użytkownik niczego ciekawego poza standardowym powitaniem Django nie widzi. Zajmiemy si˛e teraz stronami po stronie (:-)) użytkownika.
Dodawanie stron w Django polega na wykorzystywaniu widoków wbudowanych lub tworzeniu nowych. Sa˛ to klasy
lub funkcje Pythona wykonujace
˛ jakieś operacje po stronie serwera w odpowiedzi na żadania
˛
klienta. Widoki powia˛
132
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
zane sa˛ z określonymi adresami url. Widoki najcz˛eściej zwracaja˛ kod HTML wyrenderowany na podstawie szablonów,
do których możemy przekazywać dodatkowe dane 4 , np. z bazy. Dla przejrzystości przyj˛eto, że w katalogu aplikacji
(czat/czat):
1. plik views.py zawiera definicj˛e widoków, w tym wywołania szablonów,
2. plik url.py zawiera reguły łacz
˛ ace
˛ adresy url z widokami,
3. w katalogu czat/czat/templates/czat zapisujemy szablony pod nazwami określonymi w wywołuja˛
cych je widokach, np. index.html.
Aby utworzyć stron˛e główna,˛ stworzymy pierwszy widok, czyli funkcj˛e index() 5 , która˛ powia˛żemy z adresem
URL głównej strony (/). Najprostszy widok zwraca podany tekst. W pliku views.py umieszczamy:
1
2
# -*- coding: utf-8 -*# czat/czat/views.py
3
4
from django.http import HttpResponse
5
6
7
8
def index(request):
"""Strona główna aplikacji."""
return HttpResponse("Witaj w aplikacji Czat!")
Informacja: Warto zapami˛etać, że każda˛ funkcj˛e, formularz czy widok udost˛epniane przez Django, których chcemy
użyć, musimy najpierw zaimportować za pomoca˛ klauzuli typu from <skad>
˛
import <co>.
W pliku urls.py przede wszystkim importujemy widoki naszej aplikacji: from czat import views. Nast˛epnie widok index() łaczymy
˛
z adresem URL strony głównej (/):
1
2
# -*- coding: utf-8 -*# czat/czat/urls.py
3
4
5
6
from django.conf.urls import patterns, include, url
from django.contrib import admin
from czat import views # importujemy zdefiniowane w pliku views.py widoki
7
8
admin.autodiscover() # potrzebne tylko w Django 1.6
9
10
11
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
12
url(r'^admin/', include(admin.site.urls)),
13
14
)
Podstawowa˛ funkcja˛ jest tu url(), która jako pierwszy parametr przyjmuje wyrażenie regularne oznaczane skrótem
r przed łańcuchem. Symbol ^ oznacza poczatek
˛
łańcucha, $ – koniec. Zapis u’^$’ to adres główny serwera.
Drugi parametr wskazuje widok (funkcj˛e), która ma obsłużyć dany adres. Trzeci parametr name pozwala zapami˛etać
skojarzenie url-a i widoku pod nazwa,˛ której b˛edzie można użyć np. do wygenerowania adresu linku.
Skoro mamy widok i przypisaliśmy go do jakiegoś adresu URL, możemy przetestować działanie aplikacji. Po wywołaniu strony głównej powinniśmy zobaczyć tekst podany jako argument funkcji HttpResponse() w pliku
views.py:
Zazwyczaj odpowiedzia˛ na wywołanie jakiegoś adresu URL b˛edzie jednak jakaś strona zapisana w j˛ezyku HTML.
Szablony takich stron umieszczamy w podkatalogu templates/nazwa aplikacji. Tworzymy wi˛ec katalog:
4 Dane z bazy przekazywane sa˛ do szablonów za pomoca˛ Pythonowego słownika. Renderowanie polega na odszukaniu pliku szablonu, zasta˛
pieniu przekazanych zmiennych danymi i odesłaniu całości (HTML + dane) do użytkownika.
5 Nazwa index() jest przykładowa, funkcja mogłaby si˛
e nazywać inaczej.
5.3. Czat (wersja rozszerzona)
133
Materiały eCG IT Documentation, Wydanie 1
~/czat/czat$ mkdir -p templates/czat
Nast˛epnie tworzymy szablon, czyli plik ~/czat/czat/templates/czat/index.html, który zawiera:
1
2
3
4
5
6
7
<!-- czat/czat/templates/czat/index.html -->
<html>
<head></head>
<body>
<h1>Witaj w aplikacji Czat!</h1>
</body>
</html>
W pliku views.py zmieniamy instrukcje odpowiedzi:
1
2
# -*- coding: utf-8 -*# czat/czat/views.py
3
4
5
#from django.http import HttpResponse
from django.shortcuts import render
6
7
8
9
10
def index(request):
"""Strona główna aplikacji."""
#return HttpResponse("Witaj w aplikacji Czat!")
return render(request, 'czat/index.html')
Po zaimportowaniu funkcji render() używamy jej do zwrócenia szablonu. Jako pierwszy argument podajemy
parametr request, a jako drugi nazw˛e szablonu uwzgl˛edniajac
˛ a˛ katalog nadrz˛edny.
Po wpisaniu adresu 127.0.0.1:8000/ zobaczymy tekst, który umieściliśmy w szablonie:
134
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3.6 Rejestrowanie użytkowników
Zamiast zakładać konta użytkownikom w panelu administracyjnym udost˛epnimy im możliwość samodzielnego rejestrowania. Zadanie to można zrealizować na dwa sposoby. Pierwszy polega na “r˛ecznym” utworzeniu formularza i
obsłużeniu przesłanych danych w skojarzonym widoku (funkcji). Przygotujemy wi˛ec widok rejestruj(), który:
1. zwróci formularz przygotowany w szablonie rejestruj.html w odpowiedzi na żadanie
˛
typu GET, wysłane
przez przegladark˛
˛
e po wejściu użytkownika na stron˛e rejestracji pod adres URL /rejestruj;
2. obsłuży żadanie
˛
typu POST, czyli wysłanie danych z formularza na serwer, sprawdzi poprawność przesłanych
danych (nazw˛e użytkownika i hasło) i utworzy konto;
3. zaloguje nowego użytkownika i przekieruje go na stron˛e główna.˛
Zaczynamy od uzupełnienia pliku views.py. Dodajemy widok rejestruj():
7
8
9
10
11
def index(request):
"""Strona główna aplikacji."""
#return HttpResponse("Witaj w aplikacji Czat!")
kontekst = {'user': request.user}
return render(request, 'czat/index.html', kontekst)
12
13
14
15
16
from
from
from
from
django.shortcuts import redirect
django.core.urlresolvers import reverse
django.contrib.auth import authenticate, login, logout
django.contrib import messages
17
18
19
20
def rejestruj(request):
"""Rejestracja nowego użytkownika."""
from django.contrib.auth.forms import UserCreationForm
21
22
23
24
25
26
27
28
29
30
31
32
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Zostałeś zarejestrowany.")
user = authenticate(
username=form.data['username'],
password=form.data['password1'])
login(request, user)
messages.success(request, "Zostałeś zalogowany.")
return redirect(reverse('index'))
33
34
35
kontekst = {'form': UserCreationForm()}
return render(request, 'czat/rejestruj.html', kontekst)
Powyższy kod pokazuje m .in., w jaki sposób przekazać dowolne dane do szablonu. Używamy słownika, w naszym
przypadku nazwanego kontekst, który zostaje użyty jako trzeci argument funkcji render(). W ten sposób
przekazujemy obiekt użytkownika w widoku strony głównej i formularz w widoku rejestracji.
Warto także zauważyć, jak tworzymy komunikaty zwrotne dla użytkownika. Wykorzystujemy wbudowany w
Django system komunikatów: messages.success(request, "Zostałeś zarejestrowany."). Tak
utworzone komunikaty możemy odczytać w każdym szablonie ze zmiennej messages (zob. niżej szablon
index.html).
Tworzymy nowy szablon ~/czat/czat/templates/czat/rejestruj.html:
1
2
3
<!-- czat/czat/templates/czat/rejestruj.html -->
<html>
<body>
5.3. Czat (wersja rozszerzona)
135
Materiały eCG IT Documentation, Wydanie 1
4
5
6
7
8
9
10
11
<h1>Rejestracja użytkownika</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Zarejestruj</button>
</form>
</body>
</html>
Wia˛żemy adres URL rejestruj/ z utworzonym widokiem. Do pliku urls.py dopisujemy:
10
11
12
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^rejestruj/', views.rejestruj, name='rejestruj'),
13
url(r'^admin/', include(admin.site.urls)),
14
15
)
Gdybyśmy już teraz odwiedzili adres 127.0.0.1:8000/rejestruj, powinniśmy zobaczyć poniższy formularz:
Modyfikujemy również szablon strony głównej:
1
2
3
4
5
<!-- czat/czat/templates/czat/index.html -->
<html>
<head></head>
<body>
<h1>Witaj w aplikacji Czat!</h1>
6
{% if messages %}
<ul>
{% for komunikat in messages %}
<li>{{ komunikat|capfirst }}</li>
{% endfor %}
7
8
9
10
11
136
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
12
13
</ul>
{% endif %}
14
15
16
17
18
19
20
21
{% if user.is_authenticated %}
<p>Jesteś zalogowany jako {{ user.username }}.</p>
{% else %}
<p><a href="{% url 'rejestruj' %}">Zarejestruj si˛
e</a></p>
{% endif %}
</body>
</html>
W szablonach dost˛epne sa˛ podstawowe instrukcje sterujace,
˛ takie jak np. {% for %} czy {% if %}. T˛e pierwsza˛ wykorzystamy do wyświetlenia komunikatów użytkownikowi, druga˛ m. in. do sprawdzenia, czy stron˛e odwiedza użytkownik uwierzytelniony. Dane przekazane do szablonu możemy wyświetlać stosujac
˛ odpowiednia˛ notacj˛e, np.: {{ user.username }}. Dodatkowo wyświetlane dane można obrabiać za pomoca˛ filtrów, np. {{
komunikat|capfirst }} – w tym wypadku wszystkie komunikaty zostana˛ wyświetlone z wielkiej litery.
W pliku index.html umieszczamy również link do strony rejestracji, który wyświetlany b˛edzie tylko użytkownikom niezalogowanym. Aby wygenerować adres strony w atrybucie href używamy funkcji url, za która˛ podajemy
w cudzysłowach nazw˛e nadana˛ adresowi w pliku urls.py, np.: {% url ’rejestruj’ %}.
Ćwiczenie 2
Po ewentualnym ponownym uruchomieniu serwera, zarejestruj nowego użytkownika o nazwie “ewa”. Powinieneś
zobaczyć poniższa˛ stron˛e:
W przegladarce
˛
wpisz adres 127.0.0.1:8000/rejestruj, aby przejść do strony rejestracji. Na stronie wyświetla si˛e
formularz, mimo że jesteś już zarejestrowany i zalogowany.
Spróbuj zmienić szablon rejestruj.html, tak aby zalogowanym użytkownikom wyświetlał si˛e tekst “Jesteś już
zarejestrowany” oraz link do strony głównej, a niezalogowanym formularz rejestracji.
Wskazówka: Wykorzystaj tag {% if warunek %} i obiekt user, tak jak zrobiliśmy to w widoku index() i
dopisz odpowiedni kod w widoku rejestruj().
Przykładowy efekt poprawnego wykonania ćwiczenia:
5.3. Czat (wersja rozszerzona)
137
Materiały eCG IT Documentation, Wydanie 1
5.3.7 Logowanie i wylogowywanie
Skoro użytkownicy moga˛ si˛e rejestrować, trzeba umożliwić im również logowanie i wylogowywanie z serwisu. Również to zadanie można zrobić dwojako. Pierwszy sposób to tak jak w przypadku rejestracji stworzenie widoków w
pliku views.py i powiazanie
˛
ich z adresami w pliku urls.py.
Na poczatku
˛
jak zawsze importujemy wymagane funkcje, później dopisujemy widok loguj() i wyloguj() w
pliku views.py:
37
38
39
def loguj(request):
"""Logowanie użytkownika"""
from django.contrib.auth.forms import AuthenticationForm
40
if request.method == 'POST':
form = AuthenticationForm(request, request.POST)
if form.is_valid():
login(request, form.get_user())
messages.success(request, "Zostałeś zalogowany!")
return redirect(reverse('index'))
41
42
43
44
45
46
47
kontekst = {'form': AuthenticationForm()}
return render(request, 'czat/loguj.html', kontekst)
48
49
50
51
52
53
54
55
def wyloguj(request):
"""Wylogowanie użytkownika"""
logout(request)
messages.info(request, "Zostałeś wylogowany!")
return redirect(reverse('index'))
Podobnie jak w przypadku rejestrowania użytkowników, korzystamy z wbudowanego w Django formularza logowania
AuthenticationForm. Dzi˛eki temu nie musimy “r˛ecznie” sprawdzać poprawności podanych danych, robi to
metoda is_valid() formularza. Jeżeli nie zwróci ona bł˛edu, możemy zalogować użytkownika za pomoca˛ funkcji
login(), której przekazujemy obiekty HttpRequest (przesłane żadanie)
˛
i User – obiekt użytkownika zwrócony
przez metod˛e get_user() formularza.
Wylogowanie polega na użyciu funkcji logout(request) – wyloguje ona użytkownika, którego dane zapisane sa˛
w przesłanym żadaniu.
˛
Jak widać, do logowania potrzebujemy szablonu.
Najprościej utworzyć go na podstawie szablonu
rejestruj.html. Otwórzmy go i zapiszmy do pliku ~/czat/czat/templates/czat/loguj.html.
Później wystarczy dostosować wywietlany tekst. Szablon z uwzgl˛ednieniem zmian wprowadzonych w ćwiczeniu
138
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
2. może wygladać
˛
tak:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- czat/czat/templates/czat/loguj.html -->
<html>
<body>
<h1>Logowanie użytkownika</h1>
{% if user.is_authenticated %}
<p>Jesteś już zalogowany jako {{ user.username }}.
<br /><a href="/">Strona główna</a></p>
{% else %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Zaloguj</button>
</form>
{% endif %}
</body>
</html>
Pozostaje skojarzenie odpowiednich adresów URL z utworzonymi widokami. W pliku urls.py dopisujemy reguły:
10
11
12
13
14
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^rejestruj/', views.rejestruj, name='rejestruj'),
url(r'^loguj/', views.loguj, name='loguj'),
url(r'^wyloguj/', views.wyloguj, name='wyloguj'),
15
url(r'^admin/', include(admin.site.urls)),
16
17
)
Możesz przetestować działanie dodanych funkcji wywołujac
˛ w przegladarce
˛
adresy: 127.0.0.1:8000/loguj i
127.0.0.1:8000/wyloguj. Przykładowy formularz wyglada
˛ tak:
Informacja: Podsumujmy: działanie wszystkich omówionych do tej pory widoków jest podobne. Po przejściu pod
adres określony w pliku urls.py, np. 127.0.0.1:8000/loguj/, wywoływany jest powiazany
˛
z nim widok zdefiniowany
w pliku views.py, np. loguj(). Tego typu operacja generuje żadanie
˛
typu GET, w odpowiedzi na które zwracany
jest szablon (np. loguj.html) wyświetlajacy
˛ przekazny do niego formularz (np. AuthenticationForm).
Po wypełnieniu formularza użytkownik wciska odpowiedni przycisk, który inicjuje żadanietypu
˛
POST, a wi˛ec przesyłanie danych na serwer. Widoki rejestruj() i loguj() wychwytuja˛ i przetwarzaja˛ takie żadania,
˛
tj. rejestruja˛
5.3. Czat (wersja rozszerzona)
139
Materiały eCG IT Documentation, Wydanie 1
lub loguja˛ użytkownika. W odpowiedzi użytkownik zostaje przekierowany z odopiwednim komunikatem na ston˛e
główna.˛
Ćwiczenie 3
Adresów logowania i wylogowywania nikt w serwisach nie wpisuje r˛ecznie. Wstaw zatem odpowiednie linki do
szablonu strony głównej. Użytkownik niezalogowany powinien zobaczyć odnośnik Zaloguj, użytkownik zalogowany
– Wyloguj. Przykładowe strony moga˛ wygladać
˛
tak:
5.3.8 Widoki ogólne
Zajmiemy sie teraz drugim sposobem stworzenia formularza rejestracji, logowania i wylogowania. Formularze te
bowiem działaja,˛ ale nie do końca tak jak powinny. Spróbuj zarejestrować dodanego już użytkownika, albo przesłać
niepełny formularz. Zauważysz, że nie dostajemy żadnej informacji o bł˛edach. Można oczywiście dopisać ich obsług˛e
do odpowiednich widoków lub wygenerować je w szablonach, ale... wcale nie trzeba tego robić. W przypadku
prostych aplikacji wystarcza˛ wbudowane w Django widoki ogólne (ang. generic views) i formularze.
140
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Wszystko da si˛e zrobić w pliku urls.py, który zmieniamy nast˛epujaco:
˛
10
11
12
from django.views.generic.edit import CreateView
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.core.urlresolvers import reverse_lazy
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
#url(r'^rejestruj/', views.rejestruj, name='rejestruj'),
#url(r'^loguj/', views.loguj, name='loguj'),
#url(r'^wyloguj/', views.wyloguj, name='wyloguj'),
url(r'^rejestruj/', CreateView.as_view(
template_name='czat/rejestruj.html',
form_class=UserCreationForm,
success_url='/'), name='rejestruj'),
url(r'^loguj/', 'django.contrib.auth.views.login',
{'template_name': 'czat/loguj.html'},
name='loguj'),
url(r'^wyloguj/', 'django.contrib.auth.views.logout',
{'next_page': reverse_lazy('index')},
name='wyloguj'),
29
url(r'^admin/', include(admin.site.urls)),
30
31
)
Na poczatku
˛ importujemy widok przeznaczony do dodawania danych (CreateView), nast˛epnie formularz tworzenia użytkownika (UserCreationForm) i logowania (AuthenticationForm). Do generowania adresów url
potrzebna b˛edzie również funkcja reverse_lazy().
Nast˛epnie zakomentowujemy dotychczasowe powiazania
˛
adresów i widoków. Dodajemy natomiast nowe. Do adresu
/rejestruj przypisujemy wywołanie metody as_view() widoku ogólnego CreateView. Do obsłużenia adresów
/loguj i /wyloguj używamy dedykowanych widoków login i logout.
Na działanie widoków wpływaja˛ przekazywane im w różny sposób ustawienia właściwości, takie jak:
• template_name – szablon, który zostanie użyty do zwrócenia odpowiedzi;
• form_class – formularz, który zostanie przekazany do szablonu;
• success_url – adres, na który nastapi
˛ przekierowanie w przypadku braku bł˛edów (np. po udanej rejestracji);
• next_page – adres strony, na który nastapi
˛ przekierowanie użytkownika po wykonaniu żadanych
˛
akcji (np.
udanym wylogowaniu).
Pozostaje nam jeszcze określić stron˛e, na która˛ powinien zostać przekierowany użytkownik po udanym zalogowaniu.
W tym wypadku na końcu pliku settings.py definujemy wartość zmiennej LOGIN_REDIRECT_URL:
# czat/czat/settings.py
from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('index')
To wszystko. Zauważ, że funkcje rejestruj(), loguj() i wyloguj(), które umieściliśmy wczesniej w pliku
views.py nie sa˛ już potrzebne! Przetestuj teraz działanie formularza rejestracji! Spróbuj dodać zarejestrowanego
już użytkownika, wysłać pusty lub niekompletny formularz.
5.3.9 Obsługa wiadomości
Chcemy, by zalogowani użytkownicy mogli przegladać
˛
wiadomości wszystkich użytkowników, zmieniać, usuwać i
dodawać własne. Najprostszy sposób to skorzystanie z omówionych wyżej ogólnych widoków wbudowanych.
5.3. Czat (wersja rozszerzona)
141
Materiały eCG IT Documentation, Wydanie 1
Informacja: Django oferuje wbudowane widoki ogólne przeznaczone do typowych operacji:
• DetailView i ListView – (ang. generic display view) widoki przeznaczone do prezentowania szczegółów i listy
danych;
• FormView, CreateView, UpdateView i DeleteView – (ang. generic editing views) widoki przeznaczone do
wyświetlania formularzy ogólnych, w szczególności służacych
˛
dodawaniu, uaktualnianiu, usuwaniu obiektów
(danych).
Do wyświetlania listy wiadomości użyjemy klasy ListView. Do pliku urls.py dopisujemy importy:
from django.contrib.auth.decorators import login_required
from django.views.generic.list import ListView, DeleteView
from czat.models import Wiadomosc
– i wia˛żemy adres /wiadomosci z wywołaniem widoku:
url(r'^wiadomosci/', login_required(
ListView.as_view(
model=Wiadomosc,
context_object_name='wiadomosci',
paginate_by=10),
login_url='/loguj'),
name='wiadomosci'),
32
33
34
35
36
37
38
Zakładamy, że wiadomości moga˛ ogladać
˛
tylko użytkownicy zalogowani. Dlatego całe wywołanie widoku umieszczamy w funkcji login_required(). Parametr login_url określa adres, na który przekierowany zostanie
niezalogowany użytkownik.
W wywołaniu ListView.as_view() wykorzystujemy kolejne właściwości modyfikujace
˛ działanie widoków:
• model – podajemy model, którego dane zostana˛ pobrane z bazy;
• context_object_name – pozwala zmienić domyślna˛ nazw˛e (object_list) listy obiektów przekazanych do
szablonu;
• paginate_by– pozwala ustawić ilość ilość obiektów wyświetlanych na stronie.
Potrzebujemy jeszcze szablonu, którego Django szuka pod domyślna˛ nazwa˛ <nazwa modelu>_list.html, czyli w naszym przypadku tworzymy plik ~/czat/czat/templates/czat/wiadomosc_list.html:
1
2
3
4
<!-- czat/czat/templates/czat/wiadomosc_list.html -->
<html>
<body>
<h1>Wiadomości</h1>
5
{% if messages %}
<ul>
{% for komunikat in messages %}
<li>{{ komunikat|capfirst }}</li>
{% endfor %}
</ul>
{% endif %}
6
7
8
9
10
11
12
13
<h2>Lista wiadomości:</h2>
<ol>
{% for wiadomosc in wiadomosci %}
<li>
<strong>{{ wiadomosc.autor.username }}</strong> ({{ wiadomosc.data_pub }}):
<br /> {{ wiadomosc.tekst }}
14
15
16
17
18
19
142
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
20
21
22
</li>
{% endfor %}
</ol>
23
24
25
</body>
</html>
W tym momencie widok wiadomości powinien już działać. Przetestuj!
Ćwiczenie 4
W szablonie listy wiadomości przed znacznikiem zamykajacym
˛
</body> dodaj link do strony głównej. Przykładowy
efekt prezentujemy poniżej (zrzut zawiera również elementy, które dodamy później):
Dodawanie wiadomości zrealizujemy wykorzystujac
˛ widok CreateView. Ponieważ nasz model wiadomości zawiera klucz obcy, mianowicie pole autor, tym razem dostosujemy klas˛e widoku w pliku views.py. Dzi˛eki temu
b˛edziemy mogli rozszerzyć standardowa˛ funkcjonalność widoku.
58
59
60
from django.views.generic.edit import CreateView
from czat.models import Wiadomosc
from django.utils import timezone
61
62
63
64
class UtworzWiadomosc(CreateView):
model = Wiadomosc
fields = ['tekst', 'data_pub']
5.3. Czat (wersja rozszerzona)
143
Materiały eCG IT Documentation, Wydanie 1
context_object_name = 'wiadomosci'
success_url = '/wiadomosc'
65
66
67
def get_initial(self):
initial = super(UtworzWiadomosc, self).get_initial()
initial['data_pub'] = timezone.now()
return initial
68
69
70
71
72
def get_context_data(self, **kwargs):
kwargs['wiadomosci'] = Wiadomosc.objects.filter(
autor=self.request.user)
return super(UtworzWiadomosc, self).get_context_data(**kwargs)
73
74
75
76
77
def form_valid(self, form):
wiadomosc = form.save(commit=False)
wiadomosc.autor = self.request.user
wiadomosc.save()
return super(UtworzWiadomosc, self).form_valid(form)
78
79
80
81
82
Dostosowujac
˛ widok ogólny tworzymy oparta˛ na nim klas˛e UtworzWiadomosc. Z nieomówionych dotad
˛ ustawień widoku widzimy właściwość fields – pozwala ona określić w postaci listy pola, które maja˛ znaleźć si˛e na
formularzu. Jak widać, pomijamy pole autor.
Właśnie dlatego musimy nadpisać metod˛e form_valid(), która sprawdza poprawność przesłanych danych i zapisuje je w bazie. Żadanie
˛
POST otrzymane od użytkownika nie b˛edzie zawierało danych autora. Musimy je uzupełnić.
Polecenie wiadomosc = form.save(commit=False) tworzy obiekt wiadomości, ale go nie zapisuje. Dzi˛eki
temu w nast˛epnych instrukcjach możemy uzupełnić dane autora, po czym jeszcze raz zapisujemy wiadomość, tym
razem w bazie.
Metoda get_initail() pozwala ustawić domyślne wartości dla wybranych pól. Wykorzystujemy ja˛ do zainicjowania pola data_pub aktualna data.˛
Metoda get_context_data() z punktu widzenia dodawania wiadomości nie jest potrzebna, ale używamy jej
po to, aby na jednej stronie obok formularza dodawania wiadomości wyświetlić ich list˛e. Inicjujemy ja˛ poleceniem Wiadomosc.objects.filter(autor=self.request.user) wybierajacym
˛
wiadomości utworzone
przez zalogowanego użytkownika.
Ćwiczenie 5
Podobnie jak wyżej potrzebujemy szablonu, który dla widoków dodawania domyślnie nazywaja˛ si˛e <nazwa modelu>_form. Na podstawie szablonu wiadomosc_list.html utwórz szablon wiadomosc_form.html>.
Przed lista˛ wiadomości umieść kod wyświetlajacy
˛ formularz:
<h2>Dodaj wiadomość</h2>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Zapisz</button>
</form>
14
15
16
17
18
19
Dodamy teraz dwa widoki przeznaczone do aktualizaowania i usuwania wpisów. Zakładamy, że adresy do tych operacji b˛eda˛ miały postać: /aktualizuj/id_wiadomości oraz /usun/id_wiadomości, gdzie id_wiadomosci jest identyfikatorem
obiektu do usuni˛ecia. Tym razem zaczniemy od zmian w pliku urls.py:
url(r'^aktualizuj/(?P<pk>\d+)/', login_required(
views.AktualizujWiadomosc.as_view(),
login_url='/loguj'), name='aktualizuj'),
url(r'^usun/(?P<pk>\d+)/', login_required(
42
43
44
45
144
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3. Czat (wersja rozszerzona)
145
Materiały eCG IT Documentation, Wydanie 1
DeleteView.as_view(
model=Wiadomosc,
template_name='czat/wiadomosc_usun.html',
success_url='/wiadomosci'),
login_url='/loguj'), name='usun'),
46
47
48
49
50
Nowościa˛ w powyższym kodzie sa˛ wyrażenia regularne definiujace
˛ adresy z dodatkowym parametrem, np.
r’^aktualizuj/(?P<pk>\d+)/’. Cz˛eść /(?P<pk>\d+) oznacza, że oczekujemy liczby dziesi˛etnej, która
zostanie zapisana do zmiennej o nazwie pk – nazwa jest tu skrótem od ang. wyrażenia primary key, co znaczy “klucz
główny”. Zmienna ta oznaczać b˛edzie identyfikator wiadomości i dost˛epna b˛edzie w widokach.
Usuwanie danych realizujemy za pomoca˛ widoku DeleteView, który powinien być już zaimportowany razem z
widokiem ListView. Domyślny szablon dla tego widoku przyjmuje nnazw˛e <nazwa-modelu>_confir_delete.html,
dlatego uproścliśmy jego nazw˛e we właściwości template_name.
Ćwiczenie 6
Utwórz szablon wiadomosc_usun.html wzorujac
˛ sie na wcześniejszych szablonach. Zamiast instrukcji wyświetlajacej
˛ formularz umieść kod:
<p>Czy na pewno chcesz usunać
˛ wiadomość:<br />"{{ object }}"?</p>
17
Nieco wi˛ecej pracy wymaga dostosowanie widoku aktualizacji.
AktualizujWiadomosc oparta˛ na widoku ogólnym UpdateView:
85
W pliku views.py utworzymy klas˛e
from django.views.generic.edit import UpdateView
86
87
88
89
class AktualizujWiadomosc(UpdateView):
model = Wiadomosc
from czat.forms import AktualizujWiadomoscForm
146
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
90
91
92
93
form_class = AktualizujWiadomoscForm
context_object_name = 'wiadomosci'
template_name = 'czat/wiadomosc_form.html'
success_url = '/wiadomosci'
94
95
96
97
98
def get_context_data(self, **kwargs):
kwargs['wiadomosci'] = Wiadomosc.objects.filter(
autor=self.request.user)
return super(AktualizujWiadomosc, self).get_context_data(**kwargs)
99
100
101
102
def get_object(self, queryset=None):
wiadomosc = Wiadomosc.objects.get(id=self.kwargs['pk'])
return wiadomosc
Formularz generowany przez Django dla danego widoku można dostosować. Odpowiada za to właściwość
form_class, której przypisujemy utworzona˛ w nowym pliku forms.py klas˛e modyfikujac
˛ a˛ domyślne ustawienia:
1
# -*- coding: utf-8 -*-
2
3
4
from django.forms import ModelForm, TextInput
from czat.models import Wiadomosc
5
6
7
8
9
10
11
class AktualizujWiadomoscForm(ModelForm):
class Meta:
model = Wiadomosc
fields = ['tekst', 'data_pub']
exclude = ['autor']
widgets = {'tekst': TextInput(attrs={'size': 80})}
Klasa AktualizujWiadomoscForm oparta jest na wbudowanej klasie ModelForm. Właściwości podklasy
Meta pozwalaja˛ określić cechy formularza wyświetlanego przez widok, który go wykorzystuje:
• model – oznacza to samo co w widokach, czyli model, dla którego tworzony jest formularz;
• fields – to samo co w widokach, lista pól do wyświetlenia;
• exclude – opcjonalnie lista pól do pomini˛ecia;
• widgets – słownik, którego klucze oznaczaja˛ pola danych, a ich wartości odpowiadajace
˛ im w formularza
HTML typy pól i ich właściwości, np. rozmiar.
Na wyjaśnienie zasługuje jeszcze metoda get_object() widoku aktualizacji. Jej zadanie to wybranie z bazy
danych i zwrócenie do formularza wiadomości, której identyfikator został przekazany w adresie pod nazwa˛ pk:
wiadomosc = Wiadomosc.objects.get(id=self.kwargs[’pk’]).
Ćwiczenie 7
Żeby przetestować aktualizowanie i usuwanie wiadomości, w szablonie wiadomosc_list.html wygeneruj linki
Edytuj i Usuń tylko dla wiadomości utworzonych przez zalogowanego użytkownika.
Wstaw w odpowiednie miejsce szablonu poniższy kod:
20
21
22
23
{% if wiadomosc.autor.username == user.username %}
<a href="{% url 'aktualizuj' wiadomosc.id %}">Edytuj</a> &bull;
<a href="{% url 'usun' wiadomosc.id %}">Usuń</a>
{% endif %}
Dodaj również te same linki do listy wiadomości na stronach dodawania i aktualizowania.
5.3. Czat (wersja rozszerzona)
147
Materiały eCG IT Documentation, Wydanie 1
148
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3.10 Wiadomości jeszcze raz
Dodawanie wiadomości można zrealizować bez wbudowanych widoków ogólnych. Potrzebować b˛edziemy widoku o
nazwie np. wiadomosci() do wyświetlania (żadania
˛
GET) i dodawania wiadomości (żadania
˛
POST), który zwracał
b˛edzie szablon np. wiadomosci.html. Widok ten powia˛żemy z adresem /wiadomosci. Do pliku views.py
dodajemy importy i kod funkcji:
105
from django.contrib.auth.decorators import login_required
106
107
108
109
@login_required(login_url='/loguj')
def wiadomosci(request):
"""Dodawanie i wyświetlanie wiadomości"""
110
111
112
113
114
115
116
117
118
119
120
121
if request.method == 'POST':
tekst = request.POST.get('tekst', '')
if not 0 < len(tekst) <= 250:
messages.error(request,
"Wiadomość nie może być pusta, może mieć maks. 250 znaków!")
else:
wiadomosc = Wiadomosc(tekst=tekst,
data_pub=timezone.now(),
autor=request.user)
wiadomosc.save()
return redirect(reverse('wiadomosci'))
122
123
124
125
wiadomosci = Wiadomosc.objects.all()
kontekst = {'user': request.user, 'wiadomosci': wiadomosci}
return render(request, 'czat/wiadomosci.html', kontekst)
Widać powyżej, że treść przesłanej wiadomości wydobywamy ze słownika request.POST za pomoca˛ metody
get(’tekst’, ’’). Jej pierwszy argument odpowiada nazwie pola formularza użytej w szablonie, które chcemy
odczytać. Drugi argument oznacza wartość domyślna,˛ przydatna,˛ jeśli pole b˛edzie niedost˛epne. Po sprawdzeniu długości wiadomości, możemy ja˛ utworzyć wykorzystujac
˛ konstruktor naszego modelu Wiadomosc(tekst=tekst,
data_pub=timezone.now(), autor=request.user). W formie nazwanych argumentów podajemy mu
wartości kolejnych pól. Zapisanie nowej wiadomości w bazie sprowadza si˛e do polecenia wiadomosc.save().
Na koniec przekierowujemy użytkownika do tego samego widoku, ale tym razem jest to żadanie
˛
typu GET. W odpowiedzi na nie pobieramy wszystkie wiadomości z bazy (Wiadomosc.objects.all()), i przekazujemy do
szablonu, który zwracamy użytkownikowi.
Zadaniem szablonu zapisanego w pliku ~/czat/czat/templates/wiadomosci.html jest wyświetlenie komunikatów zwrotnych, formularza dodawania wiadomości i listy wiadomości dodanych.
1
2
3
4
<!-- czat/czat/templates/czat/wiadomosci.html -->
<html>
<body>
<h1>Wiadomości</h1>
5
6
7
8
9
10
11
12
{% if messages %}
<ul>
{% for komunikat in messages %}
<li>{{ komunikat|capfirst }}</li>
{% endfor %}
</ul>
{% endif %}
13
14
15
16
<h2>Dodaj wiadomość</h2>
<form method="POST">
{% csrf_token %}
5.3. Czat (wersja rozszerzona)
149
Materiały eCG IT Documentation, Wydanie 1
<input type="text" name="tekst" />
<button type="submit">Zapisz</button>
</form>
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<h2>Lista wiadomości:</h2>
<ol>
{% for wiadomosc in wiadomosci %}
<li>
<strong>{{ wiadomosc.autor.username }}</strong> ({{ wiadomosc.data_pub }}):
<br /> {{ wiadomosc.tekst }}
</li>
{% endfor %}
</ol>
</body>
</html>
Ćwiczenie 8
Powia˛ż widok wiadomosci() z adresem /wiadomosci w pliku urls.py, nadajac
˛ mu nazw˛e wiadomosci, a nast˛epnie uzupełnij szablon widoku głównego, aby zalogowanym użytkownikom wyświetlał si˛e link prowadzacy
˛ do strony
z wiadomościami. W szablonie wiadomosci.html dodaj link do strony głównej i link wylogowania.
Wskazówka: Definicje w pliku urls.py sprawdzane sa˛ po kolei, zwracany jest widok przypisany pierwszemu napotaknemu dopasowaniu adresu. Jeżeli chcemy przetestować działanie widoku wiadomosci() dla wykorzystanego
już adresu /wiadomosci przypisanego wbudowanemu widokowi ListView, powiazanie
˛
należy umieścić przed nim, np.
na poczatku.
˛
Zaloguj si˛e i przetestuj wyświetlanie 6 i dodawanie wiadomości pod adresem 127.0.0.1:8000/wiadomosci/. Sprawdź,
co si˛e stanie po wysłaniu pustej wiadomości.
Poniższe zrzuty prezentuja˛ efekty naszej pracy:
5.3.11 Szablony
Zapewne zauważyłeś, że wi˛ekszość kodu w szablonach, a zatem i w stronach HTML, które z nich powstaja,˛ si˛e
powtarza, albo jest bardzo podobna. Biorac
˛ pod uwag˛e schematyczna˛ budow˛e stron WWW jest to nieuniknione.
Django dysponuje wbudowanym silnikiem szablonów, który ułatwia ich tworzenie.
Szablony, jak można było zauważyć, składaja˛ si˛e ze zmiennych i tagów. Zmienne, które ujmowane sa˛ w podwójne
nawiasy sześciokatne
˛ {{ zmienna }}, zast˛epowane sa˛ konkretnymi wartościami. Tagi z kolei, oznaczane notacja˛
{% tag %} tworza˛ mini-j˛ezyk szablonów i pozwalaja˛ kontrolować logik˛e budowania treści. Najważniejsze tagi, {%
if warunek %}, {% for wyrażenie %}, {% url nazwa %} – już stosowaliśmy.
Spróbujmy uprościć i ujednolicić nasze szablony. Zacznijmy od szablonu bazowego, który umieścimy w pliku
~/czat/czat/templates/czat/baza.html:
1
2
3
4
5
6
7
8
<!-- czat/czat/templates/czat/baza.html -->
<!DOCTYPE html>
<html lang="pl">
<meta charset="utf-8" />
<head>
<title>{% block tytul %} System wiadomości Czat {% endblock tytul %}</title>
</head>
<body>
6
Jeżeli nie dodałeś do tej pory żadnej wiadomości, lista na poczatku
˛ b˛edzie pusta.
150
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
5.3. Czat (wersja rozszerzona)
151
Materiały eCG IT Documentation, Wydanie 1
<h1>{% block naglowek %} Witaj w aplikacji Czat! {% endblock %}</h1>
9
10
{% block komunikaty %}
{% if messages %}
<ul>
{% for komunikat in messages %}
<li>{{ komunikat|capfirst }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
11
12
13
14
15
16
17
18
19
20
{% block tresc %} {% endblock %}
21
22
{% if user.is_authenticated %}
{% block linkilog %} {% endblock %}
<p><a href="{% url 'wyloguj' %}">Wyloguj si˛
e</a></p>
{% else %}
{% block linkizalog %} {% endblock %}
{% endif %}
23
24
25
26
27
28
29
30
31
32
{% block linki %} {% endblock %}
</body>
</html>
Jest to zwykły tekstowy dokument, zawierajacy
˛ schemat strony utworzony z wymaganych znaczników HTML oraz
bloki zdefiniowane za pomoca˛ tagów mini-j˛ezyka szablonów. W pliku tym umieszczamy stała˛ i wspólna˛ struktur˛e
stron w serwisie (np. nagłówek, menu, sekcja treści, stopka itp.) oraz wydzielamy bloki, których treść b˛edzie można
zmieniać w szablonach konkretnych stron.
Wykorzystujac
˛ szablon podstawowy, zmieniamy stron˛e główna,˛ czyli plik index.html:
1
2
<!-- czat/czat/templates/czat/index.html -->
{% extends "czat/baza.html" %}
3
{% block naglowek %}Witaj w aplikacji Czat!{% endblock %}
4
5
{% block linkilog %}
<p>Jesteś zalogowany jako {{ user.username }}.</p>
<p><a href="{% url 'wiadomosc' %}">Dodaj wiadomość</a></p>
<p><a href="{% url 'wiadomosci' %}">Lista wiadomości</a></p>
{% endblock %}
6
7
8
9
10
11
{% block linkizalog %}
<p><a href="{% url 'loguj' %}">Zaloguj si˛
e</a></p>
<p><a href="{% url 'rejestruj' %}">Zarejestruj si˛
e</a></p>
{% endblock %}
12
13
14
15
Jak widać, szablon dziedziczy z szablonu bazowego. Odpowiada za to tag {% extends plik_bazowy %}.
Dalej pomijamy strukturalne znaczniki HTML zdefiniowane w bazie, zast˛epujemy natomiast zawartość bloków, które
uznajemy za potrzebne na danej stronie.
Post˛epujac
˛ na tej samej zasadzie modyfikujemy szablon rejestracji:
1
2
<!-- czat/czat/templates/czat/rejestruj.html -->
{% extends "czat/baza.html" %}
3
{% block naglowek %}Rejestracja użytkownika{% endblock %}
4
5
152
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
6
7
8
9
10
11
12
13
14
{% block tresc %}
{% if not user.is_authenticated %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Zarejestruj</button>
</form>
{% endif %}
{% endblock %}
15
16
17
18
{% block linkilog %}
<p>Jesteś już zarejestrowany jako {{ user.username }}.</p>
{% endblock %}
19
20
21
22
{% block linki %}
<p><a href="{% url 'index' %}">Strona główna</a></p>
{% endblock %}
Ćwiczenie 9
Wzorujac
˛ si˛e na podanych przykładach zmień pozostałe szablony tak, aby opierały si˛e na szablonnie bazowym. Wyglad
˛ stron nie powinien ulec zmianie!
5.3.12 Style, skrpyty, pliki
Nasze szablony zyskały na zwi˛ezłości i przejrzystości, ale nadal pozbawione sa˛ elementarnych dla dzisiejszych stron
WWW zasobów, takich jak style CSS, skrypty JavaScript czy zwykłe obrazki. Jak je dołaczyć?
˛
Przede wszystkim potrzebujemy osobnego katalogu ~czat/czat/static/czat. W terminalu w katalogu projektu (!) wydajemy polecenie:
~/czat $ mkdir -p czat/static/czat
W powyższym katalogu tworzy si˛e zazwyczaj podkatalogi dla różnych typów zasobów, np.
css, js czy img.
Sugerujemy, żeby je utworzyć.
Tworzymy również przykładowy plik
~/czat/czat/static/czat/css/style.css:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
body {
margin: 1em;
padding: 0;
font-family: Helvetica, Arial, sans-serif;
font-size: 12pt;
background: lightgreen url('../img/django.png') no-repeat fixed top right;
}
a { text-decoration: none; }
a:hover { text-decoration: underline; }
a:visited { text-decoration: none; }
.clearfix {
clear: both;
}
h1 { font-size: 1.8em; font-weight: bold; margin-top: 20px;}
h2 { font-size: 1.4em; font-weight: bold; margin-top: 20px;}
p { font-szie: 1em; font-family: Arial, sans-serif; }
.fr { float: right; }
5.3. Czat (wersja rozszerzona)
153
Materiały eCG IT Documentation, Wydanie 1
Do podkatalogu ~/czat/czat/static/czat/img wrzucamy obrazki z podanego archiwum. Wreszcie zmieniamy szablon podstawowy:
1
{% load staticfiles %}<!DOCTYPE html>
2
<link rel="stylesheet" type="text/css" href="{% static 'czat/css/style.css' %}" />
3
4
<div id="obrazki">
<img src="{% static 'czat/img/python.png' %}" width="300" />
<img src="{% static 'czat/img/sqlite.png' %}" width="300" />
</div>
5
6
7
8
Kod z linii 1. {% load staticfiles %} umieszczamy na samym poczatku
˛ dokumentu. Konfiguruje on ścieżk˛e
do zasobów. Kod z linii 3. wklejamy za znacznikiem <title> w sekcji <head>. Ilustruje on, jak dołaczamy
˛
style czy skrypty, mianowicie używamy tagu {% static plik %}. Wreszcie kod z linii 5-8 zawierajacy
˛ znacznik <div> z obrazkami wstawiamy na końcu pliku przed znacznikiem zamykajacym
˛
</body>. Widzimy tu, jak
wstawiać obrazki. Wyglad
˛ strony głównej po zmianach:
Ćwiczenie 10
W szablonie bazowym stwórz osobny block umożliwiajacy
˛ zast˛epowanie wstawionych obrazków. Zmień dowolny
szablon inny niż strona główna tak, aby wyświetlał inne obrazki. Pami˛etaj o zapisaniu dodatkowych obrazków do
odpowiedniego katalogu!
Wskazówka: Tag {% load staticfiles %} musisz wstawić do każdego szablonu (w dowolnym miejscu), w
którym chcesz odwoływać si˛e do plików z katalogu static.
154
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Na powyższym zrzucie widać wykonane ćwiczenie, czyli użycie dodatkowych obrazków. Jednak strona nie wyglada
˛
dobrze, ponieważ treść podpowiedzi nachodzi na logo Django (oczywiście przy małym rozmiarze okna przegladarki).
˛
Spróbujemy temu zaradzić.
Wykorzystamy prosty skrypt JQuery. Na poczatku
˛ ściagnij
˛
bibliotek˛e i skrypt z podanego archiwum. Rozpakuj pliki
do katalogu static/js. Nast˛epnie do szablonu podstawowego baza.html dodaj przed tagiem zamykajacym
˛
</body> kod:
<script src="{% static 'czat/js/jquery.js' %}"></script>
<script src="{% static 'czat/js/czat.js' %}"></script>
1
2
Po odświeżeniu strony powinnieneś zobaczyć poprawiona˛ stron˛e:
cdn.
5.3.13 Materiały
Słownik
aplikacja program komputerowy.
5.3. Czat (wersja rozszerzona)
155
Materiały eCG IT Documentation, Wydanie 1
156
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
framework zestaw komponentów i bibliotek wykorzystywany do budowy aplikacji, przykładem jest biblioteka Pythona Flask.
HTML j˛ezyk znaczników wykorzystywany do formatowania dokumentów, zwłaszcza stron WWW.
CSS j˛ezyk służacy
˛ do opisu formy prezentacji stron WWW.
HTTP protokół przesyłania dokumentów WWW.
GET typ żadania
˛
HTTP, służacy
˛ do pobierania zasobów z serwera WWW.
POST typ żadania
˛
HTTP, służacy
˛ do umieszczania zasobów na serwerze WWW.
logowanie proces autoryzacji i uwierzytelniania użytkownika w systemie.
ORM mapowanie obiektowo-relacyjne, oprogramowanie służace
˛ do przekształcania struktur bazy danych na obiekty
klasy danego j˛ezyka oprogramowania.
serwer deweloperski (testowy) serwer www używany w czasie prac nad oprogramowaniem.
serwer WWW serwer obsługujacy
˛ protokół HTTP.
baza danych program przeznaczony do przechowywania i przetwarzania danych.
szablon wzorzec (nazywany czasem templatka)
˛ strony WWW wykorzystywany do renderowania widoków.
URL ustandaryzowany format adresowania zasobów w internecie (przykład).
model schematy i źródła danych aplikacji.
widok we Flasku lub Django jest to funkcja, która obsługuje żadania
˛
wysyłane przez użytkownika i na ich podstawie
przygotowuje dane zwracane do przegladarki,
˛
najcz˛eściej w formie strony WWW.
kontroler logika aplikacji, w Django zawarta w funkcji obsługujacej
˛ widok.
1. O Django http://pl.wikipedia.org/wiki/Django_(informatyka)
2. Strona projektu Django https://www.djangoproject.com/
3. Co to jest framework? http://pl.wikipedia.org/wiki/Framework
4. Co nieco o HTTP i żadaniach
˛
GET i POST http://pl.wikipedia.org/wiki/Http
Źródła
• czat_pr.zip
Metryka
Autor Robert Bednarz
Utworzony 2015-07-18 o 04:24
5.4 Pythonizmy
5.4. Pythonizmy
157
Materiały eCG IT Documentation, Wydanie 1
•
•
•
•
•
•
•
•
Operatory * i **
P˛etle
Iteratory
Generatory wyrażeń
Wyrażenia listowe
Generatory
Pliki
Materiały
Python jest j˛ezykiem wydajnym i zwartym dzi˛eki wbudowanym mechanizmom ułatwiajacym
˛
wykonywanie typowych i cz˛estych zadań programistycznych. Podane niżej przykłady należy przećwiczyć w konsoli Pythona, która˛
uruchamiamy poleceniem w terminalu:
~$ python
5.4.1 Operatory * i **
Operator * służy rozpakowaniu listy zawierajacej
˛ wiele argumentów, które chcemy przekazać do funkcji:
1
2
3
# wygeneruj liczby parzyste od 2 do 10
lista = [2,11,2]
range(*lista)
Operator ** potrafi z kolei rozpakować słownik, dostarczajac
˛ funkcji nazwanych argumentów (ang. keyword argument):
1
2
def kalendarz(data, wydarzenie):
print "Data:", data,"\nWydarzenie:", wydarzenie
3
4
5
slownik = {"data" : "10.02.2015", "wydarzenie" : "szkolenie"}
kalendarz(**slownik)
5.4.2 P˛etle
P˛etla to podstawowa konstrukcja wykorzystywana w j˛ezykach programowania. Python oferuje różne sposoby powtarzania wykonywania określonych operacji, niekiedy wygodniejsze lub zwi˛eźlejsze niż p˛etle. Sa˛ to przede wszystkim
generatory wyrażeń i wyrażenia listowe, a także funkcje map() i filter().
1
2
3
kwadraty = []
for x in range(10):
kwadraty.append(x**2)
5.4.3 Iteratory
Obiekty, z których p˛etle odczytuja˛ kolejne dane to iteratory (ang. iterators) Reprezentuja˛ one strumień danych, z
którego zwracaja˛ tylko jedna˛ kolejna˛ wartość na raz za pomoca˛ metody __next()__. Jeżeli w strumieniu nie ma
wi˛ecej danych, wywoływany jest wyjatek
˛ StopIteration.
Wbudowana funkcja iter() zwraca iterator utworzony z dowolnego iterowalnego obiektu. Iteratory wykorzystujemy do przegladania
˛
list, tupli, słowników czy plików używajac
˛ instrukcji for x in y, w której y jest obiektem
iterowalnym równoważnym wyrażeniu iter(y). Np.:
158
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
1
2
3
lista = [2, 4, 6]
for x in lista:
print x
4
5
6
7
slownik = {'Adam':1, 'Bogdan':2 , 'Cezary':3}
for x in slownik:
print(x, slownik(x))
List˛e (czyli obiekt iterowalny), zawierajac
˛ a˛ tuple (klucz, wartość) można wykorzystać do utworzenia słownika, np.:
1
2
lista = [('Polska','Warszawa'), ('Berlin','Niemcy'), ('Francja','Paryż')]
dict(lista)
5.4.4 Generatory wyrażeń
Jeżeli chcemy wykonać jakaś
˛ operacj˛e na każdym elemencie sekwencji lub wybrać podzespół elementów spełniajacy
˛
określone warunki, stosujemy generatory wyrażeń (ang. generator expressions), które zwracaja˛ iteratory. Poniższy
przykład wydrukuje wszystkie imiona z dużej litery:
1
2
3
4
wyrazy = ['anna', 'ala', 'ela', 'wiola', 'ola']
imiona = (imie.capitalize() for imie in wyrazy)
for imie in imiona:
print imie
Schemat składniowy generatora jest nast˛epujacy:
˛ ( wyrażenie for wyr in sekwencja if warunek )
– przy czym:
• wyrażenie – powinno zawierać zmienna˛ z p˛etli for
• if warunek – klauzula ta jest opcjonalna i działa jak filtr eliminujacy
˛ wartości nie spełniajace
˛ warunku
Gdybyśmy chcieli wybrać tylko imiona 3-literowe w wyrażeniu, użyjemy wspomnianej opcjonalnej klauzuli if
warunek:
1
imiona = (imie.capitalize() for imie in wyrazy if len(imie) == 3)
Omawiane wyrażenia można zagnieżdzać. Przykłady podajemy niżej.
5.4.5 Wyrażenia listowe
Jeżeli nawiasy okragłe
˛ w generatorze wyrażeń zamienimy na kwadratowe dostaniemy wyrażenie listowe (ang. list
comprehensions), które – jak wskazuje nazwa – zwraca list˛e:
1
2
# wszystkie poniższe wyrażenia listowe możemy przypisać do zmiennych,
# aby móc później korzystać z utworzonych list
3
4
5
# lista kwadratów liczb od 0 do 9
[x**2 for x in range(10)]
6
7
8
9
# lista dwuwymiarowa [20,40] o wartościach a
a = int(raw_input("Podaj liczb˛
e całkowtia:
˛ "))
[[a for y in xrange(20)] for x in xrange(40)]
10
11
12
# lista krotek (x, y), przy czym x != y
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
13
14
# utworzenie listy 3-literowych imion i ich pierwszych liter
5.4. Pythonizmy
159
Materiały eCG IT Documentation, Wydanie 1
15
16
wyrazy = ['anna', 'ala', 'ela', 'wiola', 'ola']
[ [imie, imie[0]] for imie in wyrazy if len(imie) == 3 ]
17
18
19
20
# zagnieżdzone wyrażenie listowe tworzace
˛
list˛
e współrz˛
ednych
# opisujacych
˛
tabel˛
e
[ (x,y) for x in range(5) for y in range(3) ]
21
22
23
24
# zagnieżdzone wyrażenie listowe wykorzystujace
˛
filtrowanie danych
# lista kwadratów z zakresu {5;50}
[ y for y in [ x**2 for x in range(10) ] if y > 5 and y < 50 ]
Wyrażenia listowe w elegancki i wydajny sposób zast˛epuja˛ takie rozwiazania,
˛
jak:
• p˛etla
• mapowanie funkcji
• wyrażenia lambda
• filtrowanie danych
Mapowanie funkcji
Funkcja map() funkcj˛e podana˛ jako pierwszy argument stosuje do każdego elementu sekwencji podanej jako argument drugi:
1
2
def kwadrat(x):
return x**2
3
4
kwadraty = map(kwadrat, range(10))
Wyrażenia lambda
Słowo kluczowe lambda pozwala utworzyć zwi˛ezły odpowiednik prostej, jednowyrażeniowej funkcji. Poniższy
przykład należy rozumieć nast˛epujaco:
˛ do każdej liczby wygenerowanej przez funkcj˛e range() zastosuj funkcj˛e w
postaci wyrażenia lambda podnoszac
˛ a˛ wartość do kwadratu, a uzyskane wartości zapisz w liście kwadraty.
1
kwadraty = map(lambda x: x**2, range(10))
Funkcje lambda cz˛esto stosowane sa˛ w poleceniach sortowania jako wyrażenie zwracajace
˛ klucz (wartość), wg którego
maja˛ zostać posortowane elementy. Jeżeli np. mamy list˛e tupli opisujac
˛ a˛ uczniów:
1
2
3
4
5
6
uczniowie = [
('jan','Nowak','1A',15),
('ola','Kujawiak','3B',17),
('andrzej','bilski','2F',16),
('kamil','czuja','1B',14)
]
– wywołanie sorted(uczniowie) zwróci nam list˛e posortowana˛ wg pierwszego elementu każdej tupli, czyli
imienia. Jeżeli jednak chcemy sortować wg np. klasy, użyjemy parametru key, który przyjmuje jednoargumentowa˛
funkcj˛e zwracajac
˛ a˛ odpowiedni klucz do sortowania, np.: sorted(uczniowie, key=lambda x: x[2]).
W funkcjach min(), max() podobnie używamy wyrażeń lambda jako argumentu parametru key, aby wskazać
wartości, dla których wyszukujemy minimum i maksimum, np.: max(uczniowie, key=lambda x: x[3])
– zwróci najstarszego ucznia.
160
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
Filtrowanie danych
Funkcja filter() jako pierwszy argument pobiera funkcj˛e zwracajac
˛ a˛ True lub False, stosuje ja˛ do każdego
elementu sekwencji podanej jako argument drugi i zwraca tylko te, które spełniaja˛ założony warunek:
1
2
wyrazy = ['anna', 'ala', 'ela', 'wiola', 'ola']
imiona = filter(lambda imie: len(imie) == 3, wyrazy)
5.4.6 Generatory
Generatory (ang. generators) to funkcje ułatwiajace
˛ tworzenie iteratorów. Od zwykłych funkcji różnia˛ si˛e tym, że:
• zwracaja˛ iterator za pomoca˛ słowa kluczowego yield,
• zapami˛etuja˛ swój stan z momentu ostatniego wywołania, sa˛ wi˛ec wznawialne (ang. resumable),
• zwracaja˛ nast˛epna˛ wartość ze strumienia danych podczas kolejnych wywołań metody next().
Najprostszy przykład generatora zwracajacego
˛
kolejne liczby parzyste:
def gen_parzyste(N):
for i in range(N):
if i % 2 == 0
yield i
gen = gen_parzyste(10)
gen.next()
gen.next()
...
5.4.7 Pliki
Przećwicz alternatywne sposoby otwierania plików:
1
2
3
4
f = open('test.txt', 'r')
for line in f:
print line[0]
f.close()
5
6
7
8
with open("text.txt", "r") as txt:
for line in txt:
print line
9
10
11
for line in open('test.txt', 'r'):
print line[0]
5.4.8 Materiały
1. http://pl.wikibooks.org/wiki/Zanurkuj_w_Pythonie
2. http://brain.fuw.edu.pl/edu/TI:Programowanie_z_Pythonem
3. http://pl.python.org/docs/tut/
4. http://en.wikibooks.org/wiki/Python_Programming/Input_and_Output
5. https://wiki.python.org/moin/HandlingExceptions
5.4. Pythonizmy
161
Materiały eCG IT Documentation, Wydanie 1
6. http://learnpython.org/pl
7. http://www.checkio.org
8. http://www.codecademy.com
9. https://www.coursera.org
5.5 Słownik Pythona
j˛ezyk interpretowany j˛ezyk, który jest tłumaczony i wykonywany “w locie”, np. Python lub PHP. Tłumaczeniem i
wykonywaniem programu zajmuje si˛e specjalny program nazwany interpreterem j˛ezyka.
interpreter program, który analizuje kod źródłowy, a nast˛epnie go wykonuje. Interpretery sa˛ podstawowym składnikiem j˛ezyków wykorzystywanych do pisania skryptów wykonywanych po stronie klienta WWW (JavaScript)
lub serwera (np. Python, PHP).
Interpreter Pythona jest interaktywny, tzn. można w nim wydawać polecenia i obserwować ich działanie, co
pozwala wygodnie uczyć si˛e i testować oprogramowanie. Uruchamiany jest w terminalu, zazwyczaj za pomoca˛
polecenia python.
formatowanie kodu Python wymaga formatowania kodu za pomoca˛ wci˛eć, podstawowym wymogiem jest stosowanie takich samych wci˛eć w obr˛ebie pliku, np. 4 spacji i ich wielokrotności. Wci˛ecia odpowiadaja˛ nawiasom
w innych j˛ezykach, służa˛ grupowaniu instrukcji i wydzielaniu bloków kodu. Bł˛edy wci˛eć zgłaszane sa˛ jako
wyjatki
˛ IndentationError.
zmienna nazwa określajaca
˛ jakaś
˛ zapami˛etywana˛ i wykorzystywana˛ w programie wartość lub struktur˛e danych.
Zmienna może przechowywać pojedyncze wartości określonego typu, np.: imie = "Anna", jak i rozbudowane struktury danych, np.: imiona = (’Ala’, ’Ola’, ’Ela’). W nazwach zmiennych nie używamy
znaków narodowych, nie rozpoczynamy ich od cyfr.
typy danych Wszystkie dane w Pythonie sa˛ obiektami i jako takie przynależa˛ do określonego typu, który determinuje możliwe na nich operacje. W pewnym uproszczeniu podstawowe typy danych to: string – napis (łańcuch
znaków), podtyp sekwencji; integer – dodatnie i ujemne liczby całkowite; float – liczba zmiennoprzecinkowa
(separatorem jest kropka); boolean – wartość logiczna True (prawda, 1) lub False (fałsz, 0), podtyp typu całkowitego.
operatory Arytmetyczne: +, -, *, /, //, %, ** (pot˛egowanie); znak + znak (konkatenacja napisów); znak * 10
(powielenie znaków); Przypisania: =, +=, -=, *=, /=, %=, **=, //=; Logiczne: and, or, not; Fałszem logicznym
sa:
˛ liczby zero (0, 0.0), False, None (null), puste kolekcje ([], (), {}, set()), puste napisy. Wszystko inne jest
prawda˛ logiczna.˛ Zawierania: in, not in; Porównania: ==, >, <, <>, <=, >= != (jest różne).
Operator * rozpakowuj˛e list˛e paramterów przekazana˛ funkcji. Operator ** rozpakuje słownik.
lista jedna z podstawowych struktur danych, indeksowana sekwencja takich samych lub różnych elementów, które
można zmieniać. Przypomina tabele z innych j˛ezyków programowania. Np. imiona = [’Ala’, ’Ola’,
’Ela’]. Deklaracja pustej listy: lista = [].
tupla podbnie jak lista, zawiera indeksowana˛ sekwencj˛e takich samych lub różnych elementów, ale nie można ich
zmieniać. Cz˛esto służy do przechowywania lub przekazywania ustawień, stałych wartości itp. Np. imiona =
(’Ala’, ’Ola’, ’Ela’). 1-elementowa˛ tupl˛e należy zapisywać z dodatkowym przecinkiem: tupla1
= (1,).
zbiór nieuporzadkowany,
˛
nieindeksowany zestaw elementów tego samego lub różnych typów, nie może zawierać
duplikatów, obsługuje charakterystyczne dla zbiorów operacje: sum˛e, iloczyn oraz różnic˛e. Np. imiona =
set([’Ala’, ’Ola’, ’Ela’]). Deklaracja pustego zbioru: zbior = set().
słownik typ mapowania, zestaw par elementów w postaci “klucz: wartość”. Kluczami moga˛ być liczby, ciagi
˛ znaków
czy tuple. Wartości moga˛ być tego samego lub różnych typów. Np. osoby = {’Ala’: ’Lipiec’ ,
162
Rozdział 5. Python
Materiały eCG IT Documentation, Wydanie 1
’Ola’: ’Maj’, ’Ela’: ’Styczeń’}. Dane ze słownika łatwo wydobyć: slownik[’klucz’],
lub zmienić: slownik[’klucz’] = wartosc. Deklaracja pustego słownika: slownik = dict().
instrukcja warunkowa podstawowa konstrukcja w programowaniu, wykorzystuje wyrażenie logiczne przyjmujace
˛
wartość True (prawda) lub False (fałsz) do wyboru odpowiedniego działania. Umożliwia rozgałezianie kodu.
Np.:
if wiek < 18:
print "Treść zabroniona"
else:
print "Zapraszamy"
p˛etla podstawowa konstrukcja w programowaniu, umożliwia powtarzanie fragmentów kodu zadana˛ ilość razy (p˛etla
for) lub dopóki podane wyrażenie logiczne jest prawdziwe (p˛etla while). Należy zadbać, aby p˛etla była
skończona za pomoca˛ odpowiedniego warunku lub instrukcji przeywajacej
˛ powtarzanie. Np.:
for i in range(11):
print i
zmienna iteracyjna zmienna wyst˛epujaca
˛ w p˛etli, której wartość zmienia si˛e, najcz˛eściej jest zwi˛ekszana (inkremntacja) o 1, w każdym wykonaniu p˛etli. Może pełnić rol˛e “licznika” powtórzeń lub być elementem wyrażenia
logicznego wyznaczajacego
˛
koniec działania p˛etli.
iteratory (ang. iterators) – obiekt reprezentujacy
˛ sekwencj˛e danych, zwracajacy
˛ z niej po jednym elemencie na raz
przy użyciu metody next(); jeżeli nie ma nast˛epnego elementu, zwracany jest wyjatek
˛ StopIteration.
Funkcja iter() potrafi zwrócić iterator z podanego obiektu.
generatory wyrażeń (ang. generator expressions) – zwi˛ezły w notacji sposób tworzenia iteratorów według składni:
( wyrażenie for wyraz in sekwencja if warunek )
wyrażenie listowe (ang. list comprehensions) – efektywny sposób tworzenia list na podstawie elementów dowolnych sekwencji, na których wykonywane sa˛ te same operacje i które opcjonalnie spełniaja˛ określone warunki.
Składnia: [ wyrażenie for wyraz in sekwencja if warunek ]
mapowanie funkcji w kontekście funkcji map() oznacza zastosowanie danej funkcji do wszystkich dostarczonych
wartości
wyrażenia lambda zwane czasem funkcjami lambda, sposób zwi˛ezłego zapisywania prostych funkcji w postaci
pojedynczych wyrażeń
filtrowanie danych selekcja danych na podstawie jakichś kryteriów
wyjatki
˛
to komunikaty zgłaszane przez interpreter Pythona, pozwalajace
˛ ustalić przyczyny bł˛ednego działania kodu.
funkcja blok cz˛esto wykonywanego kodu wydzielony słowem kluczowym def, opatrzony unikalna˛ w danym zasi˛egu nazwa;
˛ może przyjmować dane i zwracać wartości za pomoca˛ słowa kluczowego return.
moduł plik zawierajacy
˛ wiele zazwyczaj cz˛esto używanych w wielu programach funkcji lub klas; zanim skorzystamy
z zawartych w nim fragmentów kodu, trzeba je lub cały moduł zaimportować za pomoca˛ słowa kluczowego
import.
serializacja proces przekształcania obiektów w strumień znaków lub bajtów, który można zapisać w pliku (bazie)
lub przekazać do innego programu.
5.6 Słownik systemowy
terminal to tekstowa powłoka, pozwalajaca
˛ sterować praca˛ komputera za pomoca˛ poleceń wpisywanych z klawiatury (lub wklejanych ze schowka). W systemach Linux cz˛esto da si˛e go uruchomić skrótem Win+T lub
5.6. Słownik systemowy
163
Materiały eCG IT Documentation, Wydanie 1
Ctrl+Alt+T. Jeśli skróty nie działaja˛ szukamy w menu start. Skrót Ctrl+Shift+T pozwala otworzyć
kolejna˛ kart˛e terminala, w każdej karcie możemy robić coś innego.
JSON JavaScript Object Notation – prosty tekstowy format wymiany danych oparty na podzbiorze j˛ezyka JavaScript,
obsługiwany przez wi˛ekszość j˛ezyków programowania, szeroko stosowany w aplikacjach internetowych.
API [todo]
5.7 Propozycja scenariuszy warsztatów
• python_warsztaty.pdf
5.8 Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
164
Rozdział 5. Python
ROZDZIAŁ 6
Gra robotów
6.1 Zasady i zaczynamy
RobotGame to gra, w której walcza˛ ze soba˛ programy – roboty na planszy o wymiarach 19x19 pól. Celem gry jest
umieszczenie na niej jak najwi˛ekszej ilości robotów w ciagu
˛ 100 rund rozgrywki.
Czarne pola (ang. obstacle) wyznaczaja˛ granic˛e areny walk, zielone pola (ang. spawn points) to punkty wejścia, w
których co 10 rund pojawia si˛e po 5 robotów, każdy z 50 punktami HP (ang. health points) na starcie.
W każdej rundzie każdy robot musi wybrać jedno z nast˛epujacych
˛
działań:
• Ruch (ang. move) na przyległe pole w pionie (góra, dół) lub poziomie (lewo, prawo). W przypadku, kiedy w
polu docelowym znajduje si˛e lub znajdzie si˛e inny robot nast˛epuje kolizja i utrata po 5 punktów HP.
• Atak (ang. attack) na przyległe pole, wrogi robot na tym polu traci 8-10 punktów HP.
• Samobójstwo (ang. suicide) – robot ginie pod koniec rundy zabierajac
˛ wszystkim wrogim robotom obok po 15
punktów HP.
• Obrona (ang. guard) – robot pozostaje w miejscu, tracac
˛ połow˛e punktów HP w wyniku ataku lub samobójstwa.
W grze nie można uszkodzić własnych robotów.
165
Materiały eCG IT Documentation, Wydanie 1
6.1.1 Sztuczna inteligencja
Zadaniem gracza jest stworzenie sztucznej inteligencji robota, która pozwoli mu w określonych sytuacjach na arenie
wybrać odpowiednie działanie. Trzeba wi˛ec: określić dana˛ sytuacj˛e, ustalić działanie robota, zakodować je i przetestować, np.:
1. Gdzie ma iść robot po po wejściu na aren˛e?
2. Działanie: “Idź do środka”.
3. Jaki kod umożliwi robotowi realizowanie tej reguły?
4. Czy to działa?
Aby ułatwić budowanie robota, przedstawiamy kilka przykładowych reguł i “klocków”, z których można zaczać
˛
składać swojego robota. Pokazujemy również, jak testować swoje roboty. Nie podajemy jednak “przepisu” na robota
najlepszego. Do tego musisz dojść sam.
6.1.2 Środowisko testowe
Do budowania i testowania robotów używamy biblioteki rg z pakietu rgkit. Przygotujemy wi˛ec środowisko deweloperskie w katalogu robot.
Uwaga: Jeżeli korzystasz z polecanej przez nas na warsztaty dystrybucji LxPupTahr, środowisko testowe jest już
przygotowane w katlogu ~/robot.
W terminalu wydajemy polecenia:
~$ mkdir robot; cd robot
~robot$ virtualenv env
~robot$ source env/bin/activate
(env):~/robot$ pip install rgkit
Dodatkowo instalujemy pakiet zawierajacy
˛ roboty open source, nast˛epnie symulator ułatwiajacy
˛ testowanie, a na
koniec tworzymy skrót do jego uruchamiania:
(env):~/robot$ git clone https://github.com/mpeterv/robotgame-bots bots
(env):~/robot$ git clone https://github.com/mpeterv/rgsimulator.git
(env):~/robot$ ln -s rgsimulator/rgsimulator.py symuluj
Po wykonaniu wszystkich powyższych poleceń i komendy ls -l powinniśmy zobaczyć:
Kolejne wersje robota proponujemy zapisywać w plikach robot01.py, robot02.py itd. B˛edziemy mogli je uruchamiać
lub testować za pomoca˛ poleceń:
(env)~/robot$ rgrun robot01.py robot02.py
(env)~/robot$ rgrun bots/stupid26.py robot01.py
(env)~/robot$ python ./symuluj robot01.py robot02.py
Obsługa symulatora:
• Klawisz F: utworzenie robota-przyjaciela w zaznaczonym polu.
• Klawisz E: utworzenie robota-wroga w zaznaczonym polu.
• Klawisze Delete or Backspace: usuni˛ecie robota z zaznaczonego pola.
• Klawisz H: zmiana punktów HP robota.
• Klawisz C: wyczyszczenie planszy gry.
166
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
6.1. Zasady i zaczynamy
167
Materiały eCG IT Documentation, Wydanie 1
• Klawisz Spacja: pokazuje planowane ruchy robotów.
• Klawisz Enter: uruchomienie rundy.
• Klawisz G: tworzy i usuwa roboty w punktach wejścia (ang. spawn locations), “generowanie robotów”.
Uwaga: Opisana instalacja zakłada użycie środowiska wirtualnego tworzonego przez polecenie virtualenv, dlatego przed uruchomieniem rozgrywki lub symulacji trzeba pami˛etać o wydaniu w katalogu robot polecenia
source env/bin/activate. Poleceniem deactivate opuszczamy środowisko wirtualne.
6.2 RG – klocki 1
Wskazówka:
• Każdy “klocek” można testować osobno, a później w połaczeniu
˛
z innymi. Warto i trzeba zmieniać kolejność
stosowanych reguł!
6.2.1 Idź do środka
To b˛edzie nasza domyślna reguła. Umieszczamy ja˛ w pliku robot01.py zawierajacym
˛
niezb˛edne minimum działajacego
˛
bota:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
# idź do środka planszy, ruch domyślny
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
10
11
Metody i właściwości biblioteki rg:
• rg.toward(poz_wyj, poz_cel) – zwraca nast˛epne położenie na drodze z bieżacego
˛
miejsca do podanego.
• self.location – pozycja robota, który podejmuje działanie (self).
• rg.CENTER_POINT – środek areny.
6.2.2 W środku broń sie˛ lub giń
Co powinien robić robot, kiedy dojdzie do środka? Może si˛e bronić lub popełnić samobójstwo:
1
2
3
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
return ['guard']
4
5
# LUB
6
7
# jeżeli jesteś w środku, popełnij samobójstwo
168
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
8
9
if self.location == rg.CENTER_POINT:
return ['suicide']
6.2.3 Atakuj wrogów obok
Wersja wykorzystujaca
˛ p˛etl˛e.
1
2
3
4
5
6
# jeżeli obok sa˛ przeciwnicy, atakuj
# wersja z p˛
etla˛ przegladaj
˛
ac
˛ a˛ wszystkie pola zaj˛
ete przez roboty
for poz, robot in game.robots.iteritems():
if robot.player_id != self.player_id:
if rg.dist(poz, self.location) <= 1:
return ['attack', poz]
Metody i właściwości biblioteki rg:
• Słownik game.robots zawiera dane wszystkich robotów na planszy. Metoda .iteritems() zwraca indeks poz, czyli położenie (x,y) robota, oraz słownik robot opisujacy
˛ jego właściwości, czyli:
– player_id – identyfikator gracza, do którego należy robot;
– hp – ilość punktów HP robota;
– location – tupla (x, y) oznaczajaca
˛ położenie robota na planszy;
– robot_id – identyfikator robota w Twojej drużynie.
• rg.dist(poz1, poz1) – zwraca matematyczna˛ odległość mi˛edzy dwoma położeniami.
6.2.4 Robot podstawowy
Łacz
˛ ac
˛ omówione wyżej trzy podstawowe reguły, otrzymujemy robota podstawowego:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
8
9
10
11
def act(self, game):
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
return ['guard']
12
13
14
15
16
17
# jeżeli wokół sa˛ przeciwnicy, atakuj
for poz, robot in game.robots.iteritems():
if robot.player_id != self.player_id:
if rg.dist(poz, self.location) <= 1:
return ['attack', poz]
18
19
20
# idź do środka planszy
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
Wybrane działanie robota zwracamy za pomoca˛ instrukcji return. Zwróć uwag˛e, jak ważna jest w tej wersji kodu
kolejność umieszczenia reguł, pierwszy spełniony warunek powoduje wyjście z funkcji, wi˛ec pozostałe możliwości
nie sa˛ już sprawdzane!
6.2. RG – klocki 1
169
Materiały eCG IT Documentation, Wydanie 1
Powyższy kod można przekształcić wykorzystujac
˛ zmienna˛ pomocnicza˛ ruch, inicjowana˛ działaniem domyślnym,
które może zostać zmienione przez kolejne reguły. Dopiero na końcu zwracamy ustalona˛ akcj˛e:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
# działanie domyślne:
ruch = ['move', rg.toward(self.location, rg.CENTER_POINT)]
8
9
10
11
if self.location == rg.CENTER_POINT:
ruch = ['guard']
12
13
14
for poz, robot in game.robots.iteritems():
if robot.player_id != self.player_id:
if rg.dist(poz, self.location) <= 1:
ruch = ['attack', poz]
15
16
17
18
19
return ruch
20
Ćwiczenie 1
Przetestuj działanie robota podstawowego wystawiajac
˛ go do gry z samym soba˛ w symulatorze. Zaobserwuj zachowanie si˛e robotów tworzac
˛ różne układy poczatkowe:
˛
(env)~/robot$ python ./symuluj robot04a.py robot04b.py
6.2.5 Możliwe ulepszenia
Robota podstawowego można rozbudowywać na różne sposoby przy użyciu różnych technik kodowania. Proponujemy
wi˛ec wersj˛e **A** oparta˛ na funkcjach i listach oraz wersj˛e **B** oparta˛ na zbiorach. Obie wersje implementuja˛ te
same reguły, jednak efekt końcowy nie wcale nie musi być identyczny. Przetestuj i przekonaj si˛e sam.
6.3 RG – klocki 2A
Wskazówka:
• Każdy “klocek” można testować osobno, a później w połaczeniu
˛
z innymi. Warto i trzeba zmieniać kolejność
stosowanych reguł!
6.3.1 Typy pól
Zobaczmy, w jaki sposób dowiedzieć si˛e, w jakim miejscu si˛e znajdujemy, gdzie wokół mamy wrogów lub pola, na
które można wejść. Dysponujac
˛ takimi informacjami, b˛edziemy mogli podejmować bardziej przemyślane działania.
Wykorzystamy kilka pomocniczych funkcji.
170
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Czy to wejście?
# funkcja zwróci prawd˛
e, jeżeli "poz" wskazuje punkt wejścia
def czy_wejscie(poz):
if 'spawn' in rg.loc_types(poz):
return True
return False
Metody i właściwości biblioteki rg:
• gr.loc_types(poz) – zwraca typ pola wskazywanego przez poz:
– invalid – poza granicami planszy(np. (-1, -5) lub (23, 66));
– normal – w ramach planszy;
– spawn – punkt wejścia robotów;
– obstacle – pola zablokowane ograniczajace
˛ aren˛e.
Czy obok jest wróg?
# funkcja zwróci prawd˛
e, jeżeli "poz" wskazuje wroga
def czy_wrog(poz):
if game.robots.get(poz) != None:
if game.robots[poz].player_id != self.player_id:
return True
return False
# lista wrogów obok
wrogowie_obok = []
for poz in rg.locs_around(self.location):
if czy_wrog(poz):
wrogowie_obok.append(poz)
# warunek sprawdzajacy,
˛
czy obok sa˛ wrogowie
if len(wrogowie_obok):
pass
W powyższym kodzie metoda .get(poz) pozwala pobrać dane robota, którego kluczem w słowniku jest poz.
Metody i właściwości biblioteki rg:
• rg.locs_around(poz, filter_out=None) – zwraca list˛e położeń sasiaduj
˛
acych
˛
z poz. Jako
filter_out można podać typy położeń do wyeliminowania, np.: rg.locs_around(self.location,
filter_out=(’invalid’, ’obstacle’)).
Wskazówka: Definicje funkcji i list należy wstawić na poczatku
˛ metody Robot.act() – przed pierwszym użyciem.
Wykorzystujac
˛ powyższe “klocki” możemy napisać robota realizujacego
˛
nast˛epujace
˛ reguły:
1. Opuść jak najszybciej wejście;
2. Atakuj wrogów obok;
3. W środku broń si˛e;
4. W ostateczności idź do środka.
6.3. RG – klocki 2A
171
Materiały eCG IT Documentation, Wydanie 1
Implementacja
Przykładowa implementacja może wygladać
˛
nast˛epujaco:
˛
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
def czy_wejscie(poz):
if 'spawn' in rg.loc_types(poz):
return True
return False
10
11
12
13
14
def czy_wrog(poz):
if game.robots.get(poz) != None:
if game.robots[poz].player_id != self.player_id:
return True
return False
15
16
17
18
19
20
# lista wrogów obok
wrogowie_obok = []
for poz in rg.locs_around(self.location):
if czy_wrog(poz):
wrogowie_obok.append(poz)
21
22
23
24
25
26
# jeżeli jesteś w punkcie wejścia, opuść go
if czy_wejscie(self.location):
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
27
28
29
30
# jeżeli obok sa˛ przeciwnicy, atakuj
if len(wrogowie_obok):
return ['attack', wrogowie_obok.pop()]
31
32
33
34
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
return ['guard']
35
36
37
38
# idź do środka planszy
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
39
40
Metoda .pop() zastosowana do listy zwraca jej ostatni element.
Ćwiczenie 1
Zapisz powyższa˛ implementacj˛e w katalogu robot i przetestuj ja˛ w symulatorze, a nast˛epnie wystaw ja˛ do walki z
robotem podstawowym. Poeksperymentuj z kolejnościa˛ reguł, która określa ich priorytety!
6.3.2 Atakuj, jeśli nie umrzesz
Warto atakować, ale nie wtedy, gdy grozi nam śmierć. Można przyjać
˛ zasad˛e, że atakujemy tylko wtedy, kiedy suma
potencjalnych uszkodzeń b˛edzie mniejsza niż zdrowie naszego robota. Zmień wi˛ec dotychczasowe reguły ataku wroga
172
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
korzystajac
˛ z poniższych “klocków”:
# WERSJA A
# jeżeli suma potencjalnych uszkodzeń jest mniejsza od naszego zdrowia
# funkcja zwróci prawd˛
e
def czy_atak():
if 9*len(wrogowie_obok) < self.hp:
return True
return False
Metody i właściwości biblioteki rg:
• self.hp – ilość punktów HP robota.
Ćwiczenie 2
Dodaj powyższa˛ reguł˛e do poprzedniej wersji robota.
6.3.3 Ruszaj sie˛ bezpiecznie
Zamiast iść na oślep lepiej wchodzić czy uciekać na bezpieczne pola. Za “bezpieczne” przyjmiemy na razie pole
puste, niezablokowane i nie b˛edace
˛ punktem wejścia.
# WERSJA A
# funkcja zwróci prawd˛
e jeżeli pole poz b˛
edzie puste
def czy_puste(poz):
if ('normal' in rg.loc_types(poz)) and not ('obstacle' in rg.loc_types(poz)):
if game.robots.get(poz) == None:
return True
return False
puste = [] # lista pustych pól obok
bezpieczne = [] # lista bezpiecznych pól obok
for poz in rg.locs_around(self.location):
if czy_puste(poz):
puste.append(poz)
if czy_puste(poz) and not czy_wejscie(poz):
bezpieczne.append(poz)
6.3.4 Atakuj 2 kroki obok
Jeżeli w odległości 2 kroków jest przeciwnik, zamiast iść w jego kierunku i narażać si˛e na szkody, lepiej go zaatakuj,
aby nie mógł bezkarnie si˛e do nas zbliżyć.
# WERSJA A
# funkcja zwróci prawd˛
e, jeżeli w odległości 2 kroków z przodu jest wróg
def zprzodu(l1, l2):
if rg.wdist(l1, l2) == 2:
if abs(l1[0] - l2[0]) == 1:
return False
else:
return True
return False
# funkcja zwróci współrz˛
edne pola środkowego mi˛
edzy dwoma innymi
6.3. RG – klocki 2A
173
Materiały eCG IT Documentation, Wydanie 1
# oddalonymi o 2 kroki
def miedzypole(p1, p2):
return (int((p1[0]+p2[0]) / 2), int((p1[1]+p2[1]) / 2))
for poz, robot in game.get('robots').items():
if czy_wrog(poz):
if rg.wdist(poz, self.location) == 2:
if zprzodu(poz, self.location):
return ['attack', miedzypole(poz, self.location)]
if rg.wdist(rg.toward(loc, rg.CENTER_POINT), self.location) == 1:
return ['attack', rg.toward(poz, rg.CENTER_POINT)]
else:
return ['attack', (self.location[0], poz[1])]
6.3.5 Składamy reguły
Ćwiczenie 3
Jeżeli czujesz si˛e na siłach, spróbuj dokładać do robota w wersji A (opartego na funkcjach) po jednej z przedstawionych reguł, czyli: 1) Atakuj, jeśli nie umrzesz; 2) Ruszaj si˛e bezpiecznie; 3) Atakuj na 2 kroki. Przetestuj w
symulatorze każda˛ zmian˛e.
Omówione reguły można poskładać w różny sposób, np. tak:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
def czy_wejscie(poz):
if 'spawn' in rg.loc_types(poz):
return True
return False
10
11
12
13
14
def czy_wrog(poz):
if game.robots.get(poz) != None:
if game.robots[poz].player_id != self.player_id:
return True
return False
15
16
17
18
19
20
def czy_atak():
if 9*len(wrogowie_obok) < self.hp:
return True
return False
21
22
23
24
25
def czy_puste(poz):
if ('normal' in rg.loc_types(poz)) and not ('obstacle' in rg.loc_types(poz)):
if game.robots.get(poz) == None:
return True
return False
26
27
28
29
30
31
puste = [] # lista pustych pól obok
bezpieczne = [] # lista bezpiecznych pól obok
32
33
174
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
34
35
36
37
38
39
for poz in rg.locs_around(self.location):
if czy_puste(poz):
puste.append(poz)
if czy_puste(poz) and not czy_wejscie(poz):
bezpieczne.append(poz)
40
41
42
43
44
45
46
47
48
# funkcja zwróci prawd˛
e, jeżeli w odległości 2 kroków z przodu jest wróg
def zprzodu(l1, l2):
if rg.wdist(l1, l2) == 2:
if abs(l1[0] - l2[0]) == 1:
return False
else:
return True
return False
49
50
51
52
53
# funkcja zwróci współrz˛
edne pola środkowego mi˛
edzy dwoma innymi
# oddalonymi o 2 kroki
def miedzypole(p1, p2):
return (int((p1[0]+p2[0]) / 2), int((p1[1]+p2[1]) / 2))
54
55
56
57
58
59
# lista wrogów obok
wrogowie_obok = []
for poz in rg.locs_around(self.location):
if czy_wrog(poz):
wrogowie_obok.append(poz)
60
61
62
63
# jeżeli jesteś w punkcie wejścia, opuść go
if czy_wejscie(self.location):
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
64
65
66
67
68
69
70
# jeżeli obok sa˛ przeciwnicy, atakuj, o ile to bezpieczne
if len(wrogowie_obok):
if czy_atak():
return ['attack', wrogowie_obok.pop()]
elif bezpieczne:
return ['move', bezpieczne.pop()]
71
72
73
74
75
76
77
78
79
80
# jeżeli wróg jest o dwa kroki, atakuj
for poz, robot in game.get('robots').items():
if czy_wrog(poz) and rg.wdist(poz, self.location) == 2:
if zprzodu(poz, self.location):
return ['attack', miedzypole(poz, self.location)]
if rg.wdist(rg.toward(poz, rg.CENTER_POINT), self.location) == 1:
return ['attack', rg.toward(poz, rg.CENTER_POINT)]
else:
return ['attack', (self.location[0], poz[1])]
81
82
83
84
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
return ['guard']
85
86
87
# idź do środka planszy
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
6.3. RG – klocki 2A
175
Materiały eCG IT Documentation, Wydanie 1
6.3.6 Możliwe ulepszenia
Poniżej pokazujemy “klocki”, których możesz użyć, aby zoptymalizować robota. Zamieszczamy również list˛e pytań
do przemyślenia, aby zach˛ecić ci˛e do samodzielnego konstruowania najlepszego robota :-)
Atakuj najsłabszego
# wersja A
# funkcja zwracajaca
˛
atak na najsłabszego wroga obok
def atakuj():
r = wrogowie_obok[0]
for poz in wrogowie_obok:
if game.robots[poz]['hp'] > game.robots[r]['hp']:
r = poz
return ['attack', r]
Inne
• Czy warto atakować, jeśli obok jest wi˛ecej niż 1 wróg?
• Czy warto atakować 1 wroga obok, ale mocniejszego od nas?
• Jeżeli nie można bezpiecznie si˛e ruszyć, może lepiej si˛e bronić?
• Jeśli jesteśmy otoczeni przez wrogów, może lepiej popełnić samobójstwo...
Proponujemy, żebyś sam zaczał
˛ wprowadzać i testować zasugerowane ulepszenia. Możesz też zajrzeć do drugiego
drugiego i trzeciego zestawu klocków opartych na zbiorach.
6.4 RG – klocki 2B
Wskazówka:
• Każdy “klocek” można testować osobno, a później w połaczeniu
˛
z innymi. Warto i trzeba zmieniać kolejność
stosowanych reguł!
6.4.1 Typy pól
Zobaczmy, w jaki sposób dowiedzieć si˛e, w jakim miejscu si˛e znajdujemy, gdzie wokół mamy wrogów lub pola, na
które można wejść. Dysponujac
˛ takimi informacjami, b˛edziemy mogli podejmować bardziej przemyślane działania.
Wykorzystamy wyrażenia zbiorów (ang. set comprehensions) (zob. wyrażenie listowe) i operacje na zbiorach (zob.
zbiór).
Czy to wejście?
# wszystkie pola na planszy jako współrz˛
edne (x, y)
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
# punkty wejścia (spawn)
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
176
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
# warunek sprawdzajacy,
˛
czy "poz" jest w punkcie wejścia
if poz in wejscia:
pass
Metody i właściwości biblioteki rg:
• gr.loc_types(poz) – zwraca typ pola wskazywanego przez poz:
– invalid – poza granicami planszy(np. (-1, -5) lub (23, 66));
– normal – w ramach planszy;
– spawn – punkt wejścia robotów;
– obstacle – pola zablokowane ograniczajace
˛ aren˛e.
Czy obok jest wróg?
Wersja oparta na zbiorach wykorzystuje różnic˛e i cześć wspólna˛ zbiorów.
# pola zablokowane
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
# pola zaj˛
ete przez nasze roboty
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
# pola zaj˛
ete przez wrogów
wrogowie = set(game.robots) - przyjaciele
# pola sasiednie
˛
sasiednie = set(rg.locs_around(self.location)) - zablokowane
# pola obok zaj˛
ete przez wrogów
wrogowie_obok = sasiednie & wrogowie
# warunek sprawdzajacy,
˛
czy obok sa˛ wrogowie
if wrogowie_obok:
pass
Metody i właściwości biblioteki rg:
• rg.locs_around(poz, filter_out=None) – zwraca list˛e położeń sasiaduj
˛
acych
˛
z poz. Jako
filter_out można podać typy położeń do wyeliminowania, np.: rg.locs_around(self.location,
filter_out=(’invalid’, ’obstacle’)).
Wskazówka: Definicje zbiorów należy wstawić na poczatku
˛ metody Robot.act() – przed pierwszym użyciem.
Wykorzystujac
˛ powyższe “klocki” możemy napisać robota realizujacego
˛
nast˛epujace
˛ reguły:
1. Opuść jak najszybciej wejście;
2. Atakuj wrogów obok;
3. W środku broń si˛e;
4. W ostateczności idź do środka.
Implementacja
Przykładowa implementacja może wygladać
˛
nast˛epujaco:
˛
6.4. RG – klocki 2B
177
Materiały eCG IT Documentation, Wydanie 1
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
# wszystkie pola
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
# punkty wejścia
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
# pola zablokowane
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
# pola zaj˛
ete przez nasze roboty
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
# pola zaj˛
ete przez wrogów
wrogowie = set(game.robots) - przyjaciele
# pola sasiednie
˛
sasiednie = set(rg.locs_around(self.location)) - zablokowane
# pola sasiednie
˛
zaj˛
ete przez wrogów
wrogowie_obok = sasiednie & wrogowie
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# działanie domyślne:
ruch = ['move', rg.toward(self.location, rg.CENTER_POINT)]
25
26
27
# jeżeli jesteś w punkcie wejścia, opuść go
if self.location in wejscia:
ruch = ['move', rg.toward(self.location, rg.CENTER_POINT)]
28
29
30
31
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
ruch = ['guard']
32
33
34
35
# jeżeli obok sa˛ przeciwnicy, atakuj
if wrogowie_obok:
ruch = ['attack', wrogowie_obok.pop()]
36
37
38
39
return ruch
40
Metoda .pop() zastosowana do zbioru zwraca element losowy.
Ćwiczenie 1
Zapisz powyższa˛ implementacj˛e w katalogu robot i przetestuj ja˛ w symulatorze, a nast˛epnie wystaw ja˛ do walki z
robotem podstawowym. Poeksperymentuj z kolejnościa˛ reguł, która określa ich priorytety!
Wskazówka: Do kontrolowania logiki działania robota zamiast rozłacznych
˛
instrukcji warunkowych: if war1:
... if war2: ... itd. można użyć instrukcji złożonej: if war1: ... elif war2: ...
[elif war3: ...] else: ....
178
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
6.4.2 Atakuj, jeśli nie umrzesz
Warto atakować, ale nie wtedy, gdy grozi nam śmierć. Można przyjać
˛ zasad˛e, że atakujemy tylko wtedy, kiedy suma
potencjalnych uszkodzeń b˛edzie mniejsza niż zdrowie naszego robota. Zmień wi˛ec dotychczasowe reguły ataku wroga
korzystajac
˛ z poniższych “klocków”:
# WERSJA B
# jeżeli obok sa˛ przeciwnicy, atakuj
if wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
pass
else:
ruch = ['attack', wrogowie_obok.pop()]
Metody i właściwości biblioteki rg:
• self.hp – ilość punktów HP robota.
Ćwiczenie 2
Dodaj powyższa˛ reguł˛e do poprzedniej wersji robota.
6.4.3 Ruszaj sie˛ bezpiecznie
Zamiast iść na oślep lepiej wchodzić czy uciekać na bezpieczne pola. Za “bezpieczne” przyjmiemy na razie pole
puste, niezablokowane i nie b˛edace
˛ punktem wejścia.
# WERSJA B
# zbiór bezpiecznych pól
bezpieczne = sasiednie - wrogowie_obok - wejscia - przyjaciele
6.4.4 Atakuj 2 kroki obok
Jeżeli w odległości 2 kroków jest przeciwnik, zamiast iść w jego kierunku i narażać si˛e na szkody, lepiej go zaatakuj,
aby nie mógł bezkarnie si˛e do nas zbliżyć.
# WERSJA B
wrogowie_obok2 = {poz for poz in sasiednie if (set(rg.locs_around(poz)) & wrogowie)} - przyjaciele
if wrogowie_obok2:
ruch = ['attack', wrogowie_obok2.pop()]
6.4.5 Składamy reguły
Ćwiczenie 3
Jeżeli czujesz si˛e na siłach, spróbuj dokładać do robota w wersji B (opartego na zbiorach) po jednej z przedstawionych
reguł, czyli: 1) Atakuj, jeśli nie umrzesz; 2) Ruszaj si˛e bezpiecznie; 3) Atakuj na 2 kroki. Przetestuj w symulatorze
każda˛ zmian˛e.
Omówione reguły można poskładać w różny sposób, np. tak:
W wersji B opartej na zbiorach:
6.4. RG – klocki 2B
179
Materiały eCG IT Documentation, Wydanie 1
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
# wszystkie pola
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
# punkty wejścia
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
# pola zablokowane
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
# pola zaj˛
ete przez nasze roboty
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
# pola zaj˛
ete przez wrogów
wrogowie = set(game.robots) - przyjaciele
# pola sasiednie
˛
sasiednie = set(rg.locs_around(self.location)) - zablokowane
# pola sasiednie
˛
zaj˛
ete przez wrogów
wrogowie_obok = sasiednie & wrogowie
wrogowie_obok2 = {poz for poz in sasiednie if (set(rg.locs_around(poz)) & wrogowie)} - przyja
# pola bezpieczne
bezpieczne = sasiednie - wrogowie_obok - wejscia - przyjaciele
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# działanie domyślne:
ruch = ['move', rg.toward(self.location, rg.CENTER_POINT)]
28
29
30
# jeżeli jesteś w punkcie wejścia, opuść go
if self.location in wejscia:
ruch = ['move', rg.toward(self.location, rg.CENTER_POINT)]
31
32
33
34
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
ruch = ['guard']
35
36
37
38
# jeżeli obok sa˛ przeciwnicy, atakuj, o ile to bezpieczne
if wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
if bezpieczne:
ruch = ['move', bezpieczne.pop()]
else:
ruch = ['attack', wrogowie_obok.pop()]
39
40
41
42
43
44
45
46
if wrogowie_obok2:
ruch = ['attack', wrogowie_obok2.pop()]
47
48
49
return ruch
50
6.4.6 Możliwe ulepszenia
Poniżej pokazujemy “klocki”, których możesz użyć, aby zoptymalizować robota. Zamieszczamy również list˛e pytań
do przemyślenia, aby zach˛ecić ci˛e do samodzielnego konstruowania najlepszego robota :-)
180
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Atakuj najsłabszego
# wersja B
# funkcja znajdujaca
˛
najsłabszego wroga obok z podanego zbioru (bots)
def minhp(bots):
return min(bots, key=lambda x: game.robots[x].hp)
if wrogowie_obok:
...
else:
ruch = ['attack', minhp(wrogowie_obok)]
Najkrócej do celu
Funkcji mindist() można użyć do znalezienia najbliższego wroga, aby iść w jego kierunku, kiedy opuścimy punkt
wejścia:
# WERSJA B
# funkcja zwraca ze zbioru pól (bots) pole najbliższe podanego celu (poz)
def mindist(bots, poz):
return min(bots, key=lambda x: rg.dist(x, poz))
najblizszy_wrog = mindist(wrogowie,self.location)
Inne
• Czy warto atakować, jeśli obok jest wi˛ecej niż 1 wróg?
• Czy warto atakować 1 wroga obok, ale mocniejszego od nas?
• Jeżeli nie można bezpiecznie si˛e ruszyć, może lepiej si˛e bronić?
• Jeśli jesteśmy otoczeni przez wrogów, może lepiej popełnić samobójstwo...
• Spróbuj zmienić akcj˛e domyślna.˛
• Spróbuj użyć jednej złożonej instrukcji warunkowej!
Proponujemy, żebyś sam zaczał
˛ wprowadzać i testować zasugerowane ulepszenia. Możesz też zajrzeć do trzeciego
zestawu klocków.
6.5 RG – klocki 3B
6.5.1 Robot dotychczasowy
Na podstawie reguł i klocków z cz˛eści pierwszej mogliśmy stworzyć nast˛epujacego
˛
robota:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
8
def act(self, game):
6.5. RG – klocki 3B
181
Materiały eCG IT Documentation, Wydanie 1
9
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
wrogowie = set(game.robots) - przyjaciele
10
11
12
13
14
15
sasiednie = set(rg.locs_around(self.location)) - zablokowane
wrogowie_obok = sasiednie & wrogowie
wrogowie_obok2 = {poz for poz in sasiednie if (set(rg.locs_around(poz)) & wrogowie)} - przyja
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 - wejscia - przyjaciele
16
17
18
19
20
def mindist(bots, poz):
return min(bots, key=lambda x: rg.dist(x, poz))
21
22
23
if wrogowie:
najblizszy_wrog = mindist(wrogowie,self.location)
else:
najblizszy_wrog = rg.CENTER_POINT
24
25
26
27
28
# działanie domyślne:
ruch = ['guard']
29
30
31
if self.location in wejscia:
if bezpieczne:
ruch = ['move', mindist(bezpieczne, rg.CENTER_POINT)]
elif wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
if bezpieczne:
ruch = ['move', mindist(bezpieczne, rg.CENTER_POINT)]
else:
ruch = ['attack', wrogowie_obok.pop()]
elif wrogowie_obok2:
ruch = ['attack', wrogowie_obok2.pop()]
elif bezpieczne:
ruch = ['move', mindist(bezpieczne, najblizszy_wrog)]
32
33
34
35
36
37
38
39
40
41
42
43
44
45
return ruch
46
Jego działanie opiera si˛e na wyznaczeniu zbiorów pól określonego typu zastosowaniu nast˛epujacych
˛
reguł:
1. jeżeli nie ma nic lepszego, broń si˛e,
2. z punktu wejścia idź bezpiecznie do środka;
3. atakuj wrogów wokół siebie, o ile to bezpieczne, jeżeli nie, idź bezpiecznie do środka;
4. atakuj wrogów dwa pola obok;
5. idź bezpiecznie na najbliższego wroga.
Spróbujemy go ulepszyć dodajac,
˛ ale i prezycujac
˛ reguły.
6.5.2 Śledź wybrane miejsca
Aby unikać niepotrzebnych kolizji, nie należy wchodzić na wybrane wcześniej pola. Trzeba wi˛ec zapami˛etywać pola
wybrane w danej rundzie.
Przed klasa˛ Robot definiujemy dwie zmienne globalne, nast˛epnie na poczatku
˛ metody .act() inicjujemy dane:
182
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
# zmienne globalne
runda_numer = 0 # numer rundy
wybrane_pola = set() # zbiór wybranych w rundzie pól
# inicjacja danych
# wyzeruj zbiór wybrane_pola przy pierwszym robocie w rundzie
global runda_numer, wybrane_pola
if game.turn != runda_numer:
runda_numer = game.turn
wybrane_pola = set()
Do zapami˛etywania wybranych w rundzie pól posłuża˛ funkcje ruszaj() i stoj():
# jeżeli si˛
e ruszamy, zapisujemy docelowe pole
def ruszaj(poz):
wybrane_pola.add(poz)
return ['move', poz]
# jeżeli stoimy, zapisujemy zajmowane miejsce
def stoj(act, poz=None):
wybrane_pola.add(self.location)
return [act, poz]
Ze zbioru bezpieczne wyłaczamy
˛
wybrane pola i stosujemy nowe funkcje:
# ze zbioru bezpieczne wyłaczamy
˛
wybrane_pola
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 - \
wejscia - przyjaciele - wybrane_pola
# stosujemy nowy kod w regule "atakuj wroga dwa pola obok"
elif wrogowie_obok2 and self.location not in wybrane_pola:
# stosujemy funkcje "ruszaj()" i "stoj()"
# zamiast: ruch = ['move', mindist(bezpieczne, rg.CENTER_POINT)]
ruch = ruszaj(mindist(bezpieczne, rg.CENTER_POINT))
# zamiast: ruch = ['attack', wrogowie_obok.pop()]
ruch = stoj('attack', wrogowie_obok.pop())
# zamiast: ruch = ['move', mindist(bezpieczne, najblizszy_wrog)]
ruch = ruszaj(mindist(bezpieczne, najblizszy_wrog))
Wskazówka: Można zapami˛etywać wszystkie wybrane ruchy lub tylko niektóre. Przetestuj, czy ma to wpływ na
skuteczność AI.
6.5.3 Atakuj najsłabszego
Do tej pory atakowaliśmy przypadkowego robota wokół nas, lepiej wybrać najsłabszego.
# funkcja znajdujaca
˛
najsłabszego wroga obok
def minhp(bots):
return min(bots, key=lambda x: game.robots[x].hp)
elif wrogowie_obok:
...
6.5. RG – klocki 3B
183
Materiały eCG IT Documentation, Wydanie 1
else:
ruch = stoj('attack', minhp(wrogowie_obok))
Funkcja minhp() poda nam położenie najsłabszego wroga. Argument parametru key, czyli wyrażenie lambda
zwraca właściwość robotów, czyli punkty HP, wg której sa˛ porównywane.
6.5.4 Samobójstwo lepsze niż śmierć?
Jeżeli grozi nam śmierć, a nie ma bezpiecznego miejsca, aby uciec, lepiej popełnić samobójstwo:
# samobójstwo lepsze niż śmierć
elif wrogowie_obok:
if bezpieczne:
...
else:
ruch = stoj('suicide')
6.5.5 Unikaj nierównych starć
Nie warto walczyć z przeważajac
˛ a˛ liczba˛ wrogów.
elif wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
...
elif len(wrogowie_obok) > 1:
if bezpieczne:
ruch = ruszaj(mindist(bezpieczne, rg.CENTER_POINT))
else:
ruch = stoj('attack', minhp(wrogowie_obok))
6.5.6 Goń najsłabszych
Zamiast atakować słabego uciekajacego
˛
robota, lepiej go gonić, może trafi w gorsze miejsce...
elif wrogowie_obok:
...
else:
cel = minhp(wrogowie_obok)
if game.robots[cel].hp <= 5:
ruch = ruszaj(cel)
else:
ruch = stoj('attack', minhp(wrogowie_obok))
6.5.7 Robot zaawansowany
Po dodaniu/zmodyfikowaniu omwionych powyej reguł kod naszego robota może wygladać
˛
tak:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
runda_numer = 0 # numer rundy
184
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
7
wybrane_pola = set() # zbiór wybranych w rundzie pól
8
9
class Robot:
10
11
def act(self, game):
12
13
14
15
16
global runda_numer, wybrane_pola
if game.turn != runda_numer:
runda_numer = game.turn
wybrane_pola = set()
17
18
19
20
21
# jeżeli si˛
e ruszamy, zapisujemy docelowe pole
def ruszaj(loc):
wybrane_pola.add(loc)
return ['move', loc]
22
23
24
25
26
# jeżeli stoimy, zapisujemy zajmowane miejsce
def stoj(act, loc=None):
wybrane_pola.add(self.location)
return [act, loc]
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# wszystkie pola
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
# punkty wejścia
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
# pola zablokowane
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
# pola zaj˛
ete przez nasze roboty
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
# pola zaj˛
ete przez wrogów
wrogowie = set(game.robots) - przyjaciele
# pola sasiednie
˛
sasiednie = set(rg.locs_around(self.location)) - zablokowane
# pola sasiednie
˛
zaj˛
ete przez wrogów
wrogowie_obok = sasiednie & wrogowie
wrogowie_obok2 = {poz for poz in sasiednie if (set(rg.locs_around(poz)) & wrogowie)} - przyja
# pola bezpieczne
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 - wejscia - przyjaciele - wybrane_pol
45
46
47
48
# funkcja znajdujaca
˛
najsłabszego wroga obok z podanego zbioru (bots)
def mindist(bots, loc):
return min(bots, key=lambda x: rg.dist(x, loc))
49
50
51
52
53
if wrogowie:
najblizszy_wrog = mindist(wrogowie,self.location)
else:
najblizszy_wrog = rg.CENTER_POINT
54
55
56
# działanie domyślne:
ruch = ['guard']
57
58
59
60
# jeżeli jesteś w punkcie wejścia, opuść go
if self.location in wejscia:
ruch = ruszaj(mindist(bezpieczne, rg.CENTER_POINT))
61
62
63
64
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
ruch = ['guard']
6.5. RG – klocki 3B
185
Materiały eCG IT Documentation, Wydanie 1
65
# jeżeli obok sa˛ przeciwnicy, atakuj, o ile to bezpieczne,
# najsłabszego wroga
if wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
if bezpieczne:
ruch = ruszaj(mindist(bezpieczne, rg.CENTER_POINT))
else:
ruch = ['attack', minhp(wrogowie_obok)]
66
67
68
69
70
71
72
73
74
if wrogowie_obok2 and self.location not in wybrane_pola:
ruch = ['attack', wrogowie_obok2.pop()]
75
76
77
return ruch
78
Na koniec trzeba przetestować robota. Czy rzeczywiście jest lepszy od poprzednich wersji?
6.5.8 Podsumowanie
Nie myśl, że zastosowanie wszystkich powyższych reguł automatycznie ulepszy robota. Weź pod uwag˛e fakt, że
roboty pojawiaja˛ si˛e w losowych punktach, oraz to, że strategia przeciwnika może być inna od zakładanej. Zaproponowane połaczenie
˛
klocków nie musi być optymalne. Przetestuj kolejne wersje robotów, ustal ich zalety i wady,
eksperymentuj, aby znaleźć lepsze rozwiazania.
˛
6.6 RG – dokumentacja
RobotGame to gra, w której walcza˛ ze soba˛ programy – boty. Poniżej nieautoryzowane tłumaczenie oryginalnej
dokumentacji oraz materiałów dodatkowych:
6.6.1 Zasady gry
W Grze robotów piszesz programy kierujace
˛ walczacymi
˛
dla Ciebie robotami. Plansza˛ gry jest siatka o wymiarach
19x19 pól. Celem gry jest umieszczenie na niej jak najwi˛ekszej ilości robotów w ciagu
˛ 100 rund rozgrywki.
186
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Czarne kwadraty to pola, na które nie ma wst˛epu. Wyznaczaja˛ kolista˛ aren˛e dla walk robotów.
Zielone kwadraty oznaczaja˛ punkty wejścia do gry. Co 10 rund po 5 robotów każdego gracza rozpoczyna walk˛e w
losowych punktach wejścia (ang. spawn points). Roboty z poprzednich tur pozostajace
˛ w tych punktach gina.˛
Każdy robot rozpoczyna gr˛e z 50 punktami HP (ang. health points).
Roboty moga˛ działać (przemieszczać si˛e, atakować itd.) na przyległych kwdratach w pionie (góra, dół) i w poziomie
(lewo, prawo).
W każdej rundzie możliwe sa˛ nast˛epujace
˛ działania robota:
• Ruch na przyległy kwadrat. Jeżeli znajduje si˛e tam już robot lub inny robot próbuje zajać
˛ to samo miejsce,
obydwa traca˛ 5 punktów HP z powodu kolizji, a ruch(y) nie dochodzi(a)
˛ do skutku. Jeżeli jednak robot chce
przejść na pole zaj˛ete przez innego, a ten drugi opuszcza zajmowane pole, ruch jest udany.
Minimum cztery roboty w kwadracie, przemieszczajace
˛ si˛e zgodnie ze wskazówkami zegara, b˛eda˛ mogły si˛e
poruszać, podobnie dowolna ilość robotów w kole. (Roboty nie moga˛ bezpośrednio zamieniać si˛e miejscami!)
• Atak na przyległy kwadrat. Jeżeli w atakowanym kwadracie znajdzie si˛e robot pod koniec rundy, np. robot
pozostał w miejscu lub przeszedł na nie, robot ten traci od 8 do 10 punktów HP w nast˛epstwie uszkodzeń.
• Samobójstwo – robot ginie pod koniec rundy, zabierajac
˛ 15 punktów HP wszystkim robotom w sasiedztwie.
˛
• Obrona – robot pozostaje w miejscu, tracac
˛ połow˛e punktów HP wskutek ataku lub samobójstwa, nie odnosi
uszkodzeń z powodu kolizji.
W grze nie można uszkodzić własnych robotów. Kolizje, ataki i samobójstwa wyrzadzaj
˛
a˛ szkody tylko przeciwnikom.
Wygrawa gracz, który po 100 rundach ma najwi˛eksza˛ liczb˛e robotów na planszy.
Zadaniem gracza jest zakodowanie sztucznej inteligencji (ang. AI – artificial itelligance), dla wszystkie swoich robotów. Aby wygrać, roboty gracza musza˛ ze soba˛ współpracować, np. żeby otoczyć przeciwnika.
Informacja: Niniejsza dokumentacja jest nieautoryzowanym tłumaczeniem oficjalnej dokumentacji dost˛epnej na
stonie RobotGame.
6.6.2 Rozpoczynamy
Spis treści
• Rozpoczynamy
– Tworzenie robota
– Odczytywanie właściwości robota
– Przykładowy robot
6.6. RG – dokumentacja
187
Materiały eCG IT Documentation, Wydanie 1
Tworzenie robota
Podstawowa struktura klasy reprezentujacej
˛ każdego robota jest nast˛epujaca:
˛
class Robot:
def act(self, game):
return [<some action>, <params>]
Na poczatku
˛ gry powstaje jedna instanacja klasy Robot. Oznacza to, że właściwości klasy oraz globalne zmienne
modułu sa˛ współdzielone mi˛edzy wywołaniami. W każdej rundzie system wywołuje metod˛e act tej instancji dla
każdego robota, aby określić jego działanie. (Uwaga: na poczatku
˛ przeczytaj reguły.)
Metoda act musi zwrócić jedna˛ z nast˛epujacych
˛
odpowiedzi:
['move', (x, y)]
['attack', (x, y)]
['guard']
['suicide']
Jeżeli metoda act zwróci wyjatek
˛ lub bł˛edne polecenie, robot pozostaje w obronie, ale jeżeli powtórzy si˛e to zbyt
wiele razy, gracz zostanie zmuszony do kapitulacji. Szczegóły omówiono w dziale Zabezbieczenia.
Odczytywanie właściwości robota
Każdy robot, przy użyciu wskaźnika self, udost˛epnia nast˛epujace
˛ właściwości:
• location – położenie robota w formie tupli (x, y);
• hp – punkty zdrowia wyrażone liczba˛ całkowita˛
• player_id – identyfikator gracza, do którego należy robot (czyli oznaczenie “drużyny”)
• robot_id – unikalny identyfikator robota, ale tylko w obr˛ebie “drużyny”
Dla przykładu: kod self.hp – zwróci aktualny stan zdrowia robota.
W każdej rundzie system wywołujac
˛ metod˛e act udost˛epnia jej stan gry w nast˛epujacej
˛ strukturze game:
{
# słownik wszystkich robotów na polach wyznaczonych
# przez {location: robot}
'robots': {
(x1, y1): {
'location': (x1, y1),
'hp': hp,
'player_id': player_id,
# jeżeli robot jest w twojej drużynie
'robot_id': robot_id
},
# ...i pozostałe roboty
},
# ilość odbytych rund (wartość poczatkowa
˛
0)
'turn': turn
}
Wszystkie roboty w strukturze game[’robots’] sa˛ instancjami specjalnego słownika udost˛epniajacego
˛
ich właściwości, co przyśpiesza kodowanie. Tak wi˛ec nast˛epujace
˛ konstrukcje sa˛ tożsame:
188
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
game['robots'][location]['hp']
game['robots'][location].hp
game.robots[location].hp
Poniżej zwi˛ezły przykład drukujacy
˛ położenie wszystkich robotów z danej drużyny:
class Robot:
def act(self, game):
for loc, robot in game.robots.items():
if robot.player_id == self.player_id:
print loc
Przykładowy robot
Poniżej mamy kod prostego robota, który można potraktować jako punkt wyjścia. Robot, jeżeli znajdzie wokół siebie
przeciwnka, atakuje go, w przeciwnym razie przemieszcza si˛e do środka planszy (rg.CENTER_POINT).
import rg
class Robot:
def act(self, game):
# if we're in the center, stay put
if self.location == rg.CENTER_POINT:
return ['guard']
# if there are enemies around, attack them
for loc, bot in game.robots.iteritems():
if bot.player_id != self.player_id:
if rg.dist(loc, self.location) <= 1:
return ['attack', loc]
# move toward the center
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
Użyliśmy, jak widać modułu rg, który zostanie omówiony dalej.
Informacja: Podczas gry tworzona jest tylko jedna instancja robota, w której można zapisywać trwałe dane.
Informacja: Niniejsza dokumentacja jest nieautoryzowanym tłumaczeniem oficjalnej dokumentacji dost˛epnej na
stonie RobotGame.
6.6.3 Biblioteka rg
Gra robotów udost˛epnia bibliotek˛e ułatwiajac
˛ a˛ programowanie. Zawarta jest w module rg, który importujemy na
poczatku
˛ pliku instrukcja˛ import rg.
Uwaga: Położenie robota (loc) reprezentowane jest przez tupl˛e (x, y).
rg.dist(loc1, loc2)
Zwraca matematyczna˛ odległość mi˛edzy dwoma położeniami.
6.6. RG – dokumentacja
189
Materiały eCG IT Documentation, Wydanie 1
rg.wdist(loc1, loc2)
Zwraca różnic˛e w ruchach mi˛edzy dwoma położeniami. Ponieważ robot nie może poruszać si˛e na ukos, jest to suma
dx + dy.
rg.loc_types(loc)
Zwraca list˛e typów położeń wskazywanych przez loc. Możliwe wartości to:
• invalid – poza granicami planszy(np. (-1, -5) lub (23, 66));
• normal – w ramach planszy;
• spawn – punkt wejścia robotów;
• obstacle – pola, na które nie można si˛e ruszyć (szare kwadraty).
Metoda nie ma dost˛epu do kontekstu gry, np. wartość obstacle nie oznacza, że na sprawdzanym kwadracie nie ma
wrogiego robota; wiemy tylko, że dany kwadrat jest przeszkoda˛ na mapie.
Zwrócona lista może zawierać kombinacje wartości typu: [’normal’, ’obstacle’].
rg.locs_around(loc, filter_out=None)
Zwraca list˛e położeń sasiaduj
˛
acych
˛
z loc. Jako drugi argument filter_out można podać list˛e typów położeń
do wyeliminowania. Dla przykładu: rg.locs_around(self.location, filter_out=(’invalid’,
’obstacle’)) – poda list˛e kwadratów, na które można wejść.
rg.toward(current_loc, dest_loc)
Zwraca nast˛epne położenie na drodze z bieżacego
˛
miejsca do podanego. Np. poniższy kod:
import rg
class Robot:
def act(self, game):
if self.location == rg.CENTER_POINT:
return ['suicide']
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
– skieruje robota do środka planszy, gdzie popełni on samobójstwo.
rg.CENTER_POINT
Stała (ang. constant) definiujaca
˛ położenie środkowego punktu planszy.
rg.settings
Specjalny typ słownika (AttrDict) zawierajacy
˛ ustawienia gry.
• rg.settings.spawn_every – ilość rozegranych rund od wejścia robota do gry;
• rg.settings.spawn_per_player - ilość robotów wprowadzonych przez gracza;
• rg.settings.robot_hp – domyślna ilość punktów HP robota;
190
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
• rg.settings.attack_range – tupla (minimum, maksimum) przechowujaca
˛ zakres uszkodzeń wyrza˛
dzonych przez atak;
• rg.settings.collision_damage – uszkodzenia wyrzadzone
˛
przez kolizj˛e;
• rg.settings.suicide_damage – uszkodzenia wyrzadzone
˛
przez samobójstwo;
• rg.settings.max_turns – liczba rund w grze.
Czy w danym położeniu jest robot
Ponieważ struktura game.robots jest słownikiem robotów, w którym kluczami sa˛ położenia, a wartościami roboty,
można użyć testu (x, y) in game.robots, który zwróci True, jeśli w danym położeniu jest robot, lub Flase
w przeciwnym razie.
Informacja: Niniejsza dokumentacja jest nieautoryzowanym tłumaczeniem oficjalnej dokumentacji dost˛epnej na
stonie RobotGame.
6.6.4 Testowanie robotów
Pakiet rgkit
Do budowania i testowania robotów używamy pakietu rgkit. W tym celu przygotowujemy środowisko deweloperskie,
zawierajace
˛ bibliotek˛e rg:
~$ mkdir robot; cd robot
~robot/$ virtualenv env
~robot/$ source env/bin/activate
(env):~robot$ pip install rgkit
Po wykonaniu powyższych poleceń i zapisaniu implementacji klasy Robot np. w pliku ~/robot/robot01.py
możemy uruchamiać gr˛e przeciwko samemu sobie:
(env)~/robot$ rgrun robot01.py robot01.py
Jeżeli utworzymy inne implementacje robotów, np. w pliku ~/robot/robot02.py skonfrontujemy je poleceniem:
(env)~/robot$ rgrun robot01.py robot02.py
Przydatne opcje polecenia rgrun:
• -H – symulacja bez UI
• -r – roboty wprowadzane losowo zamiast symetrycznie.
Uwaga: Pokazana powyżej instalacja zakłada użycie środowiska wirtualnego tworzonego przez pakiet virtualenv,
dlatego przed uruchomieniem symulacji, a także przed użyciem omówionego niżej pakietu robotgame-bots trzeba
pami˛etać o wydaniu w katalogu robot polecenia:
~/robot$ source env/bin/activate
Roboty open-source
Swoje roboty warto wystawić do gry przeciwko przykładowym robotom dostarczanym przez projekt robotgame-bots:
Instalacja sprowadza si˛e do wykonania polecenia w utworzonym wcześniej katalogu robot:
6.6. RG – dokumentacja
191
Materiały eCG IT Documentation, Wydanie 1
~/robot$ git clone https://github.com/mpeterv/robotgame-bots bots
Wynikiem polecenia b˛edzie utworzenia podkatalogu ~/robot/bots zawierajacego
˛
kod przykładowych robotów.
List˛e dost˛epnych robotów najłatwiej użyskać wydajac
˛ polecenie:
(env)~/robot$ ls bots
Aby zmierzyć si˛e z wybranym robotem – na poczatek
˛ sugerujemy stupid26.py – wydajemy polecenie:
(env)~/robot$ rgrun mojrobot.py bots/stupid26.py
Od czasu do czasu można zaktualizować dost˛epne roboty poleceniem:
~/robot/bots$ git pull --rebase origin master
Symulator rg
Bardzo przydatny jest symulator zachowania robotów. Instalacja w katalogu robot:
~/robot$ git clone https://github.com/mpeterv/rgsimulator.git
Nast˛epnie uruchamiamy symulator podajac
˛ jako parametr nazw˛e przynajmniej jednego robota (można dwóch):
(env)~/robot$ rgsimulator/rgsimulator.py robot01.py [robot02.py]
Symulatorem sterujemy za pomoca˛ klawiszy:
• Klawisze kursora lub WASD do zaznaczania pól.
• Klawisz F: utworzenie robota-przyjaciela w zaznaczonym polu.
• Klawisz E: utworzenie robota-wroga w zaznaczonym polu.
• Klawisze Delete or Backspace: usuni˛ecie robota z zaznaczonego pola.
• Klawisz H: zmiana punktów HP robota.
• Klawisz T: zmiana rundy.
• Klawisz C: wyczyszczenie planszy gry.
• Klawisz Spacja: pokazuje planowane ruchy robotów.
• Klawisz Enter: uruchomienie rundy.
• Klawisz L: załadowanie meczu z robotgame.net. Należy podać tylko numer meczu.
• Klawisz K: załadowanie podanej rundy z załadowanego meczu. Also updates the simulator turn counter.
• Klawisz P: zamienia kod robotów gracza 1 z 2.
• Klawisz O: ponowne załadowanie kodu obydwu robotów.
• Klawisz N: zmienia działanie robota, wyznacza “nast˛epne działanie”.
• Klawisz G: tworzy i usuwa roboty w punktach wejścia (ang. spawn locations), “generowanie robotów”.
Wskazówka: W Linuksie warto utworzyć sobie przyjazny link do wywoływania symulatora. W katalogu robot
wydajemy polecenia:
(env)~/robot$ ln -s rgsimulator/rgsimulator.py symuluj
(env)~/robot$ symuluj robot01.py [robot02.py]
192
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Informacja: Niniejsza dokumentacja jest nieautoryzowanym tłumaczeniem oficjalnej dokumentacji dost˛epnej na
stonie RobotGame, a także RobotGame – rgkit. Opis działania symulatora robotów przetłumaczono na podstawie
strony projektu Rgsimulator.
6.6.5 Strategia podstawowa
Przykład robota
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
8
9
10
11
def act(self, game):
# jeżeli jesteś w środku, broń si˛
e
if self.location == rg.CENTER_POINT:
return ['guard']
12
13
14
15
16
17
# jeżeli wokół sa˛ przeciwnicy, atakuj
for poz, robot in game.robots.iteritems():
if robot.player_id != self.player_id:
if rg.dist(poz, self.location) <= 1:
return ['attack', poz]
18
19
20
# idź do środka planszy
return ['move', rg.toward(self.location, rg.CENTER_POINT)]
Z powyższego kodu wynikaja˛ trzy zasady:
• broń si˛e, jeżeli jesteś w środku planszy;
• atakuj przeciwnika, jeżeli jest obok;
• idź do środka.
To pozwala nam rozpoczać
˛ gr˛e, ale wiele możemy ulepszyć. Wi˛ekszość usprawnień (ang. feature), które zostana˛
omówione, to rozszerzenia wersji podstawowej. Konstruujac
˛ robota, można je stosować wybiórczo.
Kolejne reguły
Rozbudujemy przykład podstawowy. Oto lista reguł, które warto rozważyć:
• Reguła 1: Opuść punkt wejścia.
Pozostawanie w punkcie wejścia nie jest dobre. Sprawdźmy, czy jesteśmy w punkcie wejścia i czy powinniśmy z
niego wyjść. Nawet wtedy, gdy jest ktoś do zaatakowania, ponieważ nie chcemy zostać zamkni˛eci w pułapce wejścia.
• Reguła 2: Uciekaj, jeśli masz zginać.
˛
Przykładowy robot atakuje aż do śmierci. Ponieważ jednak wygrana zależy od liczby pozostałych robotów, a nie ich
zdrowia, bardziej opłaca si˛e zachować robota niż poświ˛ecać go, żeby zadał dodakowe obrażenia przeciwnikowi. Jeżeli
wi˛ec jesteśmy zagrożeni śmiercia,˛ uciekamy, a nie giniemy na próżno.
• Reguła 3: Atakuje przeciwnika o dwa kroki od ciebie.
6.6. RG – dokumentacja
193
Materiały eCG IT Documentation, Wydanie 1
Przyjrzyj si˛e grajacemu
˛
wg reguł robotowi, zauważysz, że kiedy wchodzi na pole atakowane przez przeciwnika,
odnosi obrażenia. Dlatego, jeśli prawdopodobne jest, że przeciwnik może znaleźć si˛e w naszym sasiedztwie,
˛
trzeba
go zatakować. Dzi˛eki temu nit si˛e do nas bezkarnie nie zbliży.
Informacja: Połaczenie
˛
ucieczki i ataku w kierunku przeciwnika naprawd˛e jest skuteczne. Każdy agresywny wróg
zanim nas zaatakuje, sam spotyka si˛e z atakiem. Jeżeli w por˛e odskoczysz, zanim si˛e zbliży, działanie takie możesz
powtórzyć. Technika ta nazywana jest w grach kiting, a jej działanie ilustruje poniższa animacja:
Zwróć uwag˛e na słabego robota ze zdrowiem 8 HP, który podchodzi do mocnego robota z 50 HP, a nast˛epnie ucieka.
Zbliżajac
˛ si˛e atakuje pole, na które wchodzi przeciwnik, ucieka i ponawia działanie. Trwa to do momentu, kiedy
silniejszy robot popełni samobójstwo (co w tym wypadku jest mało przydatne). Wszystko bez uszczerbku na zdrowiu
słabszego robota.
• Reguła 4: Wchodź tylko na wolne pola.
Przykładowy robot idzie do środka planszy, ale w wielu wypadkach lepiej zrobić coś innego. Np. iść tam, gdzie
jest bezpiecznie, zamiast narażać si˛e na bezużyteczne niebezpieczeństwo. Co jest bowiem ryzykowne? Po wejściu
na plansz˛e ruch na pole przeciwnika lub wchodzenie w jego sasiedztwo.
˛
Wiadomo też, że nie możemy wchodzić na
zaj˛ete pola i że możemy zmniejszyć ilość kolizji, nie wchodzac
˛ na pola zaj˛ete przez nasza˛ drużyn˛e.
• Reguła 5: Idź na wroga, jeżeli go nie ma w zasi˛egu dwóch kroków.
Po co iść do środka, skoro mamy inne bezpieczne możliwości? Wprawdzie stanie w punkcie wejścia jest złe, ale to
nie znaczy, że środek planszy jest dobry. Lepszym wyborem jest ruch w kierunku, ale nie na pole, przeciwnika. W
połaczeniu
˛
z atakiem daje nam to lepsza˛ kontrol˛e nad plansza.˛ Później przekonamy si˛e jeszcze, że sa˛ sytuacje, kiedy
wejście na potencjalnie niebezpieczne pole warte jest ryzyka, ale na razie poprzestańmy na tym, co ustaliliśmy.
Łaczenie
˛
ulepszeń
Zapiszmy wszystkie reguły w pseudokodzie. Możemy użyć do tego jednej rozbudowanej instrukcji warunkowej
if/else.
jeżeli jesteś w punkcie wejścia:
rusz si˛
e bezpiecznie (np. poza wejście)
jeżeli jeddnak mamy przeciwnika o krok dalej:
jeżeli możemy umrzeć:
ruszamy si˛
e w bezpieczne miejsce
w przeciwnym razie:
atakujemy przeciwnika
jeżeli jednak mamy przeciwnika o dwa kroki dalej:
atakujemy w jego kierunku
jeżeli mamy bezpieczny ruch (i nikogo wokół siebie):
ruszamy si˛
e bezpiecznie, ale w kierunku przeciwnika
w przeciwnym razie:
bronimy si˛
e w miejscu, bo nie ma gdzie ruszyć si˛
e lub atakować
Implementacja
Do zakodowania omówionej logiki potrzebujemy struktury danych gry z jej ustawieniami i kilku funkcji. Pami˛etajmy,
że jest wiele sobosobów na zapisanie kodu w Pythonie. Poniższy w żdanym razie nie jest optymalny, ale działa jako
przykład.
194
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Zbiory zamiast list
Dla ułatwienia użyjemy pythonowych zbiorów razem z funkcja˛ set() i wyrażeniami zbiorów (ang. set comprehensions).
Informacja: Zbiory i operacje na nich omówiono w dokumentacji zbiorów, podobnie przykłady wyrażeń listowych
i odpowiadajacych
˛
im p˛etli.
Podstawowe operacje na zbiorach, których użyjemy to:
• | lub suma – zwraca zbiór wszystkich elementów zbiorów;
• - lub różnica – zbiór elementów obecnych tylko w pierwszym zbiorze;
• & lub iloczyn – zwraca zbiór elementów wyst˛epujacych
˛
w obydwu zbiorach.
Załóżmy, że zaczniemy od wygenerowania nast˛epujacych
˛
list: drużyna – członkowie drużyny, wrogowie – przeciwnicy, wejścia – punkty wejścia oraz przeszkody – położenia zablokowane, tzn. szare kwadraty.
Zbiory pól
Aby ułatwić implementacj˛e omówionych ulepszeń, przygotujemy kilka zbiorów reprezentujacych
˛
pola różnych kategorii na planszy gry. W tym celu używamy wyrażeń listowych (ang. list comprehensions).
# zbiory pól na planszy
# wszystkie pola
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
# punkty wejścia (spawn)
wejscia = {loc for loc in wszystkie if 'spawn' in rg.loc_types(loc)}
# pola zablokowane (obstacle)
zablokowane = {loc for loc in wszystkie if 'obstacle' in rg.loc_types(loc)}
# pola zaj˛
ete przez nasze roboty
przyjaciele = {loc for loc in game.robots if game.robots[loc].player_id == self.player_id}
# pola zaj˛
ete przez wrogów
wrogowie = set(game.robots) - przyjaciele
Warto zauważyć, że zbiór wrogich robotów otrzymujemy jako różnic˛e zbioru wszystkich robotów i tych z naszej
drużyny.
Wykorzystanie zbiorów
Przy poruszaniu si˛e i atakowaniu mamy tylko cztery możliwe kierunki, które zwraca funkcja rg.locs_around.
Możemy wykluczyć położenia zablokowane (ang. obstacle), ponieważ nigdy ich nie zajmujemy i nie atakujemy.
Iloczyn zbiorów sasiednie & wrogowie da nam zbiór przeciwników w sasiedztwie:
˛
# pola sasiednie
˛
sasiednie = set(rg.locs_around(self.location)) - zablokowane
# pola sasiednie
˛
zaj˛
ete przez wrogów
wrogowie_obok = sasiednie & wrogowie
6.6. RG – dokumentacja
195
Materiały eCG IT Documentation, Wydanie 1
Aby odnaleźć wrogów oddalonych o dwa kroki, szukamy przyległych kwadratów, obok których sa˛ przeciwnicy. Wyłaczamy
˛
sasiednie
˛
pola zaj˛ete przez członków drużyny.
# pola zaj˛
ete przez wrogów w odległości 2 kroków
wrogowie_obok2 = {loc for loc in sasiednie if (set(rg.locs_around(loc)) & wrogowie)} - przyjaciele
Teraz musimy sprawdzić, które z położeń sa˛ bezpieczne. Usuwamy pola zajmowane przez przeciwników w odległości
1 i 2 kroków. Pozbywamy si˛e także punktów wejścia, nie chcemy na nie wracać. Podobnie, aby zmniejszyć możliwość kolizji, wyrzucamy pola zajmowane przez drużyn˛e. W miar˛e komplikowania logiki b˛edzie można zastapić
˛ to
ograniczenie dodatkowym warunkiem, ale na razie to najlepsze, co możemy zrobić.
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 - wejscia - przyjaciele
Potrzebujemy funkcji, która wybierze ze zbioru położeń pole najbliższe podanego. Możemy użyć tej funkcji do znajdowania najbliższego wroga, jak również do wyboru pola z bezpiecznej listy. Możemy wi˛ec wybrać ruch najbardziej
przybliżajacy
˛ nas do założonego celu.
def mindist(bots, loc):
return min(bots, key=lambda x: rg.dist(x, loc))
Możemy użyć metody pop() zbioru, aby pobrać jego dowolny element, np. przeciwnika, którego zaatakujemy. Żeby
dowiedzieć si˛e, czy jesteśmy zagrożeni śmiercia,˛ możemy pomnożyć liczb˛e sasiaduj
˛
acych
˛
przeciwników przez średni
poziom uszkodzeń (9 punktów HP) i sprawdzić, czy mamy wi˛ecej siły.
Ze wzgl˛edu na sposób napisania funkcji minidist() trzeba pami˛etać o przekazywaniu jej niepustych zbiorów. Jeśli
np. zbiór przeciwników b˛edzie pusty, funkcja zwróci bład.
˛
Składamy wszystko razem
Po złożeniu wszystkich kawałków kodu razem otrzymujemy przykładowa˛ implemetacj˛e robota wyposażonego we
wszystkie założone wyżej właściwości:
1
2
#! /usr/bin/env python
# -*- coding: utf-8 -*-
3
4
import rg
5
6
class Robot:
7
def act(self, game):
8
9
wszystkie = {(x, y) for x in xrange(19) for y in xrange(19)}
wejscia = {poz for poz in wszystkie if 'spawn' in rg.loc_types(poz)}
zablokowane = {poz for poz in wszystkie if 'obstacle' in rg.loc_types(poz)}
przyjaciele = {poz for poz in game.robots if game.robots[poz].player_id == self.player_id}
wrogowie = set(game.robots) - przyjaciele
10
11
12
13
14
15
sasiednie = set(rg.locs_around(self.location)) - zablokowane
wrogowie_obok = sasiednie & wrogowie
wrogowie_obok2 = {poz for poz in sasiednie if (set(rg.locs_around(poz)) & wrogowie)} - przyja
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 - wejscia - przyjaciele
16
17
18
19
20
def mindist(bots, poz):
return min(bots, key=lambda x: rg.dist(x, poz))
21
22
23
if wrogowie:
najblizszy_wrog = mindist(wrogowie,self.location)
else:
24
25
26
196
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
27
najblizszy_wrog = rg.CENTER_POINT
28
29
30
# działanie domyślne:
ruch = ['guard']
31
32
33
34
35
36
37
38
39
40
41
42
43
44
if self.location in wejscia:
if bezpieczne:
ruch = ['move', mindist(bezpieczne, rg.CENTER_POINT)]
elif wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
if bezpieczne:
ruch = ['move', mindist(bezpieczne, rg.CENTER_POINT)]
else:
ruch = ['attack', wrogowie_obok.pop()]
elif wrogowie_obok2:
ruch = ['attack', wrogowie_obok2.pop()]
elif bezpieczne:
ruch = ['move', mindist(bezpieczne, najblizszy_wrog)]
45
46
return ruch
Informacja: Niniejsza dokumentacja jest swobodnym i nieautoryzowanym tłumaczeniem materiałów dost˛epnych na
stonie Robotgame basic strategy.
6.6.6 Strategia pośrednia
Zacznijmy od znanego
W poprzednim poradniku (Strategia podstawowa) zacz˛eliśmy od bota realizujacego
˛
nast˛epujace
˛ zasady:
• Broń si˛e w środku planszy
• Atakuj wrogów obok
• Idź do środka
Zmieniliśmy lub dodaliśmy nast˛epujace
˛ reguły:
• Opuść wejście
• Uciekaj, jeśli masz zginać
˛
• Atakuj wrogów dwa kroki obok
• Wchodź na bezpieczne, niezaj˛ete pola
• Idź na wroga, jeśli w pobliżu go nie ma
Do powyższych dodamy kolejne reguły w postaci fragmentów kodu, które trzeba zintergrować z dotychczasowa˛ implementacja˛ bota, aby go ulepszyć.
Śledź wybierane miejsca
To raczej złożona funkcja, ale jest potrzebna, aby zmniejszyć ilość kolizji. Dotychczasowe boty drużyny próbuja˛
wejść na to samo miejsce i atakuja˛ si˛e nawzajem. Co prawda nie tracimy wtedy pukntów życia, ale (prawie) zawsze
mamy lepszy wybór. Jeżeli b˛edziemy śledzić wszystkie wybrane przez nas ruchy w ramach rundy, możemy uniknać
˛
niepotrzebnych kolizji. Niestety, to wymaga wielu fragementów kodu.
6.6. RG – dokumentacja
197
Materiały eCG IT Documentation, Wydanie 1
Na poczatku
˛ dodamy zmienna,˛ która posłuży do sprawdzenia, czy dany robot jest pierwszym wywoływanym w rundzie. Jeżeli tak, musimy wyczyścić list˛e poprzednich ruchów i zaktualizować licznik rund. Odpowiedni kod trzeba
umieścić na poczatku
˛ metody Robot.act:
Uwaga: Trzeba zainicjować zmienna˛ globalna˛ runda_numer.
global runda_numer, wybrane_pola
if game.turn != runda_numer:
runda_numer = game.turn
wybrane_pola = set()
Kolejne fragmenty odpowiadać b˛eda˛ za zapami˛etywanie wykonywanych ruchów. Kod najwygodniej umieścić w pojedynczych funkcjach, które zanim zwróca˛ wybrany ruch, zapisza˛ go na liście. Warto zauważyć, że zapisywane b˛eda˛
współrz˛edne pól, na które wchodzimy lub na których pozostajemy (obrona, atak, samobójstwo). Funkcje musza˛ znaleźć si˛e w metodzie Robot.act, aby współdzieliły jej przestrzeń nazw.
# Jeżeli si˛
e ruszamy, zapisujemy docelowe pole
def ruszaj(loc):
wybrane_pola.add(loc)
return ['move', loc]
# Jeżeli pozostajemy w miejscu, zapisujemy aktualne położenie
# przy użyciu self.location
def stoj(act, loc=None):
wybrane_pola.add(self.location)
return [act, loc]
Nast˛epnym krokiem jest usuni˛ecie listy wybrane_pola ze zbioru bezpiecznych pól, które sa˛ podstawa˛ dalszych
wyborów:
bezpieczne = sasiednie - wrogowie_obok - wrogowie_obok2 \
- wejscia - przyjaciele - wybrane_pola
Roboty atakujace
˛ przeciwnika o dwa kroki obok cz˛esto go otaczaja˛ (to dobrze), ale jednocześnie blokuja˛ innych członków drużyny. Dlatego możemy wykluczać ataki na pola wrogowie_obok2, jeśli znajduja˛ si˛e na liście wykonanych
ruchów.
[Robots that attack two moves away often form a perimeter around the enemy (a good thing) but it prevents your own
bots from run across the line. For that reason we can choose to not let a robot do an an adjacent_enemy2 attack if they
are sitting in a taken spot.]
elif wrogowie_obok2 and self.location not in wybrane_pola:
Na koniec podmieniamy kod zwracajacy
˛ ruchy:
ruch = ['move', mindist(bezpieczne, najblizszy_wrog)]
ruch = ['attack', wrogowie_obok.pop()]
– tak aby wykorzystywał nowe funkcje:
ruch = ruszaj(mindist(bezpieczne, najblizszy_wrog))
ruch = stoj('attack', wrogowie_obok.pop())
Warto pami˛etać, że roboty nie moga˛ zamieniać si˛e miejscami. Wprawdzie jest możliwe zakodowanie tego, ale zamiana
nie dojdzie do skutku.
198
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
Atakuj najsłabszego wroga
Każdy udany atak zmniejsza punkty HP wrogów tak samo, ale wynik gry zależy od liczby pozostałych przy życiu
robotów, a nie od ich żywotności. Dlatego korzystniejsze jest wyeliminowanie słabego bota niż atakowanie/osłabienie
silnego. Odpowiednia˛ funkcj˛e umieścimy w funkcji Robot.act i użyjemy do wyboru robota z listy zamiast dotychczasowej funkcji .pop(), która zwracała losowe roboty.
# funkcja znajdujaca
˛
najsłabszego robota
def minhp(bots):
return min(bots, key=lambda x: robots[x].hp)
elif wrogowie_obok:
...
else:
ruch = stoj('attack', minhp(wrogowie_obok))
Samobójstwo lepsze niż śmierć
Na razie usiłujemy uciec, jeżeli grozi nam śmierć, ale czasami może si˛e nam nie udać, bo natkniemy si˛e na atakuja˛
cego wroga. Jeżeli brak bezpiecznego ruchu, a grozi nam śmierć, o ile pozostaniemy w miejscu, możemy popełnić
samobójstwo, co osłabi wrogów bardziej niż atak.
elif wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
if bezpieczne:
ruch = ruszaj(mindist(safe, rg.CENTER_POINT))
else:
ruch = stoj('suicide')
else:
ruch = stoj('attack', minhp(wrogowie_obok))
Unikaj nierównych starć
W walce jeden na jednego nikt nie ma przewagi, ponieważ wróg może odpowiadać atakiem na każdy nasz atak,
jeżeli jesteśmy obok. Ale gdy wróg ma liczebna˛ przewag˛e, atakujac
˛ dwoma robotami naszego jednego, dostaniemy
podwójnie za każdy wyprowadzony atak. Dlatego należy uciekać, jeśli wrogów jest wi˛ecej. Warto zauważyć, że jest to
kluczowa zasada w da˛żeniu do zwyci˛estwa w Grze robotów, nawet w rozgrywkach na najwyższym poziomie. Walka
z wykorzystaniem przewagi jest zreszta˛ warunkiem wygranej w wi˛ekszości pojedynków.
elif wrogowie_obok:
if 9*len(wrogowie_obok) >= self.hp:
...
elif len(wrogowie_obok) > 1:
if bezpieczne:
ruch = ruszaj(mindist(safe, rg.CENTER_POINT))
else:
ruch = stoj('attack', minhp(wrogowie_obok))
Goń słabe roboty
Możemy założyć, że słabe roboty b˛eda˛ uciekać. Zamiast atakować podczas ucieczki, powinniśmy je gonić. W ten
sposób możemy wymusić kolejny ruch w nast˛epnej turze, dzi˛eki czemu trafia˛ być może w gorsze miejsce. Bierzemy
6.6. RG – dokumentacja
199
Materiały eCG IT Documentation, Wydanie 1
pod uwag˛e roboty, które maja˛ maksymalnie 5 punktów HP, nawet gdy zaatakuja˛ zamiast uciekać, zgina˛ w wyniku
uszkodzeń z powodu kolizji.
elif wrogowie_obok:
...
else:
cel = minhp(wrogowie_obok)
if game.robots[cel].hp <= 5:
ruch = ruszaj(cel)
else:
ruch = stoj('attack', minhp(wrogowie_obok))
Trzeba pami˛etać, że startegia gonienia słabego robota ma jedna˛ oczywista˛ wad˛e. Jeżeli słaby robot wybierzez obron˛e,
goniacy
˛ odniesie uszkodzenia z powodu kolizji, broniacy
˛ nie. Można temu przeciwdziałać wybierajac
˛ atak, a nie
pogoń – koło si˛e zamyka.
Podsumowanie
Poniżej zestawienie reguł, które dodaliśmy:
• Śledź wybierane miejsca
• Atakuj najsłabszego wroga
• Samobójstwo lepsze niż śmierć
• Unikaj nierównych starć
• Goń słabe roboty
Dodanie powyższych zmian umożliwi stworzenie robota podobnego do simplebot z pakietu open-source. Sprawdź
jego kod, aby ulepszyć swojego. Do tej pory tworzyliśmy robota walczacego
˛
według zbioru kilku reguł, ale w nast˛epnym materiale poznamy roboty inaczej decydujace
˛ o ruchach, dodatkowo wykorzystujace
˛ kilka opartych na zasadach
sztuczek.
Jeśli jesteś gotów, sprawdź “Zaawansowane strategie” (już wkrótce...)
Informacja: Niniejsza dokumentacja jest swobodnym i nieautoryzowanym tłumaczeniem materiałów dost˛epnych na
stonie Robotgame Intermediate Strategy.
Informacja: Niniejsza dokumentacja jest nieautoryzowanym tłumaczeniem oficjalnej dokumentacji dost˛epnej na
stronie RobotGame oraz materiałów dodatkowych dost˛epnych na stronie robotgame robots and scripts.
6.7 Słownik Pythona
j˛ezyk interpretowany j˛ezyk, który jest tłumaczony i wykonywany “w locie”, np. Python lub PHP. Tłumaczeniem i
wykonywaniem programu zajmuje si˛e specjalny program nazwany interpreterem j˛ezyka.
interpreter program, który analizuje kod źródłowy, a nast˛epnie go wykonuje. Interpretery sa˛ podstawowym składnikiem j˛ezyków wykorzystywanych do pisania skryptów wykonywanych po stronie klienta WWW (JavaScript)
lub serwera (np. Python, PHP).
Interpreter Pythona jest interaktywny, tzn. można w nim wydawać polecenia i obserwować ich działanie, co
pozwala wygodnie uczyć si˛e i testować oprogramowanie. Uruchamiany jest w terminalu, zazwyczaj za pomoca˛
polecenia python.
200
Rozdział 6. Gra robotów
Materiały eCG IT Documentation, Wydanie 1
formatowanie kodu Python wymaga formatowania kodu za pomoca˛ wci˛eć, podstawowym wymogiem jest stosowanie takich samych wci˛eć w obr˛ebie pliku, np. 4 spacji i ich wielokrotności. Wci˛ecia odpowiadaja˛ nawiasom
w innych j˛ezykach, służa˛ grupowaniu instrukcji i wydzielaniu bloków kodu. Bł˛edy wci˛eć zgłaszane sa˛ jako
wyjatki
˛ IndentationError.
zmienna nazwa określajaca
˛ jakaś
˛ zapami˛etywana˛ i wykorzystywana˛ w programie wartość lub struktur˛e danych.
Zmienna może przechowywać pojedyncze wartości określonego typu, np.: imie = "Anna", jak i rozbudowane struktury danych, np.: imiona = (’Ala’, ’Ola’, ’Ela’). W nazwach zmiennych nie używamy
znaków narodowych, nie rozpoczynamy ich od cyfr.
typy danych Wszystkie dane w Pythonie sa˛ obiektami i jako takie przynależa˛ do określonego typu, który determinuje możliwe na nich operacje. W pewnym uproszczeniu podstawowe typy danych to: string – napis (łańcuch
znaków), podtyp sekwencji; integer – dodatnie i ujemne liczby całkowite; float – liczba zmiennoprzecinkowa
(separatorem jest kropka); boolean – wartość logiczna True (prawda, 1) lub False (fałsz, 0), podtyp typu całkowitego.
operatory Arytmetyczne: +, -, *, /, //, %, ** (pot˛egowanie); znak + znak (konkatenacja napisów); znak * 10
(powielenie znaków); Przypisania: =, +=, -=, *=, /=, %=, **=, //=; Logiczne: and, or, not; Fałszem logicznym
sa:
˛ liczby zero (0, 0.0), False, None (null), puste kolekcje ([], (), {}, set()), puste napisy. Wszystko inne jest
prawda˛ logiczna.˛ Zawierania: in, not in; Porównania: ==, >, <, <>, <=, >= != (jest różne).
Operator * rozpakowuj˛e list˛e paramterów przekazana˛ funkcji. Operator ** rozpakuje słownik.
lista jedna z podstawowych struktur danych, indeksowana sekwencja takich samych lub różnych elementów, które
można zmieniać. Przypomina tabele z innych j˛ezyków programowania. Np. imiona = [’Ala’, ’Ola’,
’Ela’]. Deklaracja pustej listy: lista = [].
tupla podbnie jak lista, zawiera indeksowana˛ sekwencj˛e takich samych lub różnych elementów, ale nie można ich
zmieniać. Cz˛esto służy do przechowywania lub przekazywania ustawień, stałych wartości itp. Np. imiona =
(’Ala’, ’Ola’, ’Ela’). 1-elementowa˛ tupl˛e należy zapisywać z dodatkowym przecinkiem: tupla1
= (1,).
zbiór nieuporzadkowany,
˛
nieindeksowany zestaw elementów tego samego lub różnych typów, nie może zawierać
duplikatów, obsługuje charakterystyczne dla zbiorów operacje: sum˛e, iloczyn oraz różnic˛e. Np. imiona =
set([’Ala’, ’Ola’, ’Ela’]). Deklaracja pustego zbioru: zbior = set().
słownik typ mapowania, zestaw par elementów w postaci “klucz: wartość”. Kluczami moga˛ być liczby, ciagi
˛ znaków
czy tuple. Wartości moga˛ być tego samego lub różnych typów. Np. osoby = {’Ala’: ’Lipiec’ ,
’Ola’: ’Maj’, ’Ela’: ’Styczeń’}. Dane ze słownika łatwo wydobyć: slownik[’klucz’],
lub zmienić: slownik[’klucz’] = wartosc. Deklaracja pustego słownika: slownik = dict().
instrukcja warunkowa podstawowa konstrukcja w programowaniu, wykorzystuje wyrażenie logiczne przyjmujace
˛
wartość True (prawda) lub False (fałsz) do wyboru odpowiedniego działania. Umożliwia rozgałezianie kodu.
Np.:
if wiek < 18:
print "Treść zabroniona"
else:
print "Zapraszamy"
p˛etla podstawowa konstrukcja w programowaniu, umożliwia powtarzanie fragmentów kodu zadana˛ ilość razy (p˛etla
for) lub dopóki podane wyrażenie logiczne jest prawdziwe (p˛etla while). Należy zadbać, aby p˛etla była
skończona za pomoca˛ odpowiedniego warunku lub instrukcji przeywajacej
˛ powtarzanie. Np.:
for i in range(11):
print i
zmienna iteracyjna zmienna wyst˛epujaca
˛ w p˛etli, której wartość zmienia si˛e, najcz˛eściej jest zwi˛ekszana (inkremntacja) o 1, w każdym wykonaniu p˛etli. Może pełnić rol˛e “licznika” powtórzeń lub być elementem wyrażenia
logicznego wyznaczajacego
˛
koniec działania p˛etli.
6.7. Słownik Pythona
201
Materiały eCG IT Documentation, Wydanie 1
iteratory (ang. iterators) – obiekt reprezentujacy
˛ sekwencj˛e danych, zwracajacy
˛ z niej po jednym elemencie na raz
przy użyciu metody next(); jeżeli nie ma nast˛epnego elementu, zwracany jest wyjatek
˛ StopIteration.
Funkcja iter() potrafi zwrócić iterator z podanego obiektu.
generatory wyrażeń (ang. generator expressions) – zwi˛ezły w notacji sposób tworzenia iteratorów według składni:
( wyrażenie for wyraz in sekwencja if warunek )
wyrażenie listowe (ang. list comprehensions) – efektywny sposób tworzenia list na podstawie elementów dowolnych sekwencji, na których wykonywane sa˛ te same operacje i które opcjonalnie spełniaja˛ określone warunki.
Składnia: [ wyrażenie for wyraz in sekwencja if warunek ]
mapowanie funkcji w kontekście funkcji map() oznacza zastosowanie danej funkcji do wszystkich dostarczonych
wartości
wyrażenia lambda zwane czasem funkcjami lambda, sposób zwi˛ezłego zapisywania prostych funkcji w postaci
pojedynczych wyrażeń
filtrowanie danych selekcja danych na podstawie jakichś kryteriów
wyjatki
˛
to komunikaty zgłaszane przez interpreter Pythona, pozwalajace
˛ ustalić przyczyny bł˛ednego działania kodu.
funkcja blok cz˛esto wykonywanego kodu wydzielony słowem kluczowym def, opatrzony unikalna˛ w danym zasi˛egu nazwa;
˛ może przyjmować dane i zwracać wartości za pomoca˛ słowa kluczowego return.
moduł plik zawierajacy
˛ wiele zazwyczaj cz˛esto używanych w wielu programach funkcji lub klas; zanim skorzystamy
z zawartych w nim fragmentów kodu, trzeba je lub cały moduł zaimportować za pomoca˛ słowa kluczowego
import.
serializacja proces przekształcania obiektów w strumień znaków lub bajtów, który można zapisać w pliku (bazie)
lub przekazać do innego programu.
202
Rozdział 6. Gra robotów
ROZDZIAŁ 7
Galerie
7.1 GetSimple CMS
7.1.1 Instalacja
7.2 Metryka
Autor Robert Bednarz ([email protected])
Utworzony 2015-07-18 o 04:24
203
Materiały eCG IT Documentation, Wydanie 1
204
Rozdział 7. Galerie
ROZDZIAŁ 8
Indeks
• genindex
205
Materiały eCG IT Documentation, Wydanie 1
206
Rozdział 8. Indeks
Indeks
Symbols
iteratory, 163, 202
środowisko IDE, 27
środowisko graficzne, 28
J
A
j˛ezyk interpretowany, 162, 200
JavaScript, 104
JSON, 164
AJAX, 104
API, 164
aplikacja, 155
B
K
Klasa, 91, 93
kontroler, 157
baza danych, 157
L
C
lista, 162, 201
logowanie, 157
CMS, 104
CSS, 104, 157
D
Debian, 27
F
filtrowanie danych, 163, 202
formatowanie kodu, 162, 201
framework, 28, 104, 157
funkcja, 163, 202
G
generatory wyrażeń, 163, 202
GET, 157
GNU Compiler Collection, 27
GPL, 27
H
HTML, 103, 157
HTTP, 157
HTTP(S), 103
I
instrukcja warunkowa, 163, 201
interpreter, 28, 104, 162, 200
M
mapowanie funkcji, 163, 202
MinGw, 27
model, 157
moduł, 163, 202
O
Obiekt, 91, 93
operatory, 162, 201
ORM, 157
P
p˛etla, 163, 201
PHP, 104
plik źródłowy, 91, 93
plik nagłówkowy, 91, 93
POST, 157
private, 91, 93
public, 91, 93
Python, 104
Q
Qt, 27, 91, 93
Qt Creator, 27, 91, 93
207
Materiały eCG IT Documentation, Wydanie 1
S
słownik, 162, 201
serializacja, 163, 202
serwer deweloperski (testowy), 157
serwer WWW, 28, 104, 157
sloty, 91, 93
sygnały, 91, 93
system bazodanowy, 28, 104
szablon, 157
T
terminal, 163
tupla, 162, 201
typy danych, 162, 201
U
URL, 157
W
widok, 157
WWW, 103
wyjatki,
˛ 163, 202
wyrażenia lambda, 163, 202
wyrażenie listowe, 163, 202
X
XML, 104
Xubuntu 14.04, 27
Z
zbiór, 162, 201
zmienna, 162, 201
zmienna iteracyjna, 163, 201
208
Indeks

Podobne dokumenty