3. Nieformalne wprowadzenie do Pythona
**************************************

W nadchodzących przykładach wejście i wyjście są rozróżniane przez
obecność lub nieobecność promptów (*>>>* i *...*): aby powtórzyć
przykład, musisz wpisać wszystko po prompcie, kiedy prompt jest
widoczny; linie, które nie zaczynają się promptem są wyjściem z
interpretera. Zwróć uwagę, że prompt drugiego rzędu z pustą linią w
przykładzie oznacza, że musisz wpisać pustą linię; używa się tego do
zakończenia wielo-liniowej komendy.

Wiele przykładów w tej instrukcji, także tych wpisywanych w konsoli
interaktywnej, zawiera komentarze. Komentarze w Pythonie zaczynają się
znakiem hash "#" i ciągną się do końca fizycznej linii. Komentarz może
pojawić się na początku linii, po wiodących spacjach lub kodzie, lecz
nie może być zawarty w literale ciągu znaków. Znak hash w ciągu znaków
jest po prostu znakiem hash. Jako że komentarze mają wyjaśniać kod i
nie są interpretowane przez Pythona, można je ominąć przy wpisywaniu
przykładów.

Trochę przykładów:

   # to jest pierwszy komentarz
   spam = 1  # a to jest drugi komentarz
             # … i teraz trzeci!
   text = "# To nie jest komentarz, bo jest w cudzysłowie."


3.1. Używanie Pythona jako kalkulatora
======================================

Wypróbujmy parę prostych poleceń Pythona. Uruchom interpreter i
poczekaj na pojawienie się pierwszego znaku zachęty ">>>". (Nie
powinno to zająć dużo czasu.)


3.1.1. Liczby
-------------

Interpreter działa jak prosty kalkulator: można wpisać do niego
wyrażenie, a on wypisze jego wartość. Składnia wyrażenia jest prosta:
operatory "+", "-", "*" i "/" można użyć do arytmetyki; nawiasy ("()")
można użyć do grupowania. Na przykład:

   >>> 2 + 2
   4
   >>> 50 - 5*6
   20
   >>> (50 - 5*6) / 4
   5.0
   >>> 8 / 5  # dzielenie zawsze zwraca liczbę zmiennoprzecinkową
   1.6

Liczby całkowite (np. "2", "4", "20") są typu "int", te z częścią
ułamkową (np. "5.0", "1.6") są typu "float". Więcej o typach
numerycznych dowiemy się więcej później w tym tutorialu.

Dzielenie ("/") zawsze zwraca liczbę zmiennoprzecinkową. Aby zrobić
*dzielenie całkowite* i uzyskać wynik całkowity możesz użyć operatora
"//"; aby obliczyć resztę możesz użyć "%":

   >>> 17 / 3  # klasyczne dzielenie zwraca liczbę zmiennoprzecinkową
   5.666666666666667
   >>>
   >>> 17 // 3  # dzielenie całkowite pomija część ułamkową
   5
   >>> 17 % 3  # operator % zwraca resztę z dzielenia
   2
   >>> 5 * 3 + 2  # iloraz całkowity * dzielnik + reszta
   17

W Pythonie możesz użyć operatora "**", do obliczania potęgowania [1]:

   >>> 5 ** 2  # 5 do kwadratu
   25
   >>> 2 ** 7  # 2 do potęgi 7.
   128

Znak równości ("=") jest używany do przypisania wartości do zmiennej.
Przypisanie do zmiennej nie jest wypisywane przez interpreter:

   >>> width = 20
   >>> height = 5 * 9
   >>> width * height
   900

Jeśli zmienna nie jest „zdefiniowana” (nie ma przypisanej wartości),
próba jej użycia spowoduje błąd:

   >>> n  # próba dostępu do niezdefiniowanej zmiennej
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   NameError: name 'n' is not defined

Python implementuje w pełni arytmetykę zmiennoprzecinkową; operatory z
operandami typów mieszanych przekształcają operandy całkowite w
zmiennoprzecinkowe:

   >>> 4 * 3.75 - 1
   14.0

W trybie interaktywnym ostatnie wyświetlone wyrażenie jest
przypisywane do zmiennej "_". Dzięki temu kiedy używasz Pythona jako
biurkowego kalkulatora, jest nieco prościej kontynuować obliczenia, na
przykład:

   >>> tax = 12.5 / 100
   >>> price = 100.50
   >>> price * tax
   12.5625
   >>> price + _
   113.0625
   >>> round(_, 2)
   113.06

Ta zmienna powinna być traktowana przez użytkownika jako tylko-do-
odczytu. Nie przypisuj wprost do niej wartości --- stworzyłbyś
niezależną zmienną lokalną o tej samej nazwie maskując wbudowaną
zmienną z jej magicznym zachowaniem.

Oprócz "int" i "float", Python wspiera inne typy liczb, takie jak
"Decimal" i "Fraction". Python ma też wbudowane wsparcie dla liczb
zespolonych i używa sufiksów "j" lub "J" do wskazania części urojonej
(np. "3+5j").


3.1.2. Tekst
------------

Python umożliwia manipulację tekstem (reprezentowanym przez typ "str",
tzw. „ciąg znaków” lub „string”) oraz liczbami. Obejmuje to znaki
„"!"”, słowa „"królik"”, nazwy „"Paryż"”, zdania „"Możesz na mnie
liczyć."”, itp. „"Hurra! :)"”. Mogą być one umieszczone w pojedynczych
cudzysłowach ("'...'") lub podwójnych cudzysłowach (""..."") z takim
samym wynikiem [2].

   >>> 'spam eggs'  # pojedynczy cudzysłów
   'spam eggs'
   >>> "Paris rabbit got your back :)! Yay!"  # podwójny cudzysłów
   'Paris rabbit got your back :)! Yay!'
   >>> '1975'  # cyfry i liczby ujęte w cudzysłów są również ciągami znaków
   '1975'

Aby umieścić znak cudzysłowu, musimy go oznaczyć znakiem "ucieczki",
poprzedzając znakiem "\". Alternatywnie, możemy użyć innego rodzaju
znaków do oznaczenia cudzysłowu:

   >>> 'Oni powiedzieli \'tak\'.'  # użyj \' jako znaku ucieczki da pojedynczego cudzysłowu…
   "Oni powiedzieli 'tak'."
   >>> "Oni powiedzieli 'tak'."  # …lub użyj podwójnego cudzysłowu
   "Oni powiedzieli 'tak'."
   >>> 'Oni powiedzieli "tak".'
   'Oni powiedzieli "tak".'
   >>> "Oni powiedzieli \"tak\"."
   'Oni powiedzieli "tak".'
   >>> 'Oni powiedzieli "tamci powiedzieli \'tak\'".'
   'Oni powiedzieli "tamci powiedzieli \'tak\'".'

W interaktywnej powłoce Pythona definicja ciągu znaków i wyjściowy
ciąg znaków mogą wyglądać inaczej. Funkcja "print()" wytwarza czytelne
wyjście, poprzez pominięcie otaczających cudzysłowów, pominięcie
znaków ucieczki i wypisanie znaków specjalnych:

   >>> s = 'Pierwsza linia.\nDruga linia.'  # \n oznacza nową linię
   >>> s  # bez print(), znaki specjalne są zawarte w ciągu znaków
   'Pierwsza linia.\nDruga linia.'
   >>> print(s)  # z print(), znaki specjalne są interpretowane, więc \n tworzy nową linię
   Pierwsza linia.
   Druga linia.

Jeśli nie chcesz, aby znaki poprzedzone "\" były interpretowane jako
znaki specjalne, możesz użyć *surowych ciągów znaków* (ang. *raw
strings*) dodając "r" przed pierwszym cudzysłowem:

   >>> print('C:\jakas\nazwa')  # tutaj \n oznacza nową linię!
   C:\jakas
   azwa
   >>> print(r'C:\jakas\nazwa')  # zwróć uwagę na r przed cudzysłowem
   C:\jakas\nazwa

Istnieje jeden subtelny aspekt surowych ciągów znaków: surowy ciąg
znaków nie może kończyć się nieparzystą liczbą znaków "\"; zobacz wpis
FAQ, aby uzyskać więcej informacji i sposobów obejścia tego problemu.

Literał ciągu znaków może obejmować wiele linii. Jednym ze sposobów
jest użycie potrójnych cudzysłowów: """"..."""" lub "'''...'''". Znaki
końca linii są automatycznie dołączane do napisów, ale można temu
zapobiec, dodając "\" na końcu linii. W poniższym przykładzie
początkowy znak nowej linii nie jest uwzględniony:

   >>> print("""\
   ... Użycie: cosiek [OPCJE]
   ...      -h                        Wyświetl tą wiadomość użycia
   ...      -H hostname               Nazwa hosta do połączenia
   ... """)
   Użycie: cosiek [OPCJE]
        -h                        Wyświetl tą wiadomość użycia
        -H hostname               Nazwa hosta do połączenia

   >>>

Ciągi mogą być łączone operatorem "+" i powtarzane przy użyciu "*":

   >>> # 3 razy 'un', a następnie 'ium'
   >>> 3 * 'un' + 'ium'
   'unununium'

Dwa lub więcej *literały ciągu znaków* (czyli te zawarte w
cudzysłowach) obok siebie są automatycznie łączone.

   >>> 'Py' 'thon'
   'Python'

To zachowanie jest szczególnie przydatne, gdy chcesz dzielić długie
ciągi:

   >>> text = ('Umieść kilka ciągów znaków w nawiasach '
   ...         'aby je połączyć.')
   >>> text
   'Umieść kilka ciągów znaków w nawiasach aby je połączyć'.

Jednak działa tylko dla literałów, nie dla zmiennych lub wyrażeń:

   >>> prefix = 'Py'
   >>> prefiks 'thon'  # nie można łączyć zmiennej i literału ciagu znaków
     File "<stdin>", line 1
       prefix 'thon'
              ^^^^^^
   SyntaxError: invalid syntax
   >>> ('un' * 3) 'ium'
     File "<stdin>", line 1
       ('un' * 3) 'ium'
                  ^^^^^
   SyntaxError: invalid syntax

Jeśli chcesz połączyć zmienne lub zmienną i literał, użyj "+":

   >>> prefix + 'thon'
   'Python'

Ciągi znaków mogą być *indeksowane*. Pierwszy znak ma indeks 0. Nie ma
osobnego typu znakowego; znak jest po prostu ciągiem znaków o długości
jeden:

   >>> word = 'Python'
   >>> word[0]  # znak na pozycji 0
   'P'
   >>> word[5]  # znak na pozycji 5
   'n'

Indeksy mogą być też liczbami ujemnymi, aby zacząć odliczać od prawej:

   >>> word[-1]  # ostatni znak
   'n'
   >>> word[-2]  # przedostatni znak
   'o'
   >>> word[-6]
   'P'

Zwróć uwagę, że jako -0 to to samo co 0, ujemne indeksy zaczynają się
od -1.

Dodatkowo do indeksowania, obsługiwany jest również *podział*. Podczas
gdy indeksowanie służy do uzyskiwania pojedynczych znaków, *podział*
pozwala na uzyskanie podciągu znaków:

   >>> word[0:2]  # znaki od pozycji 0 (włącznie) do 2 (wyłącznie)
   'Py'
   >>> word[2:5]  # znaki od pozycji 2 (włącznie) do 5 (wyłącznie)
   'tho'

Indeksy podzielonych fragmentów mają przydatne wartości domyślne;
pominięty pierwszy indeks domyślnie jest zerem, pominięty drugi indeks
domyślnie ma wartość długości dzielonego stringa.

   >>> word[:2]  # znak od początku do pozycji 2 (wyłącznie)
   'Py'
   >>> word[4:]  # znak od pozycji 4 (włącznie) do końca
   'on'
   >>> word[-2:]  # znak od przedostatniego (włącznie) do końca
   'on'

Zwróć uwagę, że początkowy indeks wchodzi w skład podciągu, a końcowy
nie. W ten sposób "s[:i] + s[i:]" jest zawsze równe "s":

   >>> word[:2] + word[2:]
   'Python'
   >>> word[:4] + word[4:]
   'Python'

Jednym ze sposobów na zapamiętanie, jak działa podział, to myślenie o
indeksach wskazujących *pomiędzy* znakami, z lewą krawędzią pierwszego
znaku numerowaną 0. Wtedy prawa krawędź ostatniego znaku ciągu o
długości *n* ma indeks *n*, na przykład:

    +---+---+---+---+---+---+
    | P | y | t | h | o | n |
    +---+---+---+---+---+---+
    0   1   2   3   4   5   6
   -6  -5  -4  -3  -2  -1

W pierwszym wierszu liczb są pozycje indeksów od 0 do 6 w ciągu. W
drugim wierszu odpowiadające im indeksy ujemne. Fragment od *i* do *j*
składa się ze wszystkich znaków pomiędzy krawędziami oznaczonymi
kolejno *i* i *j*.

Dla nieujemnych indeksów długość wydzielonego fragmentu to różnica
indeksów, jeśli oba mieszczą się w zakresie. Na przykład długość
"word[1:3]" to 2.

Próba użycia za dużego indeksu skończy się błędem:

   >>> word[42]  # word ma tylko 6 znaków
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   IndexError: string index out of range

Jednak indeksy podzielonych fragmentów poza zakresem są obsłużone
bezpiecznie przy podziale:

   >>> word[4:42]
   'on'
   >>> word[42:]
   ''

Ciągi znaków Pythona nie mogą być zmieniane — są *niemutowalne*. W
związku z tym przypisywanie wartości do indeksowanej pozycji w ciągu
spowoduje błąd:

   >>> word[0] = 'J'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment
   >>> word[2:] = 'py'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment

Jeśli potrzebujesz innego ciągu znaków, powinieneś(-nnaś) stworzyć
nowy:

   >>> 'J' + word[1:]
   'Jython'
   >>> word[:2] + 'py'
   'Pypy'

Wbudowana funkcja "len()" zwraca długość ciągu:

   >>> s = 'superkalifradalistodekspialitycznie'
   >>> len(s)
   35

Zobacz także:

  Text Sequence Type --- str
     Ciągi znaków są przykładami *typów sekwencyjnych* i obsługują
     wspólne operacje wspierane przez takie typy.

  Metody ciągów
     Ciągi znaków wspierają dużą liczbę metod do podstawowych
     przekształceń i wyszukiwania.

  f-strings
     Literały ciągów znaków z osadzonymi wyrażeniami.

  Format String Syntax
     Informacje o formatowaniu ciągów znaków przy użyciu
     "str.format()".

  printf-style String Formatting
     Stare operacje formatowania, wywoływane gdy ciągi znaków są
     lewymi operandami operatora "%" są opisane tutaj bardziej
     szczegółowo.


3.1.3. Listy
------------

Python ma kilka *złożonych* typów danych, używanych do grupowania
różnych wartości. Najbardziej wszechstronnym jest *lista*, która może
zostać zapisana jako lista wartości (elementów) rozdzielonych
przecinkami ujęta w nawiasy kwadratowe. Listy mogą zawierać elementy
różnych typów, ale zazwyczaj wszystkie elementy mają ten sam typ.

   >>> squares = [1, 4, 9, 16, 25]
   >>> squares
   [1, 4, 9, 16, 25]

Tak jak ciągi znaków (i wszystkie inne wbudowane typy *sekwencyjne*),
do elementów list można odwoływać się przez indeksy oraz można z nich
„wydzielać”:

   >>> squares[0]  # indeksowanie zwraca element
   1
   >>> squares[-1]
   25
   >>> squares[-3:]  # slicing zwraca nową listę
   [9, 16, 25]

Listy wspierają też operacje takie jak łączenie:

   >>> squares + [36, 49, 64, 81, 100]
   [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

W przeciwieństwie do ciągów znaków, które są *niemutowalne*, listy są
typem *mutowalnym*, w szczególności można zmieniać ich treść:

   >>> cubes = [1, 8, 27, 65, 125]  # coś tu jest nie tak
   >>> 4 ** 3  # sześcian 4 to 64, a nie 65!
   64
   >>> cubes[3] = 64  # zastąp nieprawidłową wartość
   >>> cubes
   [1, 8, 27, 64, 125]

Można również dodawać nowe elementy na końcu listy, przez użycie
*metody* (dowiemy się więcej o metodach później) "list.append()":

   >>> cubes.append(216)  # dodaj sześcian 6
   >>> cubes.append(7 ** 3)  # i sześcian 7
   >>> cubes
   [1, 8, 27, 64, 125, 216, 343]

Proste przypisanie w Pythonie nigdy nie kopiuje danych. Kiedy
przypisujesz listę do zmiennej, zmienna odnosi się do *istniejącej
listy*. Wszystkie zmiany dokonane na liście przez jedną zmienną będą
widoczne przez wszystkie inne zmienne, które się do niej odwołują.:

   >>> rgb = ["czerwony", "zielony", "niebieski"]
   >>> rgba = rgb
   >>> id(rgb) == id(rgba)  # odwołują się do tego samego obiektu
   True
   >>> rgba.append("alfa")
   >>> rgb
   ["czerwony", "zielony", "niebieski", "alfa"]

Wszystkie operacje wykrawania zwracają nową listę zawierającą żądane
elementy. Następujący slice więc zwraca płytką kopię listy:

   >>> correct_rgba = rgba[:]
   >>> correct_rgba[-1] = "alfa"
   >>> correct_rgba
   ["czerwony", "zielony", "niebieski", "alfa"]
   >>> rgba
   ["czerwony", "zielony", "niebieski", "alfa"]

Możliwe jest również przypisywanie do slice'ów. Może to zmienić
rozmiar listy lub zupełnie ją wyczyścić:

   >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> litery
   ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> # zastąp niektóre wartości
   >>> letters[2:5] = ['C', 'D', 'E']
   >>> litery
   ['a', 'b', 'C', 'D', 'E', 'f', 'g']
   >>> # teraz je usuń
   >>> letters[2:5] = []
   >>> letters
   ['a', 'b', 'f', 'g']
   >>> # wyczyść listę zastępując wszystkie elementy pustą listą
   >>> letters[:] = []
   >>> letters[:]
   []

Wbudowana funkcja "len()" ma również zastosowanie do list:

   >>> letters = ['a', 'b', 'c', 'd']
   >>> len(letters)
   4

Można zagnieżdżać listy (tworzyć listy zawierające inne listy), na
przykład:

   >>> a = ['a', 'b', 'c']
   >>> n = [1, 2, 3]
   >>> x = [a, n]
   >>> x
   [['a', 'b', 'c'], [1, 2, 3]]
   >>> x[0]
   ['a', 'b', 'c']
   >>> x[0][1]
   'b'


3.2. Pierwsze kroki do programowania
====================================

Oczywiście możemy używać Pythona do zadań bardziej skomplikowanych niż
dodawanie dwóch do dwóch. Na przykład możemy napisać początkowy
podciąg ciągu Fibonacciego następująco:

   >>> # ciąg Fibonacciego:
   >>> # suma dwóch elementów określa następny
   >>> a, b = 0, 1
   >>> while a < 10:
   ...     print(a)
   ...     a, b = b, a+b
   ...
   0
   1
   1
   2
   3
   5
   8

Ten przykład wprowadza kilka nowych funkcji.

* Pierwsza linia zawiera *wielokrotne przypisanie*: zmienne "a" i "b"
  jednocześnie dostają nowe wartości 0 i 1. W ostatniej linii jest
  ponownie wykorzystane, demonstrując, że wyrażenia po prawej stronie
  są ewaluowane wcześniej, zanim którekolwiek z przypisań ma miejsce.
  Wyrażenia po prawej stronie są ewaluowane od lewej do prawej.

* Pętla "while" wykonuje się dopóki warunek (tutaj: "a < 10")
  pozostaje prawdziwy. W Pythonie, tak jak w C, każda niezerowa liczba
  całkowita jest prawdziwa; zero jest fałszywe. Warunek może być
  również ciągiem znaków lub listą, tak naprawdę jakąkolwiek
  sekwencją; cokolwiek o niezerowej długości jest prawdziwe, puste
  sekwencje są fałszywe. Warunek użyty w przykładzie jest prostym
  porównaniem. Standardowe operatory porównań pisane są tak samo jak w
  C: "<" (mniejsze niż), ">" (większe niż), "==" (równe), "<="
  (mniejsze lub równe), ">=" (większe lub równe) i "!=" (różne).

* *Ciało* pętli jest *wcięte*: indentacja (wcięcia) jest sposobem na
  grupowanie instrukcji. W trybie interaktywnym trzeba wprowadzić
  znak(i) spacji lub tabulacji, aby wciąć wiersz. W praktyce będziesz
  przygotowywać bardziej skomplikowane dane wejściowe dla Pythona za
  pomocą edytora tekstu; wszystkie przyzwoite edytory tekstu mają
  funkcję automatycznych wcięć. W chwili, gdy wprowadza się jakąś
  instrukcję złożoną w czasie sesji interpretera Pythona, trzeba
  zakończyć ją pustym wierszem (bowiem interpreter nie wie, czy
  ostatni wprowadzony wiersz jest ostatnim z tej instrukcji). Ważne
  jest, aby każdy wiersz należący do tej samej grupy instrukcji, był
  wcięty o taką samą liczbę spacji lub znaków tabulacji.

* Funkcja "print()" wypisuje wartość argumentu(-ów), które jej podano.
  Różnica pomiędzy tą instrukcją, a zwykłym zapisem wyrażenia, które
  chce się wypisać (tak jak robiliśmy to w przykładzie z kalkulatorem)
  występuje w sposobie obsługi wielu wyrażeń i napisów. Łańcuchy
  znaków wypisywane są bez cudzysłowów, a pomiędzy nimi zapisywane są
  spacje, tak aby można było ładnie sformatować pojawiający się napis,
  na przykład:

     >>> i = 256*256
     >>> print('Wartość i wynosi', i)
     Wartość i wynosi 65536

  Keyword argument *end* można wykorzystać, aby uniknąć znaku nowej
  linii po wypisaniu lub aby zakończyć wypisanie innym ciągiem znaków:

     >>> a, b = 0, 1
     >>> while a < 1000:
     ...     print(a, end=',')
     ...     a, b = b, a+b
     ...
     0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

-[ Przypisy ]-

[1] Jako że "**" ma wyższą precedencję niż "-", "-3**2" zostanie
    zinterpretowane jako "-(3**2)" i zwróci "-9". Aby tego uniknąć i
    otrzymać "9", możesz użyć "(-3)**2".

[2] W przeciwieństwie do innych języków, znaki specjalne takie jak
    "\n" mają to samo znaczenie zarówno z pojedynczym ("'…'") jak i
    podwójnym (""…"") cudzysłowem. Jedyną różnicą między nimi jest to,
    że wewnątrz pojedynczego cudzysłowu nie musisz używać znaku
    ucieczki dla """ (lecz musisz użyć znaku ucieczki "\'") i vice
    versa.
