V minulém díle jste viděli...¶
Mezi nejužitečnější vlastnosti integrovaných vývojových prostředí je integrace nástrojů pro ladění kódu. Ladící program (slangově debugger) umožňuje za běhu sledovat hodnoty proměnných, vypisovat grafy volání funkcí, spouštět program po jednotlivých příkazech nebo spustit samostatně jen vybranou část kódu.
Ladění se sustí klávesovou zkratkou F5, po spuštění se naplní levý postraní panel Run and debug (Ctrl+Shift+D). V tomto panelu je například zobrazen seznam proměnných s aktuálními hodnotami, seznam bodů zastavení (breakpoints) nebo graf volání aktuální funkce.
Dalši užitečné nástroje pro krokování najdete v nabídce Run:
Položka | Klávesová zkratka | Krátký popis |
---|---|---|
Continue |
F5 | obnoví vykonávání skriptu (až po další bod zastavení) |
Step Over |
F10 | vykoná následující příkaz |
Step Into |
F11 | vstoupí do těla volané funkce |
Step Out |
Shift+F11 | provede aktuální funkci a vrátí se do funkce volající |
Toggle breakpoint |
F9 | přepne bod zastavení na řádku s kurzorem |
Práce se soubory 1¶
V programovacím jazyce Python lze přistupovat k souborům, které máme uložené na disku. Soubory lze číst, zapisovat do nich, vytvářet nové, mazat je a další operace.
Základní práce je docela přímočará. Pro práci se souborem používáme funkci open()
, která dokáže soubor otevřít v několika různých módech, mezi které patří například čtení nebo zápis. Funkce open
se většinou používá s jedním nebo dvěma parametry, kdy první určuje jméno souboru (včetně relativní nebo úplné cesty), se kterým chceme pracovat, a druhý určuje mód práce se souborem (čtení/zápis/...)
Funkce open()
vrací objekt, který nám dovoluje následně se souborem pracovat.
Různé módy přístupu k souboru v Pythonu
Mód | Popis |
---|---|
r | Otevře soubor pro čtení. (výchozí) |
w | Otevře soubor pro zápis. Pokud soubor existuje, přemaže ho novým prázdným souborem. |
x | Vytvoří a otevře soubor, pokud na disku neexistuje. Pokud soubor již existuje, skončí to chybou. |
a | Otevře soubor pro zápis, aniž by smazal jeho obsah. Zápis bude probíhat za poslední data v souboru. Pokud soubor neexistuje, pak je vytvořen. |
t | Otevře soubor v textovém režimu. (výchozí) |
b | Otevře soubor v binárním režimu. |
+ | Otevře soubor pro upravení. (čtení a psaní) |
Ukázky použití funkce open()
file1 = open("test.txt") # otevře soubor pro čtení v textovém režimu
file2 = open("test.txt", "r") # otevře soubor pro čtení v textovém režimu
file3 = open("test.txt", "w") # otevře soubor pro zápis v textovém režimu
file4 = open("test.txt", "wb") # otevře soubor pro zápis v binárním režimu
file5 = open("test.txt", "rb") # otevře soubor pro čtení v binárním režimu
file6 = open("test.txt", "a") # otevře soubor pro přidávání v textovém režimu
file7 = open("data/test3.txt") # jméno souboru včetně relativní cesty
file8 = open("c:/data/test3.txt") # jméno souboru včetně úplné cesty
Po práci se souborem je vhodné soubor uzavřít, čímž dojde k dokončení všech operací a zneplatnění ukazatele na soubor. K tomu slouží metoda close()
.
file1.close() #uzavření souboru
Čtení textových souborů¶
Ze souboru otevřeného pro čtení můžeme číst data a ukládat je do proměnných v našem programu. Pro čtení lze využít například metodu read()
, která data načte a vrátí je jako svou návratovou hodnotu (typu str
).
# otevře soubor pro čtení v textovém režimu
file1 = open("data/data.txt", "r", encoding='UTF-8')
print(file1)
# přečte soubor a obsah uloží do proměnné file_content
file_content = file1.read()
file_content1 = file1.read()
# obsah souboru vypíšeme
print(file_content)
# soubor následně uzavřeme
file1.close()
<_io.TextIOWrapper name='data/data.txt' mode='r' encoding='UTF-8'> Nějaký textový soubor, který obsahuje více řádků.
# ukázka, že nemohu načíst data vícekrát
# otevře soubor pro čtení v textovém režimu
file1 = open("data/data.txt", "r", encoding='UTF-8')
print(file1)
# přečte soubor a obsah uloží do proměnné file_content
file_content = file1.read()
file_content1 = file1.read()
# obsah souboru vypíšeme
print(file_content1)
# soubor následně uzavřeme
file1.close()
# ukázka, že nemohu načíst data vícekrát
<_io.TextIOWrapper name='data/data.txt' mode='r' encoding='UTF-8'>
Jiný způsob práce se souborem je využití klíčového slova with
. Zde je výhoda v tom, že nemusíme volat close()
a řešit uvolnění prostředků po nějaké chybě (například pokud do souboru nelze zapisovat nebo z něj číst). Také proměnná file1
má omezenou existenci pouze na tento blok, což zefektivňuje a zpřehledňuje kód.
with open('data/data.txt') as file1:
#print(file1.read())
file_content = file1.read()
file_content1 = file1.read()
# obsah souboru vypíšeme
print(file_content)
# širší ukázka
Nějaký textový soubor, který obsahuje více řádků.
# soubor neexistuje:
with open('data/data2.txt') as file1:
print(file1.read())
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[6], line 1 ----> 1 with open('data/data2.txt') as file1: 2 print(file1.read()) File /usr/lib/python3.11/site-packages/IPython/core/interactiveshell.py:308, in _modified_open(file, *args, **kwargs) 301 if file in {0, 1, 2}: 302 raise ValueError( 303 f"IPython won't let you open fd={file} by default " 304 "as it is likely to crash IPython. If you know what you are doing, " 305 "you can use builtins' open." 306 ) --> 308 return io_open(file, *args, **kwargs) FileNotFoundError: [Errno 2] No such file or directory: 'data/data2.txt'
Při práci se soubory může velmi lehce dojít k chybě při otevírání nebo další práci se souborem, například že soubor neexistuje, nelze z něj číst, atp. V tomto případě by náš program skončil chybou. Tyto chyby lze ale v Pythonu ošetřit pomocí výjimek (exceptions). Lze toho docílit tak, že funkce a metody pracující se soubory dáme do bloku try
a následně výjimky odchytáváme. Více v příkladu:
try:
with open('data/data2.txt') as file1:
print(file1.read())
except OSError as e:
print(f"Při práci se souborem došlo k chybě.\n{e}")
print("\nProgram ale pokračuje dál bez přerušení.")
Při práci se souborem došlo k chybě. [Errno 2] No such file or directory: 'data/data2.txt' Program ale pokračuje dál bez přerušení.
Poznámka:
Funkce open
vyvolává pouze výjimky typu OSError
(operating system error).
K jiným chybám ale může dojít ve vašem kódu uvnitř bloku with
.
V následujících příkladech nebudeme tento způsob používat z důvodu zpřehlednění kódu, ale ve vašich programech by bylo vhodné tento způsob zpracování výjimek používat u každé práce se souborem.
Někdy je vhodné číst soubor po jednotlivých řádcích. Zde lze použít metodu readline()
:
with open('data/data.txt') as file1:
line = file1.readline()
while line:
print(line, end='')
line = file1.readline()
Nějaký textový soubor, který obsahuje více řádků.
Alternativně lze použít for
-cyklus, kde jako zdroj hodnot použijeme soubor:
with open('data/data.txt') as file1:
file1.readline()
for line in file1:
print(line, end='')
# opět ukázka, že nemohu načíst data víckrát
který obsahuje více řádků.
Je též možné načíst jednotlivé řádky do seznamu řetězců pomocí metody readlines()
a následně s nimi pracovat.
with open('data/data.txt') as file1:
lines = file1.readlines()
print("Vsechna data v seznamu:\n", lines, "\n")
print("Vypsani 2. radku:\n",lines[1])
Vsechna data v seznamu: ['Nějaký textový soubor,\n', 'který obsahuje\n', 'více řádků.'] Vypsani 2. radku: který obsahuje
Alternativně:
with open('data/data.txt') as file1:
lines = list(file1)
print("Vsechna data v seznamu:\n", lines, "\n")
print("Vypsani 2. radku:\n",lines[1])
Vsechna data v seznamu: ['Nějaký textový soubor,\n', 'který obsahuje\n', 'více řádků.'] Vypsani 2. radku: který obsahuje
Zápis do textových souborů¶
Do souborů je samozřejmě možné zapisovat. K tomu slouží metoda write()
nebo funkce print()
. Metoda write()
má jediný parametr typu str
. V případě funkce print()
, kterou už dobře známe, je třeba specifikovat (pomocí parametru file
), do kterého souboru se data mají zapsat. Když parametr nezadáme, použije se standardní výstup, jak jsme byli doposud zvyklí.
text = "Nějaký text, který chceme zapsat do souboru."
# otevřeme soubor pro zápis v textovém režimu
# pokud neexistuje, je nově vytvořen
file1 = open("data/new_file.txt", 'w')
# zapíšeme text pomocí write()
file1.write("vice textu"+str(67)+"\n")
file1.write("vice textu"+str(67)+"\n")
file1.write(f"vice textu {67}. \n")
# zapíšeme text pomocí print()
print(text,124, file=file1)
# uzavřeme
file1.close()
# ukázka ... write víckrát, čísla (str, +, fstring).
Stejně jako u čtení, je vhodné použít konstrukci with
.
# otevřeme soubor pro zápis
with open('data/new_file.txt', "w") as file1:
file1.write("Nějaký text.\n")
print("Nějaký další text pomocí print().", file=file1)
Pokud potřebujeme pracovat s více soubory najednou, můžeme je otevřít v rámci jedné konstrukce with
, například:
# zkopírování souboru:
with open('data/data.txt') as file1:
with open('data/data_new.txt', "w") as file2:
file2.write(file1.read())
# zkopírování souboru:
with open('data/data.txt') as file1, open('data/data_new.txt', "w") as file2:
file2.write(file1.read())
Ukázkový příklad 1: zápis číselných hodnot do souboru¶
Zapíšeme 2 sloupce čísel oddělené tabulátorem (znak '\t'
), kde v prvním sloupci bude vždy číslo (od 1 do n) a v druhém jeho odmocnina. Při zápisu číselných hodnot do souboru pomocí metody write()
je nejprve musíme převést na stringy. To můžeme udělat například pomocí funkce str()
nebo pomocí formátovacích řetězců (f
-stringů).
import math
n = 10
with open('data/cisla.txt', "w") as file1:
for i in range(1, n):
# s využitím funkce str() a metody write()
file1.write(str(i) + '\t'+ str(math.sqrt(i))+'\n')
# alternativně pomocí f-stringu:
# file1.write(f"{i}\t{math.sqrt(i)}\n")
# alternativně pomocí f-stringu a funkce print():
# print(f"{i}\t{math.sqrt(i)}", file=file1)
soucet = 0
with open('data/cisla.txt', "r") as file1:
for line in file1:
s = line.split()
print("sqrt (",s[0],") = ",s[1])
#print(f"sqrt ( {s[0]} ) = {s[1]}")
soucet += float(s[1])
print(soucet)
sqrt ( 1 ) = 1.0 sqrt ( 2 ) = 1.4142135623730951 sqrt ( 3 ) = 1.7320508075688772 sqrt ( 4 ) = 2.0 sqrt ( 5 ) = 2.23606797749979 sqrt ( 6 ) = 2.449489742783178 sqrt ( 7 ) = 2.6457513110645907 sqrt ( 8 ) = 2.8284271247461903 sqrt ( 9 ) = 3.0 19.30600052603572
Ukázkový příklad 2: načtení číselných hodnot ze souboru, jejich výpis a spočítání součtu odmocnin¶
Při čtení dat z textového souboru je musíme vhodně zpracovat (parsovat), abychom s nimi pak mohli pracovat. Hodnota načtená pomocí metod read()
, readline()
nebo pomocí for
-cyklu je typu str
(string). String musíme nejprve rozdělit na jednotlivé podstringy a ty následně převést na vhodný datový typ.
Rozdělení stringu lze provést pomocí nám již známé metody split()
, která daný string rozdělí na seznam kratších stringů v místech, kde se nacházel oddělovač. Například:
"rum,pivo,zelena".split(',') == ['rum', 'pivo', 'zelena']
with open('data/cisla.txt') as file2:
sum = 0 # budeme počítat sumu z druhého sloupce
for line in file2:
string_values = line.split('\t') # rozdělíme řádek podle znaku \t
index = int(string_values[0]) # první hodnotu převedeme na int
value = float(string_values[1]) # druhou převedeme na float
sum += value # přičteme k sumě
print('sqrt(', index, ') = ', value) # ukázkový výpis
print('Soucet odmocnin je:', sum)
sqrt( 1 ) = 1.0 sqrt( 2 ) = 1.4142135623730951 sqrt( 3 ) = 1.7320508075688772 sqrt( 4 ) = 2.0 sqrt( 5 ) = 2.23606797749979 sqrt( 6 ) = 2.449489742783178 sqrt( 7 ) = 2.6457513110645907 sqrt( 8 ) = 2.8284271247461903 sqrt( 9 ) = 3.0 Soucet odmocnin je: 19.30600052603572
Nastavení standardního výstupu¶
Pokud nechceme stále zadávat parametr file
při použití funkce print()
, lze nastavit standardní výstup do námi zvoleného souboru.
Lze to provést pomocí nastavení sys.stdout
na náš soubor. Je nutné importovat balíček sys
.
import sys # importujeme balíček sys
# uložíme si původní hodnotu výstupu
orig_stdout = sys.stdout
with open('data/soubor.txt', 'w') as file1:
# změníme výstup na náš soubor
sys.stdout = file1
print('Tento text se zapíše do souboru.')
# změníme výstup zpět na standardní výstup
sys.stdout = orig_stdout
print("neco")
neco
Čtení a zápis binárních souborů¶
Práce s binárními soubory je velmi podobná. Používáme stejné funkce a metody open()
, read()
, write()
a close()
. Rozdíl je hlavně v tom, že binární soubory jsou pro člověka nečitelné a data jsou v něm uložena právě v binární, nikoli textové podobě.
S binárními soubory je spojeno několik komplikací. Nejprve musíme naše data převést na byty a pak zapsat. Navíc je třeba dát pozor na kódování čísel větších než 1 byte. Zde podle architektury procesoru existuje kódování little endian a big endian, které se liší pořadím bytu.
Pro převedení seznamu s hodnotami na pole bytů lze například použít funkci bytearray()
.
# Zápis pěti bytů do souboru v binární podobě
data = [1, 2, 255, 66, 32]
bytes = bytearray(data)
with open('data/binarni_soubor.bin', "wb") as file2:
file2.write(bytes)
Čtení binárních souborů se provádí pomocí metody read()
.
with open('data/binarni_soubor.bin', "rb") as file2:
content = file2.read() # přečteme vše
print(content[2]) # přistoupíme ke třetímu bytu ze souboru
print(content)
data = list(content) # převod bytového pole na seznam čísel
print(data)
255 b'\x01\x02\xffB ' [1, 2, 255, 66, 32]
Příklady¶
- Načtěte textový soubor
data/text.txt
a vypište ho na obrazovku tak, že všechna písmena budou velká.
with open('data/text.txt') as file_in:
print(file_in.read().upper())
OKOLO LESA POLE LÁN, HOJ JEDE, JEDE Z LESA PÁN, NA VRANÉM BUJNÉM JEDE KONI, VESELE PODKOVIČKY ZVONÍ, JEDE SÁM A SÁM. A PŘED CHALUPOU S KONĚ HOP A NA CHALUPU: KLOP, KLOP, KLOP! „HOLA HEJ! OTEVŘTE MI DVÉŘE, ZBLOUDIL JSEM PŘI LOVENÍ ZVĚŘE, DEJTE VODY PÍT!“
with open('data/text.txt') as file_in:
for line in file_in:
print(line.upper(), end="")
OKOLO LESA POLE LÁN, HOJ JEDE, JEDE Z LESA PÁN, NA VRANÉM BUJNÉM JEDE KONI, VESELE PODKOVIČKY ZVONÍ, JEDE SÁM A SÁM. A PŘED CHALUPOU S KONĚ HOP A NA CHALUPU: KLOP, KLOP, KLOP! „HOLA HEJ! OTEVŘTE MI DVÉŘE, ZBLOUDIL JSEM PŘI LOVENÍ ZVĚŘE, DEJTE VODY PÍT!“
- Upravte předchozí příklad tak, aby byl výsledek konverze uložen do nového souboru a nevypisoval se na obrazovku.
with open('data/text.txt') as source:
with open('data/text_novy.txt','w') as dest:
dest.write(source.read().upper())
with open('data/text.txt') as source, open('data/text_novy1.txt','w') as dest:
for line in source:
dest.write(line.upper())
#print(line.upper(), file=dest, end="")
- V souboru
data/text.txt
spočítejte počet řádků a počet slov.
pocet_radek = 0
pocet_slov = 0
with open('data/text.txt') as src:
for line in src:
pocet_radek += 1
pocet_slov += len(line.split())
print('Pocet radek:', pocet_radek, ' Pocet slov:', pocet_slov)
Pocet radek: 11 Pocet slov: 47
- Vytvořte program, který do textového souboru
data/sinus.txt
vypíše dvojice hodnot $x,y$ kde $x$ budou čísla od $0$ do $2\pi$ s krokem $0.05$ a $y = \sin(x)$. Každá dvojice bude vypsaná na samostatný řádek ve formátux,y
(dvě čísla oddělená čárkou).
import math
min = 0
max = 2.0 * math.pi
step = 0.05
# Otevření souboru pro zápis
with open('data/sin_values.txt', 'w') as file:
x = min
while x <= max:
file.write(f"{x},{math.sin(x)}\n")
x += step
- Načtěte soubor
data/inventory.txt
, ve kterém je seznam zboží na skladě. Z dat vypočtěte celkovou cenu zboží na skladě a také celkový počet kusů všeho zboží dohromady. Výsledek vypište (na standardní výstup). Podívejte se nejprve na strukturu souboru a podle toho ho v programu zpracujte. Všimněte si například, že první řádek obsahuje jen popis sloupců.
- Data v souboru
data/inventory.txt
převeďte z formátu CSV (hodnoty oddělené čárkou) na tabulku v HTML (do nějakého jiného souboru). Příklad:
<table>
<tr>
<td>Kýbl</td>
<td>5</td>
<td>85</td>
</tr>
<tr>
<td>Pytel cementu</td>
<td>10</td>
<td>12</td>
</tr>
</table>
- Vypište do souboru čísla od 2 do n a vedle nich do sloupce odděleného tabulátorem (znak
'\t'
) jejich prvočíselný rozklad oddělený čárkami. Příklad:
...
8 2,2,2
9 3,3
10 2,5
...