Cesty a soubory s Pathlib

Základní práci se soubory – čtení z nich a psaní do nich – rozebírá lekce o souborech. Pro zopakování:

# Otevření textového souboru "basnicka.txt" pro čtení
with open('basnicka.txt', encoding='utf-8') as soubor:
    # Přečtení obsahu
    contents = soubor.read()

# Velikost souboru
print(len(soubor))

Jméno souboru, případně cesta k němu, se tradičně zadává jako řetězec. Jednotlivé adresáře jsou odděleny lomítkem (případně na Windows zpětným lomítkem); fungují tu absolutní i relativní cesty.

Pro prosté otvírání známých souborů to stačí. Když ale potřebuješ s cestami k souborům pracovat víc, řetězce jsou docela nepohodlné. A navíc je problém pamatovat na všechny různé případy, které můžou nastat.

Zkus pro příkad napsat funkce, které dostanou cestu k souboru a:

  • vrat_casti rozdělí cestu na jednotlivé adresáře (a vrátí je jako seznam),
  • vrat_priponu vrátí příponu souboru.

Na mém Linuxovém počítači cesty vypadají jako /home/janca/Documents/archiv.tar.gz, takže bych mohl napsat něco jako:

def vrat_casti(path):
    """Vrátí seznam komponentů cesty (jednotlivých adresářů/souborů)"""
    return path.split('/')

def vrat_priponu(path):
    """Vrátí příponu souboru"""
    parts = path.split('.')
    return parts[-1]

Pro mou cestu to funguje:

>>> retezcova_cesta = '/home/janca/Documents/archiv.tar.gz'

>>> vrat_casti(retezcova_cesta)
['', 'home', 'janca', 'Documents', 'archiv.tar.gz']
>>> vrat_pripona(retezcova_cesta)
'gz'

Ale pro jinou cestu na jiném počítači už ne:

>>> retezcova_cesta = 'C:\\Users\\Jana\\Programy\\superprojekt\\README'

>>> vrat_casti(retezcova_cesta)
['C:\\Users\\Jana\\Programy\\superprojekt\\README']
>>> vrat_priponu(retezcova_cesta)
'C:\Users\Jana\Programy\superprojekt\README'

To, že programátoři používali na cesty řetězce a nepromýšleli všechny možné podivnosti souborových systémů, je hlavní důvod proč si ještě dnes spousta programů neporadí s diakritikou nebo mezerami v názvech souborů.

Jde to líp? Samozřejmě!

Knihovna pathlib

Od verze 3.4 obsahuje Python knihovnu pathlib, jejíž třída Path reprezentuje cestu k souboru a umožňuje s takovými cestami jednoduše a bezpečně manipulovat.

>>> from pathlib import Path

>>> # Cesta, která na Windows i Unixu funguje podobně:
>>> cesta = Path('/home/janca/Documents/archiv.tar.gz')
>>> cesta.parts
('/', 'home', 'janca', 'Documents', 'archiv.tar.gz')
>>> cesta.suffix
'.gz'

Ukázka s cestou pro Windows (která by na Unixu nefungovala):

Pouštíš-li ukázku na Windows, můžeš místo PureWindowsPath použít rovnou Path.

>>> from pathlib import PureWindowsPath

>>> win_cesta = PureWindowsPath('C:\\Users\\Jana\\Programy\\superprojekt\\README')
>>> win_cesta.parts
('C:\\', 'Users', 'Jana', 'Programy', 'superprojekt', 'README')
>>> win_cesta.suffix
''

Ukažme si teď něco z toho, co pathlib umožňuje. Nebude to všechno – další možnosti najdeš na taháku nebo v angličtině v dokumentaci.

Tvoření cest

Cesty v pathlib se tvoří zavoláním třídy Path. Na Windows se tím vytvoří WindowsPath, na Unixu PosixPath.

Obě považují dopředná lomítka za oddělovač adresářů, takže následující bude fungovat na všech systémech:

>>> docs_cesta = Path('/home/janca/Documents')
>>> docs_cesta
PosixPath('/home/janca/Documents')

Už při vytvoření cesty se tato normalizuje, zjednoduší bez změny významu. Víc lomítek za sebou se spojí do jednoho, zbytečné adresáře nebo lomítka na konci se vynechají.

>>> Path('/tmp//foo/./bar/')
PosixPath('/tmp/foo/bar')

Když chci k takové cestě něco připojit, použiju operátor / (který by se měl používat na dělení, ale psst!):

>>> docs_cesta / 'archiv.tar.gz'
PosixPath('/home/janca/Documents/archiv.tar.gz')

Přidávat se takhle dají řetězcové cesty, nebo i další Path:

>>> Path('/') / 'home/janca' / Path('archiv.tar.gz')
PosixPath('/home/janca/archiv.tar.gz')

Pozor ale na to, že absolutní cesta (s lomítkem nebo jménem disku na začátku) znamená, že procházení začíná znovu od kořenového adresáře. Když k něčemu připojím absolutní cestu, předchozí cesta se zahodí.

>>> Path('/home/janca') / '/tmp/foo'
PosixPath('/tmp/foo')

Občas lomítko není pohodlné. V takových případech jde použít metoda joinpath, která má stejný efekt:

>>> Path('/').joinpath('home', 'janca/archiv.tar.gz')
PosixPath('/home/janca/archiv.tar.gz')

Atributy

Cesty v pathlib mají spoustu užitečných atributů – vlastností, ke kterým se dostaneš pomocí tečky:

>>> # Příklady ukážeme opět na téhle cestě:
>>> cesta = Path('/home/janca/Documents/archiv.tar.gz')
>>> cesta
PosixPath('/home/janca/Documents/archiv.tar.gz')

>>> # jméno
>>> cesta.name
'archiv.tar.gz'

>>> # Přípona (poslední)
>>> cesta.suffix
'.gz'

>>> # Věchny přípony
>>> cesta.suffixes
['.tar', '.gz']

>>> # "kořen" jména (bez poslední přípony)
>>> cesta.stem
'archiv.tar'

>>> # "rodič" – adresář, který tuto cestu obsahuje
>>> cesta.parent
PosixPath('/home/janca/Documents')

>>> cesta.parent.parent
PosixPath('/home/janca')
>>> cesta.parent.parent.parent.parent
PosixPath('/')

Všechny "předky" -- rodiče, prarodiče, atd. -- nabízí atribut "parents". Výsledek je ale iterátor; aby se ukázaly jednotlivé hodnoty, je potřeba ho projít cyklem for, převést na seznam, atp.

>>> cesta.parents
<PosixPath.parents>

>>> list(cesta.parents)
[PosixPath('/home/janca/Documents'),
 PosixPath('/home/janca'),
 PosixPath('/home'),
 PosixPath('/')]

>>> # Je cesta absolutní?
>>> cesta.is_absolute()
True
>>> Path('foo/archiv.zip').is_absolute()
False

>>> # Jaká by byla relativní vzhledem k jiné, nadřazené cestě?
>>> relativni_cesta = cesta.relative_to('/home/janca')
>>> relativni_cesta
PosixPath('Documents/archiv.tar.gz')

>>> # Spojením té nadřazené cesty a této relativní dostanu zpátky původní cestu
>>> Path('/home/janca') / relativni_cesta
PosixPath('/home/janca/Documents/archiv.tar.gz')

>>> # Přepsání jména souboru (poslední části cesty)
>>> cesta.with_name('hrad.jpeg')
PosixPath('/home/janca/Documents/hrad.jpeg')

>>> # Přepsání koncovky
>>> cesta.with_suffix('.bz2')
PosixPath('/home/janca/Documents/archiv.tar.bz2')

>>> # Pokud existující koncovka není, `with_suffix` ji přidá
>>> Path('myproject/README').with_suffix('.xz')
PosixPath('myproject/README.xz')

Zkoumání disku

Všechno uvedené výše jsou čistě „textové“ operace – pracují jen se jmény. Soubor archiv.zip (ani jiné) počítači mít, aby ses dostala k příponě nebo ke jménům nadřazených adresářů.

Dokonce si můžeš vyzkoušet, jak by to fungovalo na jiném systému – místo Path naimportuj a použij PureWindowsPath nebo PurePosixPath, které reprezentují Windowsové, resp. Unixové cesty.

Zamysli se: k čemu se hodí umět pojmenovat soubor, který neexistuje?

Řešení

Teď se dostaneme k operacím pro které je potřeba mít přístup k souborovému systému.

Nejdříve dvě funkce, které vrací cesty k užitečným adresářům:

>>> # Aktuální adresář
>>> Path.cwd()
PosixPath('/home/janca/pyladies/barvy')

>>> # Můj domovský adresář
>>> Path.home()
PosixPath('/home/janca')

A základní otázky – existuje daný soubor? Je to normální soubor nebo adresář?

>>> # Existuje na té ukázkové cestě nějaký soubor?
>>> cesta.exists()
False

>>> # Existuje můj domovský adresář?
>>> Path.home().exists()
True

>>> # A je to vůbec adresář?
>>> Path.home().is_dir()
True

>>> # Je to normální datový soubor?
>>> Path.home().is_file()
False

Ukázka

Abychom měli všichni stejné podmínky, stáhni si na další experimenty archiv s testovacími soubory. Dej si ho do aktuálního adresáře (Path.cwd()), a pak ho rozbal pomocí tarfile:

>>> import tarfile

>>> cesta_k_archivu = Path("archiv.tar.gz")

>>> # Co je v archivu?
>>> tarfile.open(cesta_k_archivu, 'r|gz').getnames()
['soubory',
 'soubory/hrad.jpeg',
 'soubory/hrad.attribution',
 'soubory/.gitignore',
 'soubory/kolecko.png',
 'soubory/texty',
 'soubory/texty/vodnik.txt',
 'soubory/texty/lidove',
 'soubory/texty/lidove/pes.txt',
 'soubory/texty/lidove/holka.txt',
 'soubory/texty/vladimir.txt',
 'soubory/texty/cizojazycne',
 'soubory/texty/cizojazycne/iroha.txt',
 'soubory/texty/cizojazycne/witch.txt',
 'soubory/hlad.txt',
 'soubory/hraz.attribution',
 'soubory/ententyky.txt',
 'soubory/hraz.jpeg',
 'soubory/README']

>>> # Extrakce archivu. (Kdybys to zkoušel/a pro jiné archivy, vždy před
>>> # rozbalením zkontroluj cesty všech souborů v archivu -- ať se rozbalením
>>> # nepřepíše nějaký důležitý soubor!)
>>> tarfile.open(cesta_k_archivu, 'r|gz').extractall()

Rozbalením archivu vznikl ./soubory/ (tedy: adresář soubory v aktuálním adresáři). Pojď se mu kouknout na zoubek:

>>> zaklad = Path('./soubory')
>>> zaklad
PosixPath('soubory')

>>> print('Je to adresář?', zaklad.is_dir())
Je to adresář? True
>>> print('Je to normální soubor?', zaklad.is_file())
Je to normální soubor? False

Podle informací o archivu je v soubory nějaký ententyky.txt – podle přípony soubor s textem.

>>> ententyky = zaklad / 'ententyky.txt'
>>> print('Je to adresář?', ententyky.is_dir())
Je to adresář? False
>>> print('Je to normální soubor?', ententyky.is_file())
Je to normální soubor? True

Objekty Path lze používat v naprosté většině situací, kdy jde použít cesta jako řetězec. Například pro funkci open:

with open(ententyky, encoding='utf-8') as file:
    print(file.read())

Path ale má open i jako metodu:

with ententyky.open(encoding='utf-8') as file:
    print(file.read())

A protože je čtení celého textového obsahu souboru docela užitečné, existuje i zkratka která soubor otevře, přečte a zavře najednou:

print(ententyky.read_text())

(Větší soubory je ale lepší otevřít ve with a zpracovávat třeba po řádcích, aby se obsah nemusel do paměti počítače načíst celý najednou.)

Existuje i write_text:

cesta = Path.cwd() / 'pisnicka.txt'
cesta.write_text('Holka modrooká\nNesedávej u potoka!')

A co adresáře?

I s adresáři umí pathlib pracovat. Nejzákladnější operace je získání cest k obsaženým souborům:

>>> zaklad.iterdir()
<generator object Path.iterdir at 0x7fbd4443b9e8>

Metoda iterdir opět vrací iterátor – objekt, přes který musíš „projít“ (cyklem for, převedením na seznam ap.), abys z něj dostala obsah.

>>> list(zaklad.iterdir())
[PosixPath('soubory/hrad.jpeg'),
 PosixPath('soubory/hrad.attribution'),
 PosixPath('soubory/.gitignore'),
 PosixPath('soubory/kolecko.png'),
 PosixPath('soubory/texty'),
 PosixPath('soubory/hlad.txt'),
 PosixPath('soubory/hraz.attribution'),
 PosixPath('soubory/ententyky.txt'),
 PosixPath('soubory/hraz.jpeg'),
 PosixPath('soubory/README')]

>>> for cesta in zaklad.iterdir():
>>>    print(cesta)
soubory/hrad.jpeg
soubory/hrad.attribution
soubory/.gitignore
soubory/kolecko.png
soubory/texty
soubory/hlad.txt
soubory/hraz.attribution
soubory/ententyky.txt
soubory/hraz.jpeg
soubory/README

Strom adresářů – rekurze

Adresáře, podadresáře a soubory v nich tvoří strukturu, na kterou se často používají rekurzivní funkce.

Tady je funkce vypis_soubory, která ypíše všechny soubory v daném adresáři. Před každé jméno dá odrážku -, aby to líp vypadalo:

from pathlib import Path

def vypis_soubory(odrazka, adresar):
    """Vypíše odrážkový seznam jmen souborů v daném adresáři"""
    for soubor in adresar.iterdir():
        print(odrazka, soubor.name)

vypis_soubory('-', Path.cwd())

Odrážka se dá zadat:

vypis_soubory('*', Path.cwd())
vypis_soubory('  *', Path.cwd())

Tahle funkce se dá změnit, aby vypsala i obsahy podadresářů. Jak? Poté, co vypíše jméno nějakého podadresáře, zavolá funkci která vypíše obsah toho podadresáře. Takovou funkci ale už máš napsanou – stačí trochu změnit odrážku, aby bylo poznat co je podadresář.

from pathlib import Path

def vypis_soubory(odrazka, adresar):
    """Vypíše odrážkový seznam jmen souborů v daném adresáři i podadresářích"""
    for soubor in adresar.iterdir():
        print(odrazka, soubor.name)
        if soubor.is_dir():
            vypis_soubory('  ' + odrazka, soubor)

vypis_soubory('-', Path.cwd())

Podobně lze například spočítat soubory v nějakém adresáři (i všech podadresářích).

from pathlib import Path

def spocitej_normalni_soubory(adresar):
    """Vrátí počet normálních souborů v daném adresáři i všech podadresářích"""
    pocet = 0
    for soubor in adresar.iterdir():
        if soubor.is_dir():
            pocet = pocet + spocitej_normalni_soubory(soubor)
        elif soubor.is_file():
            pocet = pocet + 1
    return pocet

print(spocitej_normalni_soubory(Path.cwd()))
{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-pondeli:iterable:3",
      "title": "Adresáře, soubory a cesty",
      "html": "\n          \n    \n\n    <h1>Cesty a soubory s Pathlib</h1>\n<p>Z&#xE1;kladn&#xED; pr&#xE1;ci se soubory &#x2013; &#x10D;ten&#xED; z nich a psan&#xED; do nich &#x2013; rozeb&#xED;r&#xE1;\n<a href=\"/2019/brno-jaro-2019-pondeli/beginners/files/\">lekce o souborech</a>. Pro zopakov&#xE1;n&#xED;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\"># Otev&#x159;en&#xED; textov&#xE9;ho souboru &quot;basnicka.txt&quot; pro &#x10D;ten&#xED;</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">&apos;basnicka.txt&apos;</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">&apos;utf-8&apos;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">soubor</span><span class=\"p\">:</span>\n    <span class=\"c1\"># P&#x159;e&#x10D;ten&#xED; obsahu</span>\n    <span class=\"n\">contents</span> <span class=\"o\">=</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Velikost souboru</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">soubor</span><span class=\"p\">))</span>\n</pre></div><p>Jm&#xE9;no souboru, p&#x159;&#xED;padn&#x11B; cesta k n&#x11B;mu, se tradi&#x10D;n&#x11B; zad&#xE1;v&#xE1; jako &#x159;et&#x11B;zec.\nJednotliv&#xE9; adres&#xE1;&#x159;e jsou odd&#x11B;leny lom&#xED;tkem (p&#x159;&#xED;padn&#x11B; na Windows zp&#x11B;tn&#xFD;m lom&#xED;tkem);\nfunguj&#xED; tu absolutn&#xED; i relativn&#xED; cesty.</p>\n<p>Pro prost&#xE9; otv&#xED;r&#xE1;n&#xED; zn&#xE1;m&#xFD;ch soubor&#x16F; to sta&#x10D;&#xED;.\nKdy&#x17E; ale pot&#x159;ebuje&#x161; s cestami k&#xA0;soubor&#x16F;m pracovat v&#xED;c,\n&#x159;et&#x11B;zce jsou docela nepohodln&#xE9;.\nA nav&#xED;c je probl&#xE9;m pamatovat na v&#x161;echny r&#x16F;zn&#xE9; p&#x159;&#xED;pady, kter&#xE9; m&#x16F;&#x17E;ou nastat.</p>\n<p>Zkus pro p&#x159;&#xED;kad napsat funkce, kter&#xE9; dostanou cestu k&#xA0;souboru a:</p>\n<ul>\n<li><code>vrat_casti</code> rozd&#x11B;l&#xED; cestu na jednotliv&#xE9; adres&#xE1;&#x159;e (a vr&#xE1;t&#xED; je jako seznam),</li>\n<li><code>vrat_priponu</code> vr&#xE1;t&#xED; p&#x159;&#xED;ponu souboru.</li>\n</ul>\n<p>Na m&#xE9;m Linuxov&#xE9;m po&#x10D;&#xED;ta&#x10D;i cesty vypadaj&#xED; jako\n<code>/home/janca/Documents/archiv.tar.gz</code>, tak&#x17E;e bych mohl napsat n&#x11B;co jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">vrat_casti</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vr&#xE1;t&#xED; seznam komponent&#x16F; cesty (jednotliv&#xFD;ch adres&#xE1;&#x159;&#x16F;/soubor&#x16F;)&quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">vrat_priponu</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vr&#xE1;t&#xED; p&#x159;&#xED;ponu souboru&quot;&quot;&quot;</span>\n    <span class=\"n\">parts</span> <span class=\"o\">=</span> <span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&apos;.&apos;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">parts</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n</pre></div><p>Pro mou cestu to funguje:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">retezcova_cesta</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;/home/janca/Documents/archiv.tar.gz&apos;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">vrat_casti</span><span class=\"p\">(</span><span class=\"n\">retezcova_cesta</span><span class=\"p\">)</span>\n<span class=\"go\">[&apos;&apos;, &apos;home&apos;, &apos;janca&apos;, &apos;Documents&apos;, &apos;archiv.tar.gz&apos;]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">vrat_pripona</span><span class=\"p\">(</span><span class=\"n\">retezcova_cesta</span><span class=\"p\">)</span>\n<span class=\"go\">&apos;gz&apos;</span>\n</pre></div><p>Ale pro jinou cestu na jin&#xE9;m po&#x10D;&#xED;ta&#x10D;i u&#x17E; ne:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">retezcova_cesta</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;C:</span><span class=\"se\">\\\\</span><span class=\"s1\">Users</span><span class=\"se\">\\\\</span><span class=\"s1\">Jana</span><span class=\"se\">\\\\</span><span class=\"s1\">Programy</span><span class=\"se\">\\\\</span><span class=\"s1\">superprojekt</span><span class=\"se\">\\\\</span><span class=\"s1\">README&apos;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">vrat_casti</span><span class=\"p\">(</span><span class=\"n\">retezcova_cesta</span><span class=\"p\">)</span>\n<span class=\"go\">[&apos;C:\\\\Users\\\\Jana\\\\Programy\\\\superprojekt\\\\README&apos;]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">vrat_priponu</span><span class=\"p\">(</span><span class=\"n\">retezcova_cesta</span><span class=\"p\">)</span>\n<span class=\"go\">&apos;C:\\Users\\Jana\\Programy\\superprojekt\\README&apos;</span>\n</pre></div><div class=\"admonition note\"><p>To, &#x17E;e program&#xE1;to&#x159;i pou&#x17E;&#xED;vali na cesty &#x159;et&#x11B;zce a neprom&#xFD;&#x161;leli v&#x161;echny mo&#x17E;n&#xE9;\npodivnosti souborov&#xFD;ch syst&#xE9;m&#x16F;, je hlavn&#xED; d&#x16F;vod pro&#x10D; si je&#x161;t&#x11B; dnes spousta\nprogram&#x16F; neporad&#xED; s diakritikou nebo mezerami v n&#xE1;zvech soubor&#x16F;.</p>\n</div><p>Jde to l&#xED;p? Samoz&#x159;ejm&#x11B;!</p>\n<h2>Knihovna pathlib</h2>\n<p>Od verze 3.4 obsahuje Python knihovnu <code>pathlib</code>, jej&#xED;&#x17E; t&#x159;&#xED;da <code>Path</code> reprezentuje\ncestu k souboru a umo&#x17E;&#x148;uje s&#xA0;takov&#xFD;mi cestami jednodu&#x161;e a bezpe&#x10D;n&#x11B; manipulovat.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Cesta, kter&#xE1; na Windows i Unixu funguje podobn&#x11B;:</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca/Documents/archiv.tar.gz&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parts</span>\n<span class=\"go\">(&apos;/&apos;, &apos;home&apos;, &apos;janca&apos;, &apos;Documents&apos;, &apos;archiv.tar.gz&apos;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">suffix</span>\n<span class=\"go\">&apos;.gz&apos;</span>\n</pre></div><p>Uk&#xE1;zka s&#xA0;cestou pro Windows (kter&#xE1; by na Unixu nefungovala):</p>\n<div class=\"admonition note\"><p>Pou&#x161;t&#xED;&#x161;-li uk&#xE1;zku na Windows, m&#x16F;&#x17E;e&#x161; m&#xED;sto <code>PureWindowsPath</code> pou&#x17E;&#xED;t rovnou\n<code>Path</code>.</p>\n</div><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">PureWindowsPath</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">win_cesta</span> <span class=\"o\">=</span> <span class=\"n\">PureWindowsPath</span><span class=\"p\">(</span><span class=\"s1\">&apos;C:</span><span class=\"se\">\\\\</span><span class=\"s1\">Users</span><span class=\"se\">\\\\</span><span class=\"s1\">Jana</span><span class=\"se\">\\\\</span><span class=\"s1\">Programy</span><span class=\"se\">\\\\</span><span class=\"s1\">superprojekt</span><span class=\"se\">\\\\</span><span class=\"s1\">README&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">win_cesta</span><span class=\"o\">.</span><span class=\"n\">parts</span>\n<span class=\"go\">(&apos;C:\\\\&apos;, &apos;Users&apos;, &apos;Jana&apos;, &apos;Programy&apos;, &apos;superprojekt&apos;, &apos;README&apos;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">win_cesta</span><span class=\"o\">.</span><span class=\"n\">suffix</span>\n<span class=\"go\">&apos;&apos;</span>\n</pre></div><p>Uka&#x17E;me si te&#x10F; n&#x11B;co z&#xA0;toho, co <code>pathlib</code> umo&#x17E;&#x148;uje.\nNebude to v&#x161;echno &#x2013; dal&#x161;&#xED; mo&#x17E;nosti najde&#x161; <a href=\"https://pyvec.github.io/cheatsheets/pathlib/pathlib-cs.pdf\">na tah&#xE1;ku</a> nebo v&#xA0;angli&#x10D;tin&#x11B;\nv&#xA0;<a href=\"https://docs.python.org/3/library/pathlib.html\">dokumentaci</a>.</p>\n<h2>Tvo&#x159;en&#xED; cest</h2>\n<p>Cesty v&#xA0;<code>pathlib</code> se tvo&#x159;&#xED; zavol&#xE1;n&#xED;m t&#x159;&#xED;dy <code>Path</code>.\nNa Windows se t&#xED;m vytvo&#x159;&#xED; <code>WindowsPath</code>, na Unixu <code>PosixPath</code>.</p>\n<p>Ob&#x11B; pova&#x17E;uj&#xED; dop&#x159;edn&#xE1; lom&#xED;tka za odd&#x11B;lova&#x10D; adres&#xE1;&#x159;&#x16F;,\ntak&#x17E;e n&#xE1;sleduj&#xED;c&#xED; bude fungovat na v&#x161;ech syst&#xE9;mech:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">docs_cesta</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca/Documents&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">docs_cesta</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents&apos;)</span>\n</pre></div><p>U&#x17E; p&#x159;i vytvo&#x159;en&#xED; cesty se tato <em>normalizuje</em>, zjednodu&#x161;&#xED; bez zm&#x11B;ny v&#xFD;znamu.\nV&#xED;c lom&#xED;tek za sebou se spoj&#xED; do jednoho, zbyte&#x10D;n&#xE9; adres&#xE1;&#x159;e nebo lom&#xED;tka na\nkonci se vynechaj&#xED;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/tmp//foo/./bar/&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;/tmp/foo/bar&apos;)</span>\n</pre></div><p>Kdy&#x17E; chci k takov&#xE9; cest&#x11B; n&#x11B;co p&#x159;ipojit, pou&#x17E;iju oper&#xE1;tor <code>/</code> (kter&#xFD; by se m&#x11B;l\npou&#x17E;&#xED;vat na d&#x11B;len&#xED;, ale psst!):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">docs_cesta</span> <span class=\"o\">/</span> <span class=\"s1\">&apos;archiv.tar.gz&apos;</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents/archiv.tar.gz&apos;)</span>\n</pre></div><p>P&#x159;id&#xE1;vat se takhle daj&#xED; &#x159;et&#x11B;zcov&#xE9; cesty, nebo i dal&#x161;&#xED; <code>Path</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"s1\">&apos;home/janca&apos;</span> <span class=\"o\">/</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;archiv.tar.gz&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/archiv.tar.gz&apos;)</span>\n</pre></div><p>Pozor ale na to, &#x17E;e absolutn&#xED; cesta (s lom&#xED;tkem nebo jm&#xE9;nem disku na za&#x10D;&#xE1;tku)\nznamen&#xE1;, &#x17E;e proch&#xE1;zen&#xED; za&#x10D;&#xED;n&#xE1; znovu od ko&#x159;enov&#xE9;ho adres&#xE1;&#x159;e.\nKdy&#x17E; k n&#x11B;&#x10D;emu p&#x159;ipoj&#xED;m absolutn&#xED; cestu, p&#x159;edchoz&#xED; cesta se zahod&#xED;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca&apos;</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"s1\">&apos;/tmp/foo&apos;</span>\n<span class=\"go\">PosixPath(&apos;/tmp/foo&apos;)</span>\n</pre></div><p>Ob&#x10D;as lom&#xED;tko nen&#xED; pohodln&#xE9;.\nV takov&#xFD;ch p&#x159;&#xED;padech jde pou&#x17E;&#xED;t metoda <code>joinpath</code>, kter&#xE1; m&#xE1; stejn&#xFD; efekt:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">joinpath</span><span class=\"p\">(</span><span class=\"s1\">&apos;home&apos;</span><span class=\"p\">,</span> <span class=\"s1\">&apos;janca/archiv.tar.gz&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/archiv.tar.gz&apos;)</span>\n</pre></div><h2>Atributy</h2>\n<p>Cesty v pathlib maj&#xED; spoustu u&#x17E;ite&#x10D;n&#xFD;ch atribut&#x16F; &#x2013; vlastnost&#xED;, ke kter&#xFD;m se\ndostane&#x161; pomoc&#xED; te&#x10D;ky:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># P&#x159;&#xED;klady uk&#xE1;&#x17E;eme op&#x11B;t na t&#xE9;hle cest&#x11B;:</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca/Documents/archiv.tar.gz&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents/archiv.tar.gz&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># jm&#xE9;no</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">name</span>\n<span class=\"go\">&apos;archiv.tar.gz&apos;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># P&#x159;&#xED;pona (posledn&#xED;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">suffix</span>\n<span class=\"go\">&apos;.gz&apos;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># V&#x11B;chny p&#x159;&#xED;pony</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">suffixes</span>\n<span class=\"go\">[&apos;.tar&apos;, &apos;.gz&apos;]</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># &quot;ko&#x159;en&quot; jm&#xE9;na (bez posledn&#xED; p&#x159;&#xED;pony)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">stem</span>\n<span class=\"go\">&apos;archiv.tar&apos;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># &quot;rodi&#x10D;&quot; &#x2013; adres&#xE1;&#x159;, kter&#xFD; tuto cestu obsahuje</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n<span class=\"go\">PosixPath(&apos;/home/janca&apos;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n<span class=\"go\">PosixPath(&apos;/&apos;)</span>\n</pre></div><p>V&#x161;echny &quot;p&#x159;edky&quot; -- rodi&#x10D;e, prarodi&#x10D;e, atd. -- nab&#xED;z&#xED; atribut &quot;parents&quot;.\nV&#xFD;sledek je ale <em>iter&#xE1;tor</em>; aby se uk&#xE1;zaly jednotliv&#xE9; hodnoty,\nje pot&#x159;eba ho proj&#xED;t cyklem <code>for</code>, p&#x159;ev&#xE9;st na seznam, atp.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parents</span>\n<span class=\"go\">&lt;PosixPath.parents&gt;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">parents</span><span class=\"p\">)</span>\n<span class=\"go\">[PosixPath(&apos;/home/janca/Documents&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;/home/janca&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;/home&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;/&apos;)]</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Je cesta absolutn&#xED;?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">is_absolute</span><span class=\"p\">()</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;foo/archiv.zip&apos;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">is_absolute</span><span class=\"p\">()</span>\n<span class=\"go\">False</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Jak&#xE1; by byla relativn&#xED; vzhledem k jin&#xE9;, nad&#x159;azen&#xE9; cest&#x11B;?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">relativni_cesta</span> <span class=\"o\">=</span> <span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">relative_to</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">relativni_cesta</span>\n<span class=\"go\">PosixPath(&apos;Documents/archiv.tar.gz&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Spojen&#xED;m t&#xE9; nad&#x159;azen&#xE9; cesty a t&#xE9;to relativn&#xED; dostanu zp&#xE1;tky p&#x16F;vodn&#xED; cestu</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;/home/janca&apos;</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">relativni_cesta</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents/archiv.tar.gz&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># P&#x159;eps&#xE1;n&#xED; jm&#xE9;na souboru (posledn&#xED; &#x10D;&#xE1;sti cesty)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">with_name</span><span class=\"p\">(</span><span class=\"s1\">&apos;hrad.jpeg&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents/hrad.jpeg&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># P&#x159;eps&#xE1;n&#xED; koncovky</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">with_suffix</span><span class=\"p\">(</span><span class=\"s1\">&apos;.bz2&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/Documents/archiv.tar.bz2&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Pokud existuj&#xED;c&#xED; koncovka nen&#xED;, `with_suffix` ji p&#x159;id&#xE1;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;myproject/README&apos;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">with_suffix</span><span class=\"p\">(</span><span class=\"s1\">&apos;.xz&apos;</span><span class=\"p\">)</span>\n<span class=\"go\">PosixPath(&apos;myproject/README.xz&apos;)</span>\n</pre></div><h2>Zkoum&#xE1;n&#xED; disku</h2>\n<p>V&#x161;echno uveden&#xE9; v&#xFD;&#x161;e jsou &#x10D;ist&#x11B; &#x201E;textov&#xE9;&#x201C; operace &#x2013; pracuj&#xED; jen se jm&#xE9;ny.\nSoubor <code>archiv.zip</code> (ani jin&#xE9;) po&#x10D;&#xED;ta&#x10D;i m&#xED;t, aby ses dostala k&#xA0;p&#x159;&#xED;pon&#x11B;\nnebo ke jm&#xE9;n&#x16F;m nad&#x159;azen&#xFD;ch adres&#xE1;&#x159;&#x16F;.</p>\n<div class=\"admonition note\"><p>Dokonce si m&#x16F;&#x17E;e&#x161; vyzkou&#x161;et, jak by to fungovalo na jin&#xE9;m syst&#xE9;mu &#x2013; m&#xED;sto <code>Path</code>\nnaimportuj a pou&#x17E;ij <code>PureWindowsPath</code> nebo <code>PurePosixPath</code>, kter&#xE9; reprezentuj&#xED;\nWindowsov&#xE9;, resp. Unixov&#xE9; cesty.</p>\n</div><p>Zamysli se: k&#xA0;&#x10D;emu se hod&#xED; um&#x11B;t pojmenovat soubor, kter&#xFD; neexistuje?</p>\n<div class=\"solution\" id=\"solution-0\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-2019-pondeli/intro/pathlib/index/solutions/0/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p>Jm&#xE9;no pot&#x159;ebuje&#x161; t&#x159;eba kdy&#x17E; chce&#x161; soubor vytvo&#x159;it.</p>\n    </div>\n</div><p>Te&#x10F; se dostaneme k&#xA0;operac&#xED;m pro kter&#xE9; je pot&#x159;eba m&#xED;t p&#x159;&#xED;stup k&#xA0;souborov&#xE9;mu\nsyst&#xE9;mu.</p>\n<p>Nejd&#x159;&#xED;ve dv&#x11B; funkce, kter&#xE9; vrac&#xED; cesty k&#xA0;u&#x17E;ite&#x10D;n&#xFD;m adres&#xE1;&#x159;&#x16F;m:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Aktu&#xE1;ln&#xED; adres&#xE1;&#x159;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">()</span>\n<span class=\"go\">PosixPath(&apos;/home/janca/pyladies/barvy&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># M&#x16F;j domovsk&#xFD; adres&#xE1;&#x159;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">home</span><span class=\"p\">()</span>\n<span class=\"go\">PosixPath(&apos;/home/janca&apos;)</span>\n</pre></div><p>A z&#xE1;kladn&#xED; ot&#xE1;zky &#x2013; existuje dan&#xFD; soubor?\nJe to norm&#xE1;ln&#xED; soubor nebo adres&#xE1;&#x159;?</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Existuje na t&#xE9; uk&#xE1;zkov&#xE9; cest&#x11B; n&#x11B;jak&#xFD; soubor?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">()</span>\n<span class=\"go\">False</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Existuje m&#x16F;j domovsk&#xFD; adres&#xE1;&#x159;?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">home</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">()</span>\n<span class=\"go\">True</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># A je to v&#x16F;bec adres&#xE1;&#x159;?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">home</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">is_dir</span><span class=\"p\">()</span>\n<span class=\"go\">True</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Je to norm&#xE1;ln&#xED; datov&#xFD; soubor?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">home</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">is_file</span><span class=\"p\">()</span>\n<span class=\"go\">False</span>\n</pre></div><h2>Uk&#xE1;zka</h2>\n<p>Abychom m&#x11B;li v&#x161;ichni stejn&#xE9; podm&#xED;nky, st&#xE1;hni si na dal&#x161;&#xED; experimenty\n<a href=\"/2019/brno-jaro-2019-pondeli/intro/pathlib/static/archiv.tar.gz\">archiv s&#xA0;testovac&#xED;mi soubory</a>.\nDej si ho do aktu&#xE1;ln&#xED;ho adres&#xE1;&#x159;e (<code>Path.cwd()</code>), a pak ho rozbal pomoc&#xED;\n<code>tarfile</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">tarfile</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cesta_k_archivu</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s2\">&quot;archiv.tar.gz&quot;</span><span class=\"p\">)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Co je v archivu?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">tarfile</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">cesta_k_archivu</span><span class=\"p\">,</span> <span class=\"s1\">&apos;r|gz&apos;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">getnames</span><span class=\"p\">()</span>\n<span class=\"go\">[&apos;soubory&apos;,</span>\n<span class=\"go\"> &apos;soubory/hrad.jpeg&apos;,</span>\n<span class=\"go\"> &apos;soubory/hrad.attribution&apos;,</span>\n<span class=\"go\"> &apos;soubory/.gitignore&apos;,</span>\n<span class=\"go\"> &apos;soubory/kolecko.png&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/vodnik.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/lidove&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/lidove/pes.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/lidove/holka.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/vladimir.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/cizojazycne&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/cizojazycne/iroha.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/texty/cizojazycne/witch.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/hlad.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/hraz.attribution&apos;,</span>\n<span class=\"go\"> &apos;soubory/ententyky.txt&apos;,</span>\n<span class=\"go\"> &apos;soubory/hraz.jpeg&apos;,</span>\n<span class=\"go\"> &apos;soubory/README&apos;]</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Extrakce archivu. (Kdybys to zkou&#x161;el/a pro jin&#xE9; archivy, v&#x17E;dy p&#x159;ed</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># rozbalen&#xED;m zkontroluj cesty v&#x161;ech soubor&#x16F; v archivu -- a&#x165; se rozbalen&#xED;m</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># nep&#x159;ep&#xED;&#x161;e n&#x11B;jak&#xFD; d&#x16F;le&#x17E;it&#xFD; soubor!)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">tarfile</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">cesta_k_archivu</span><span class=\"p\">,</span> <span class=\"s1\">&apos;r|gz&apos;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">extractall</span><span class=\"p\">()</span>\n</pre></div><p>Rozbalen&#xED;m archivu vznikl <code>./soubory/</code> (tedy: adres&#xE1;&#x159; <code>soubory</code> v aktu&#xE1;ln&#xED;m\nadres&#xE1;&#x159;i).\nPoj&#x10F; se mu kouknout na zoubek:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">zaklad</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;./soubory&apos;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">zaklad</span>\n<span class=\"go\">PosixPath(&apos;soubory&apos;)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Je to adres&#xE1;&#x159;?&apos;</span><span class=\"p\">,</span> <span class=\"n\">zaklad</span><span class=\"o\">.</span><span class=\"n\">is_dir</span><span class=\"p\">())</span>\n<span class=\"go\">Je to adres&#xE1;&#x159;? True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Je to norm&#xE1;ln&#xED; soubor?&apos;</span><span class=\"p\">,</span> <span class=\"n\">zaklad</span><span class=\"o\">.</span><span class=\"n\">is_file</span><span class=\"p\">())</span>\n<span class=\"go\">Je to norm&#xE1;ln&#xED; soubor? False</span>\n</pre></div><p>Podle informac&#xED; o archivu je v soubory n&#x11B;jak&#xFD; <code>ententyky.txt</code> &#x2013; podle p&#x159;&#xED;pony\nsoubor s&#xA0;textem.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">ententyky</span> <span class=\"o\">=</span> <span class=\"n\">zaklad</span> <span class=\"o\">/</span> <span class=\"s1\">&apos;ententyky.txt&apos;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Je to adres&#xE1;&#x159;?&apos;</span><span class=\"p\">,</span> <span class=\"n\">ententyky</span><span class=\"o\">.</span><span class=\"n\">is_dir</span><span class=\"p\">())</span>\n<span class=\"go\">Je to adres&#xE1;&#x159;? False</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Je to norm&#xE1;ln&#xED; soubor?&apos;</span><span class=\"p\">,</span> <span class=\"n\">ententyky</span><span class=\"o\">.</span><span class=\"n\">is_file</span><span class=\"p\">())</span>\n<span class=\"go\">Je to norm&#xE1;ln&#xED; soubor? True</span>\n</pre></div><p>Objekty <code>Path</code> lze pou&#x17E;&#xED;vat v naprost&#xE9; v&#x11B;t&#x161;in&#x11B; situac&#xED;, kdy jde pou&#x17E;&#xED;t cesta\njako &#x159;et&#x11B;zec.\nNap&#x159;&#xED;klad pro funkci <code>open</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">ententyky</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">&apos;utf-8&apos;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"nb\">file</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">())</span>\n</pre></div><p><code>Path</code> ale m&#xE1; <code>open</code> i jako metodu:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">with</span> <span class=\"n\">ententyky</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">&apos;utf-8&apos;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"nb\">file</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"nb\">file</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">())</span>\n</pre></div><p>A proto&#x17E;e je &#x10D;ten&#xED; cel&#xE9;ho textov&#xE9;ho obsahu souboru docela u&#x17E;ite&#x10D;n&#xE9;,\nexistuje i zkratka kter&#xE1; soubor otev&#x159;e, p&#x159;e&#x10D;te a zav&#x159;e najednou:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">ententyky</span><span class=\"o\">.</span><span class=\"n\">read_text</span><span class=\"p\">())</span>\n</pre></div><p>(V&#x11B;t&#x161;&#xED; soubory je ale lep&#x161;&#xED; otev&#x159;&#xED;t ve <code>with</code> a zpracov&#xE1;vat t&#x159;eba po &#x159;&#xE1;dc&#xED;ch,\naby se obsah nemusel do pam&#x11B;ti po&#x10D;&#xED;ta&#x10D;e na&#x10D;&#xED;st cel&#xFD; najednou.)</p>\n<p>Existuje i <code>write_text</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">cesta</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"s1\">&apos;pisnicka.txt&apos;</span>\n<span class=\"n\">cesta</span><span class=\"o\">.</span><span class=\"n\">write_text</span><span class=\"p\">(</span><span class=\"s1\">&apos;Holka modrook&#xE1;</span><span class=\"se\">\\n</span><span class=\"s1\">Nesed&#xE1;vej u potoka!&apos;</span><span class=\"p\">)</span>\n</pre></div><h2>A co adres&#xE1;&#x159;e?</h2>\n<p>I s adres&#xE1;&#x159;i um&#xED; <code>pathlib</code> pracovat.\nNejz&#xE1;kladn&#x11B;j&#x161;&#xED; operace je z&#xED;sk&#xE1;n&#xED; cest k obsa&#x17E;en&#xFD;m soubor&#x16F;m:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">zaklad</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">()</span>\n<span class=\"go\">&lt;generator object Path.iterdir at 0x7fbd4443b9e8&gt;</span>\n</pre></div><p>Metoda iterdir op&#x11B;t vrac&#xED; <em>iter&#xE1;tor</em> &#x2013; objekt, p&#x159;es kter&#xFD; mus&#xED;&#x161; &#x201E;proj&#xED;t&#x201C;\n(cyklem for, p&#x159;eveden&#xED;m na seznam ap.), abys z&#xA0;n&#x11B;j dostala obsah.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">zaklad</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">())</span>\n<span class=\"go\">[PosixPath(&apos;soubory/hrad.jpeg&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/hrad.attribution&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/.gitignore&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/kolecko.png&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/texty&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/hlad.txt&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/hraz.attribution&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/ententyky.txt&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/hraz.jpeg&apos;),</span>\n<span class=\"go\"> PosixPath(&apos;soubory/README&apos;)]</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">cesta</span> <span class=\"ow\">in</span> <span class=\"n\">zaklad</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">():</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>   <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">cesta</span><span class=\"p\">)</span>\n<span class=\"go\">soubory/hrad.jpeg</span>\n<span class=\"go\">soubory/hrad.attribution</span>\n<span class=\"go\">soubory/.gitignore</span>\n<span class=\"go\">soubory/kolecko.png</span>\n<span class=\"go\">soubory/texty</span>\n<span class=\"go\">soubory/hlad.txt</span>\n<span class=\"go\">soubory/hraz.attribution</span>\n<span class=\"go\">soubory/ententyky.txt</span>\n<span class=\"go\">soubory/hraz.jpeg</span>\n<span class=\"go\">soubory/README</span>\n</pre></div><h2>Strom adres&#xE1;&#x159;&#x16F; &#x2013; rekurze</h2>\n<p>Adres&#xE1;&#x159;e, podadres&#xE1;&#x159;e a soubory v&#xA0;nich tvo&#x159;&#xED; strukturu, na kterou se &#x10D;asto\npou&#x17E;&#xED;vaj&#xED; rekurzivn&#xED; funkce.</p>\n<p>Tady je funkce <code>vypis_soubory</code>, kter&#xE1; yp&#xED;&#x161;e v&#x161;echny soubory v dan&#xE9;m adres&#xE1;&#x159;i.\nP&#x159;ed ka&#x17E;d&#xE9; jm&#xE9;no d&#xE1; odr&#xE1;&#x17E;ku <code>-</code>, aby to l&#xED;p vypadalo:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">vypis_soubory</span><span class=\"p\">(</span><span class=\"n\">odrazka</span><span class=\"p\">,</span> <span class=\"n\">adresar</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vyp&#xED;&#x161;e odr&#xE1;&#x17E;kov&#xFD; seznam jmen soubor&#x16F; v dan&#xE9;m adres&#xE1;&#x159;i&quot;&quot;&quot;</span>\n    <span class=\"k\">for</span> <span class=\"n\">soubor</span> <span class=\"ow\">in</span> <span class=\"n\">adresar</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odrazka</span><span class=\"p\">,</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n<span class=\"n\">vypis_soubory</span><span class=\"p\">(</span><span class=\"s1\">&apos;-&apos;</span><span class=\"p\">,</span> <span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">())</span>\n</pre></div><p>Odr&#xE1;&#x17E;ka se d&#xE1; zadat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">vypis_soubory</span><span class=\"p\">(</span><span class=\"s1\">&apos;*&apos;</span><span class=\"p\">,</span> <span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">())</span>\n<span class=\"n\">vypis_soubory</span><span class=\"p\">(</span><span class=\"s1\">&apos;  *&apos;</span><span class=\"p\">,</span> <span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">())</span>\n</pre></div><p>Tahle funkce se d&#xE1; zm&#x11B;nit, aby vypsala i obsahy <em>podadres&#xE1;&#x159;&#x16F;</em>.\nJak?\nPot&#xE9;, co vyp&#xED;&#x161;e jm&#xE9;no n&#x11B;jak&#xE9;ho podadres&#xE1;&#x159;e, zavol&#xE1; funkci kter&#xE1; vyp&#xED;&#x161;e\nobsah toho podadres&#xE1;&#x159;e.\nTakovou funkci ale u&#x17E; m&#xE1;&#x161; napsanou &#x2013; sta&#x10D;&#xED; trochu zm&#x11B;nit odr&#xE1;&#x17E;ku, aby bylo\npoznat co je podadres&#xE1;&#x159;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">vypis_soubory</span><span class=\"p\">(</span><span class=\"n\">odrazka</span><span class=\"p\">,</span> <span class=\"n\">adresar</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vyp&#xED;&#x161;e odr&#xE1;&#x17E;kov&#xFD; seznam jmen soubor&#x16F; v dan&#xE9;m adres&#xE1;&#x159;i i podadres&#xE1;&#x159;&#xED;ch&quot;&quot;&quot;</span>\n    <span class=\"k\">for</span> <span class=\"n\">soubor</span> <span class=\"ow\">in</span> <span class=\"n\">adresar</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">():</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odrazka</span><span class=\"p\">,</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">is_dir</span><span class=\"p\">():</span>\n            <span class=\"n\">vypis_soubory</span><span class=\"p\">(</span><span class=\"s1\">&apos;  &apos;</span> <span class=\"o\">+</span> <span class=\"n\">odrazka</span><span class=\"p\">,</span> <span class=\"n\">soubor</span><span class=\"p\">)</span>\n\n<span class=\"n\">vypis_soubory</span><span class=\"p\">(</span><span class=\"s1\">&apos;-&apos;</span><span class=\"p\">,</span> <span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">())</span>\n</pre></div><p>Podobn&#x11B; lze nap&#x159;&#xED;klad spo&#x10D;&#xED;tat soubory v&#xA0;n&#x11B;jak&#xE9;m adres&#xE1;&#x159;i (i v&#x161;ech\npodadres&#xE1;&#x159;&#xED;ch).</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">spocitej_normalni_soubory</span><span class=\"p\">(</span><span class=\"n\">adresar</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vr&#xE1;t&#xED; po&#x10D;et norm&#xE1;ln&#xED;ch soubor&#x16F; v dan&#xE9;m adres&#xE1;&#x159;i i v&#x161;ech podadres&#xE1;&#x159;&#xED;ch&quot;&quot;&quot;</span>\n    <span class=\"n\">pocet</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"k\">for</span> <span class=\"n\">soubor</span> <span class=\"ow\">in</span> <span class=\"n\">adresar</span><span class=\"o\">.</span><span class=\"n\">iterdir</span><span class=\"p\">():</span>\n        <span class=\"k\">if</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">is_dir</span><span class=\"p\">():</span>\n            <span class=\"n\">pocet</span> <span class=\"o\">=</span> <span class=\"n\">pocet</span> <span class=\"o\">+</span> <span class=\"n\">spocitej_normalni_soubory</span><span class=\"p\">(</span><span class=\"n\">soubor</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">soubor</span><span class=\"o\">.</span><span class=\"n\">is_file</span><span class=\"p\">():</span>\n            <span class=\"n\">pocet</span> <span class=\"o\">=</span> <span class=\"n\">pocet</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n    <span class=\"k\">return</span> <span class=\"n\">pocet</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">spocitej_normalni_soubory</span><span class=\"p\">(</span><span class=\"n\">Path</span><span class=\"o\">.</span><span class=\"n\">cwd</span><span class=\"p\">()))</span>\n</pre></div>\n\n\n        "
    }
  }
}