PPy3/StałeIZmienne

Z Brain-wiki

Stałe i zmienne

Stałe dosłowne (literalne)

Stałe dosłowne to takie, których wartości wprost wpisano do pliku z kodem (lub w linii poleceń interpretera). Mogą to być liczby (paru rodzajów) lub napisy, ale również różne złożone rodzaje (typy) danych, z którymi zapoznamy się nieco później.

Zapamiętajmy od razu: liczba dla komputera to zupełnie co innego, niż napis składający się z cyfr. Na napisie nie wykonamy operacji arytmetycznych - a na liczbie, operacji właściwych dla napisów (takich jak np. wyjęcie z niego znaku stojącego na określonej pozycji). Istnieją jednak operacje przekształcające każdy z tych typów danych w drugi.

Liczby

Dobrze jest pamiętać, że nieco odmiennie traktowane są liczby całkowite, a inaczej - liczby ułamkowe, zwykle zwane zmiennoprzecinkowymi (po angielsku floating point, jako że Amerykanie piszą kropkę dziesiętną a nie - jak my - przecinek, przez co i w Pythonie używa się w tym celu kropki).

  • Liczby całkowite w zapisie dziesiętnym: 1024, 0, -666, ...
  • Liczby ułamkowe: 1.0, .99, 98.6, -37.43, ...
  • Liczby ułamkowe w zapisie wykładniczym: 1.024e3, 96.9E-12, ...

Notacja e3, E-12 itp. (wielka i mała litera e są tu równoważne) oznacza pomnożenie poprzedzającej liczby przez odpowiednio 103, 10-12, ... i służy ułatwieniu zapisu liczb bardzo dużych lub bardzo małych. Nie można tam wtrącać dodatkowych odstępów, podobnie jak pomiędzy cyframi.

Jeśli część całkowita (lub ułamkowa) liczby zmiennoprzecinkowej wynosi zero, to można to zero pominąć. Oczywiście nie można pominąć obu, zapisując liczbę zero! (można napisać: 0. albo .0, ale nie samotną kropkę).

Podstawowa różnica pomiędzy sposobem traktowania liczb całkowitych i zmiennoprzecinkowych polega na tym, że:

  • liczby całkowite mogą być dowolnie duże, a rachunki całkowitoliczbowe wykonywane są dokładnie,
  • liczby ułamkowe oraz wyniki rachunków na liczbach ułamkowych należy zawsze traktować jako przybliżone (oczywiście dla szczególnych wartości zdarza się, że są one dokładne); zakres wielkości liczb ułamkowych jest ograniczony.

Python zna też liczby zespolone oraz operacje na nich, ale tego zdaje się nie było w szkole...

Liczby całkowite można pisać również w podstawach innych niż 10:

  • dwójkowe: 0b101 == 5
  • ósemkowe: 0o123 == 83
  • szesnastkowe: 0x1f == 31

(podwojony znak równości oznacza: lewa strona jest równa prawej; litery b, o, x mogą być zarówno małe jak i wielkie).

W zapisie szesnastkowym, wymagającym 16 różnych cyfr, w roli "brakujących" cyfr oznaczających liczby od 10 do 15 przyjmuje się początkowe litery alfabetu (a-f), można równoważnie używać liter małych lub wielkich.

Napisy

Napis (ang. string) to po prostu ciąg znaków.

OK, nic nie jest tak proste, jak się wydaje. Pytanie: co to jest znak? Odpowiedzi dostarcza standard Unicode, w skład którego chodzi m. in. katalog wszystkich znaków, używanych przez systemy pisma wszystkich w zasadzie języków świata (języków żywych, i co ważniejszych spośród martwych). Nie będziemy się w tej chwili zastanawiać nad tym, jak dokładnie znaki te są reprezentowane w komputerze. Warto jednak pamiętać, że napisy nie muszą ograniczać się do znaków znanych z zapisu języków europejskich.

Literalne stałe napisowe, czyli napisy "na twardo" wpisane do kodu, mogą być podane w paru różnych postaciach:

napis1 = 'jedna z postaci napisu'
napis2 = "nieco inna postać napisu"
napis3 = '''tak też może wyglądać napis,
i w tej postaci może zawierać przejścia do nowego wiersza
(w poprzednich nie może)'''
napis4 = """zamiast apostrofów, mogą być cudzysłowy - wychodzi na to samo,
również w postaci takiej, jak napis1 i napis2 są one równoważne"""
napis5 = "korzyść z tego pojawia się np. gdy w treści napisu potrzebujemy umieścić znak taki jak ' "
napis6 = 'w treści napisów można użyć kilku specjalnych sekwencji:\nTo powoduje przejście do nowego wiersza..'
napis7 = 'jeśli dwa napisy (lub więcej) postawimy ' 'jeden obok drugiego ' 'to zostaną połączone w jeden'
napis8 = 'lecz uwaga: pomiędzy sklejone napisy nie zostanie wstawiona żadna spacja ani w ogóle nic.'

Sekwencje specjalne w napisach

\\ dosłowny znak \
\' apostrof: '
\" cudzysłów: "
\a kod BEL
\b kod BS ('backspace')
\f kod FF ('formfeed')
\n kod LF ('linefeed')
\r kod CR ('carriage return')
\t kod HT ('horizontal tab')
\v kod VT ('vertical tab')
\nnn znak o kodzie 'nnn' w zapisie ósemkowym
\xnn znak o kodzie 'nn' w zapisie szesnastkowym
\N{nazwa} znak o danej nazwie symbolicznej w tabeli Unicode
\unnnn znak o pozycji '0xnnnn' w 16-bitowej tabeli Unicode
\Unnnnnnnn znak o pozycji '0xnnnnnnnn' w 32-bitowej tabeli Unicode

To co określam tutaj nazwą kod to są szczególne ,,znaki", które nie posiadają reprezentacji graficznej, ale mogą wystąpić w strumieniu tekstowym pełniąc jakiegoś rodzaju rolę sterującą (p. poniżej). Czasami stosuje się określenie znaki niedrukowalne. Jest ich więcej, niż występuje w powyższej tabeli — pozostałym nie nadano specjalnego zapisu i dostępne są np. przez notację \nnn albo \xnn, ale niezwykle rzadko bywają potrzebne.

  • Wypisanie kodu BEL na terminal najczęściej skutkuje sygnałem akustycznym (BIP!) lub wizualnym (błysk), zależy to od ustawień emulatora terminala
  • Kod BS cofa kursor o jedną pozycję, umożliwiając nadpisanie ostatniego wypisanego znaku
  • Kod FF stosowano w tekście przeznaczonym do wydrukowania na drukarce wierszowej, powodował przejście do następnej strony. Obecnie ze względu na wymarcie drukarek wierszowych w zasadzie nie ma zastosowania
  • Kod LF to przejście do nowej linii, inaczej - znacznik końca linii w strumieniu tekstowym
  • Kod CR czyli powrót karetki cofa kursor do początku aktualnej linii
  • Kod HT to ten, który zwykle nazywa się po prostu kodem tabulacji. Jego interpretacja zależy od ustawień terminala lub innego programu renderującego tekst, zwykle oznacza przeskok do pozycji będącej kolejną całkowitą wielokrotnością 4 lub 8 w bieżącej linii
  • Kod VT z założenia działa analogicznie jak HT, ale w kierunku pionowym. Obecnie rzadko stosowany
  • W zapisie \nnn może wystąpić jedna, dwie lub trzy cyfry ósemkowe n
  • W zapisie \xnn należy użyć dokładnie dwóch cyfr szesnatkowych n
  • W zapisie \unnnn należy użyć dokładnie czterech cyfr szesnastkowych n
  • W zapisie \Unnnnnnnn należy użyć dokładnie ośmiu cyfr szesnastkowych n

Uwaga: w plikach tekstowych utworzonych w systemie Windows linie zwykle kończą się sekwencją dwuznakową CR LF ('\r\n') - inaczej niż w systemie Linux, gdzie znakiem końca linii jest LF. Python nie ma z tym problemu, interpretując pliki z kodem ,,łyka" obie konwencje. Ale np. jeśli w systemie Windows zapiszemy plik zaczynający się ,,magiczną" sekwencją #! /usr/bin/python3, to po przeniesieniu go na Linux nie będzie się on uruchamiał zgodnie z oczekiwaniami, gdyż Linux odczyta nazwę interpretera jak 'python3\r'... Co inteligentniejsze edytory tekstu pozwalają na wybór konwencji końca linii.

Jeżeli chcemy zapisać napis obfitujący w znaki \, możemy użyć notacji takiej:

napis1 = r'oto\napis\z\bakslaszami'
napis2 = R'tu\znak"\"nie\będzie\nigdy\oznaczał\początku\specjalnej\sekwencji'

Wielkość użytej na początku litery R nie ma znaczenia.

Zmienne, czyli nazwy

Programy oczywiście nie operują jedynie na stałych. Potrzebny jest w nich sposób odnoszenia się do wartości, które nie są znane z góry (w chwili pisania programu) - albo dlatego, że zostaną dostarczone dopiero przy uruchomieniu lub w trakcie pracy programu, jako dane wejściowe (później zobaczymy, na jakie sposoby można tego dokonać), albo dlatego, że będą wynikiem obliczeń lub przekształceń danych wykonywanych przez program.

Do tego w Pythonie służą zmienne - można je uważać za nazwy, z jakimi wiążemy pewne wartości (liczby, napisy, itd.), poprzez instrukcję podstawienia. Do zapisu instrukcji podstawienia służy znak równości (=), po jego lewej stronie stawiamy nazwę (zmiennej), po drugiej - wyrażenie, np. literalną stałą, ale również może być to wyrażenie zbudowane ze stałych, operatorów (np. arytmetycznych), nazw zmiennych (reprezentujących w wyrażeniu związane z nimi aktualnie wartości), i szereg innych elementów które dopiero poznamy.

Do zapamiętania: pojedynczy znak równości = w Pythonie (i wielu innych językach programowania) nie tworzy równania, czyli stwierdzenia, że lewa strona jest równa prawej; tylko podstawienie, a więc operację powodującą, że z nazwą stojącą po stronie lewej zostaje związana obliczona wartość wyrażenie stojącego po prawej. Zauważmy, że jest to operacja niesymetryczna (stron nie można bezkarne zamienić miejscami):

i = 0 # pierwsze użycie nazwy, w tym przypadku 'i', tworzy zmienną i wiąże z nią wartość
i = i + 2 # to jest legalne, i oznacza, że wartość związana z 'i' rośnie o 2
i + 2 = i # to jest błędne, po lewej stronie nie może stać wyrażenie złożone

Pojawienie się w wyrażeniu stojącym po prawej stronie podstawienia tej samej nazwy, która stoi po lewej stronie, nie tworzy jakiejkolwiek niejednoznaczności: zasadą jest, że wpierw obliczana jest wartość wyrażenia z prawej strony, z wykorzystaniem aktualnych wartości zmiennych, a potem następuje związanie nazwy zmiennej stojącej po lewej z wynikiem.

Zauważmy, że błędem byłoby użycie nazwy po raz pierwszy bez uprzedniego nadania jej wartości, np. w wyrażeniu arytmetycznym.

Reguły tworzenia nazw

Aktualnie reguły określające, co jest poprawną nazwą w Pythonie, dopuszczają użycie całkiem szerokiego podzbioru znaków Unicode i są dość trudne do opisania w zrozumiały sposób. Pomijając jednak taką możliwość, że ktoś zechce użyć w nazwie zmiennej znaków pisma Kanji lub perskiego, można w dużym uproszczeniu powiedzieć tak:

  • nazwy można budować z liter (wielkich i małych), cyfr, i znaku podkreślenia (_)
  • z zastrzeżeniem, że pierwszym znakiem nazwy nie może być cyfra
  • litery wielkie i małe są rozróżniane, tak więc nazwy różniące się jedynie wielkością liter są różne
  • długość nazwy nie podlega ograniczeniu
  • zabronione jest użycie jako nazwy któregokolwiek z tzw. słów zastrzeżonych, które mają specjalne znaczenie w składni języka Python.Tutaj można znaleźć ich wykaz.

W szczególności, nazwy (zmiennych i innych obiektów) mogą jak najbardziej zawierać litery właściwe dla języka polskiego (oraz dla innych języków). Z rozmaitych względów nie jest to jednak szczególnie rekomendowane, lepiej (przynajmniej na razie) ograniczyć się do liter podstawowego alfabetu łacińskiego.

Oprócz twardych reguł zawartych w definicji języka, w tworzeniu nazw programiści trzymają się na ogół pewnych konwencji - które nie są w żaden sposób egzekwowane przez interpreter, ale ułatwiają czytanie kodu — zwłaszcza, gdy się nim dzielimy z innymi:

  • w nazwach zmiennych używamy małych liter (a nie wielkich)
  • wielkie litery rezerwujemy dla nazw oznaczających wartości stałe, które nie mają prawa się zmienić w trakcie pracy programu
  • staramy się, by nazwy coś znaczyły i ułatwiały zrozumienie kodu programu
  • nie unikamy nazw składających się z dwóch lub nawet kilku słów; ponieważ spacja jako składnik nazwy nie jest dozwolona, zastępujemy ją znakiem podkreślenia
  • unikamy jednak nazw przesadnie długich, a nazwy zmiennych, które są potrzebne jedynie "chwilowo" mogą wręcz być jednoliterowe
  • nazwy zaczynające się od podkreślenia (_) mają pewne specjalne znaczenia i nie tworzymy takich nazw, chyba że całkiem świadomie.

Wyrażenia

Arytmetyczne

Wyrażenia arytmetyczne tworzymy z udziałem znanych już operatorów arytmetycznych +, -, /, *, **, //, %, ..., ale również wywołań funkcji zwracających wartości liczbowe (więcej o tym dalej), z wykorzystaniem literalnych liczb i nazw oznaczających zmienne, których aktualne wartości powinny być liczbami. Możemy również używać nawiasów (wyłącznie okrągłych!) do grupowania podwyrażeń, aby wymusić określoną kolejność operacji. Każdy na ogół pamięta, że dzielenie i mnożenie mają pierwszeństwo przed dodawaniem i odejmowaniem; potęgowanie ma jeszcze wyższy priorytet. Gdy mamy do czynienia z operatorami o równym priorytecie, to operacje wykonywane są zgodnie z kolejnością czytania, od lewej do prawej. Jeżeli mamy wątpliwości, to użycie nawiasów nie będzie błędem. Przykłady:

a + b * c == a + (b * c)
a / b / c == (a / b) / c
a * b ** c == a * (b ** c)
a ** b ** c == a ** (b ** c)
a ** - b == a ** (-b)
a ** b / c == (a ** b) / c

Zachowanie operatora potęgowania jest tu nieco szczególne, i zgadza się z umową przyjętą w matematyce.

Operatory arytmetyczne znajdują również czasem zastosowanie do obiektów nie będących liczbami, mają wtedy oczywiście nieco inne znaczenie. Np. suma dwóch napisów jest ich sklejeniem (mówi się też: konkatenacją).

W przypadku, gdy będziemy mieszać w jednym wyrażeniu liczby całkowite i zmiennoprzecinkowe, to wynik będzie liczbą zmiennoprzecinkową. Wyjątkiem jest dzielenie: a / b zawsze da w wyniku liczbę zmiennoprzecinkową, natomiast a // b - całkowitą, jeśli oba argumenty są całkowite; w przeciwnym razie, zmiennoprzecinkową (ale o zerowej części ułamkowej).

Rozszerzone operatory przypisania

Z dwuargumentowymi operatorami arytmetycznymi związane są tzw. rozszerzone operatory przypisania, stanowiące drobne udogodnienie pozwalające w sposób bardziej zwięzły zapisać dość często występujące operacje - takie, jak powiększenie aktualnej wartości x o 1 i zapamiętanie tej nowej, powiększonej wartości pod nazwą x:

# poniższe instrukcje są parami równoważne
x = x + a 
x += a 
#
x = x * a
x *= a
#
x = x - a
x -= a
#
x = x / a
x /= a
#
x **= a
x = x**a

Wersja np. z potęgowaniem może jest niezbyt często przydatna, ale wprowadzono ją choćby po to, by było konsekwentnie.

Logiczne

Wyrażenia logiczne mogą mieć jedną z dwu wartości: Prawda (True) lub Fałsz (False). Literalne wartości True i False są też przykładami wyrażeń logicznych, choć dość mało przydatnymi. Prawdziwe lub fałszywe mogą być np. porównania dwóch wartości, tworzone za pomocą operatorów >, <, >=, <=, ==, != (to ostatnie, to sposób w jaki w Pythonie pisze się znak nierówności). Jak już wspomniano, podwojony znak równości jest operatorem porównania (w odróżnieniu od pojedynczego - przypisania). Porównywać można przede wszystkim liczby (a więc - dowolne wyrażenia o wartościach liczbowych), ale również np. napisy - wówczas większy oznacza tyle, co dalszy w porządku leksykograficznym. Porównania mają priorytet niższy, niż operatory arytmetyczne.

Przy bliższym poznaniu okazuje się, że wartości True i False są tak naprawdę w pewnym sensie liczbami: odpowiednio 1 i 0. Dozwolone jest więc np. stosowanie do nich operacji arytmetycznych.

Z elementarnych wyrażeń logicznych (porównań) można tworzyć złożone wyrażenia logiczne za pomocą operatorów (spójników) logicznych, pisanych and, or i not. Mają one następujące właśności:

(a and b) == (b and a)
(False and False) == False
(False and True) == False
(True and True) == True
(a or b) == (b or a)
(False or False) == False
(False or True) == True
(True or True) == True
(not True) == False
(not False) == True

Spójniki logiczne mają priorytet jeszcze niższy, niż porównania - stąd nawiasy w powyższym. Wśród nich najwyższy priorytet ma not, następnie and, na końcu or.

Wyrażenia logiczne mają tę szczególną własność, że wartość wyrażenia można często określić obliczając jedynie część jego elementów. Np. a and b, jeżeli wartością a jest False, jest na pewno False - niezależnie od wartości b. W takich przypadkach Python przerywa obliczanie (od lewej do prawej, z uwzględnieniem nawiasów) gdy tylko wartość jest określona. Fakt ten czasami może mieć znaczenie - jeżeli np. obliczenie któregoś z członów wyrażenia logicznego jest szczególnie czasochłonne, lub ma tzw. skutki uboczne.

Wyrażenia logiczne znajdują zastosowanie przede wszystkim w instrukcji warunkowej - pozwalają określić warunki, pod jakimi pewne operacje będą wykonane, lub nie - o tym dalej.

Warto wiedzieć, że w Pythonie każde wyrażenie może służyć jako wyrażenie logiczne. Inaczej mówiąc, każda wartość (napis, liczba, lista, itd.) może być wykorzystana w charakterze wartości logicznej. Obowiązują tu proste reguły:

  • liczba 0 jest fałszywa (równoważna False); obojętne, czy całkowita czy zmiennoprzecinkowa;
  • każda liczba różna od zera jest prawdziwa (równoważna True);
  • napis pusty (o długości 0) jest fałszywy, każdy inny napis jest prawdziwy (również np. zawierający wyłącznie spacje);
  • ogólniej — dowolnego typu kolekcja (lista, słownik, zbiór, ...) jest prawdziwa, o ile jest niepusta; każda kolekcja pusta (0-elementowa) jest fałszywa;
  • wartość pusta czyli None jest, jak nietrudno zgadnąć, fałszywa.

W przypadku ogólniejszych typów danych (obiektów klas złożonych) sytuacja może już nie być taka prosta, ponieważ twórca klasy ma moc określenia reguły decydującej o prawdziwości / nieprawdziwości obiektów danej klasy. Ten temat jest na razie poza zakresem naszego kursu.

Jeżeli chcemy wymusić, aby dana wartość stała się dosłownie wartością logiczną, tzn. jedną z (True, False) w sposób zgodny z powyższymi regułami, można to osiągnąć przykładając funkcję bool: a więc bool(wyrażenie). Rzadko jednak bywa to potrzebne.

Reguła „skrótowej" ewaluacji wyrażeń logicznych, w połączeniu z regułami prawdziwości innych typów danych, pozwala na dość popularne idiomy, jak np.:

# jeśli `wynik' jest niepustą listą to wypisze jej zawartość
# jeśli natomiast pustą, pojawi się komunikat
print(wynik or "wynik jest pusty!")

które pozwalają uniknąć używania instrukcji złożonych w wielu prostych przypadkach. Działa to dzięki temu, że spójniki and i or nie wymuszają aby wynik był wartością logiczną:

  • jeżeli a jest prawdziwe, to a or b == a, i a and b == b dla każdego b;
  • jeżeli a jest fałszywe, to a and b == a, i a or b == b dla każdego b.

Inaczej w przypadku operatora not: wynikiem jego działania jest zawsze jedna z wartości logicznych, podobnie jak w przypadku funkcji bool() — tyle, że przeciwna.

Napisowe

Wartością wyrażenia może być również napis. Na przykład, a + b, jeżeli a i b są napisami, jest napisem utworzonym przez ich sklejenie (zauważmy, że w odróżnieniu od dodawania liczb nie jest to operacja przemienna).

Wcześniej wspomniano, że dwa napisy literalne postawione obok siebie zostaną automatycznie sklejone w jeden: np. 'abc' "123" jest równoważne 'abc123'. Nie stosuje się to jednak np. do zmiennych o wartościach napisowych: napisanie dwóch nazw obok siebie bez operatora pomiędzy nimi jest błędem składniowym. Jest tak, ponieważ wspomniane sklejenie napisów literalnych ma miejsce na etapie kompilacji kodu - tzn. wtedy, gdy interpreter analizuje zapis programu i przekłada go na instrukcje, jakie zostaną wykonane w etapie uruchomienia - a wartości stojące za nazwami zmiennych nie są na tym etapie jednoznacznie określone.

Bogatszy repertuar operacji tworzących wyrażenia o wartościach będących napisami poznamy dalej.

Inne wyrażenia

Oprócz liczb, napisów i wartości logicznych, Python posiada szereg dalszych, złożonych typów danych, które również mogą być wartościami wyrażeń. Wspomniano już przelotnie o kolekcjach (listy, słowniki, zbiory, ...) — służą one jako ,,pojemniki" do gromadzenia obiektów w zasadzie dowolnych typów, i zostaną omówione w dalszym ciągu. Istnieje też specjalny typ obiektu pustego, mający dokładnie jednego reprezentanta: wartość specjalną None. Jeszcze innym typem danych są funkcje, z którymi się już zaraz zapoznamy.

Każdy typ obiektu w Pythonie może być wartością odpowiednio zbudowanego wyrażenia. Gdy poznamy kolejne typy danych, wprowadzimy również operacje tworzące takie wyrażenia.

Ćwiczenia

1. Które z następujących są poprawnymi nazwami według reguł Pythona:

  nazwa1
  9sił
  dluga-nazwa
  wykonaj_rachunki
  _
  to&owo
  if 

2. Wykazać, że poniższe równości są równoważnościami -- tzn. że zachodzą dla dowolnej kombinacji wartości a i b:

  not (a or b) == not a and not b
  not (a and b) == not a or not b
  a or not a == True

Wskazówka: stworzyć tabelki wartości wyrażeń po lewej i prawej stronie operatora porównania == dla wszystkich możliwych kombinacji wartości a i b.

3. Które z poniższych równości są tożsamościami, w wyniku działania reguł pierwszeństwa operatorów?

  a / b / c == a / (b / c)
  a ** b / c == (a ** b) / c
  -a ** b == (-a) ** b

CDN...


poprzednia | Strona główna | dalej

--RobertJB (dyskusja) 14:22, 21 cze 2016 (CEST)