Nacházíte se zde: Domů ‣ Ponořme se do Pythonu 3 ‣
Úroveň obtížnosti: ♦♦♦♢♢
❝ I’m telling you this ’cause you’re one of my friends.
My alphabet starts where your alphabet ends! ❞
(Protože jedním z mých přátel jsi, tak říkám ti:
Má abeceda začíná tam, kde tvá končí!)
— Dr. Seuss, On Beyond Zebra!
Přemýšlí o tom jen málo lidí, ale text je neuvěřitelně komplikovaný. Začněme s abecedou. Obyvatelé Bougainville používají nejmenší abecedu na světě. Jejich abeceda Rotokas se skládá z pouhých 12 písmen: A, E, G, I, K, O, P, R, S, T, U a V. Na opačném konci spektra najdeme jazyky, jako jsou čínština, japonština a korejština, které používají tisíce znaků. Angličtina používá 26 písmen — nebo 52, pokud počítáte zvlášť malá a velká písmena — a k tomu pár interpunkčních znaků, jako jsou !@#$%&.
Pokud v souvislosti s počítači mluvíte o „textu“, pak pravděpodobně myslíte „znaky a symboly na počítačové obrazovce“. Ale počítače nepracují se znaky a symboly. Pracují s bity a bajty. Každý kousek textu, který jste kdy spatřili na počítačové obrazovce, byl ve skutečnosti uložen v určitém znakovém kódování. Zhruba řečeno, kódování znaků zachycuje vztah mezi tím, co vidíte na obrazovce, a tím, co je ve skutečnosti uloženo v paměti počítače a na disku. Znakových kódování se používá velmi mnoho. Některá jsou optimalizována pro konkrétní jazyk, jakým je ruština, čínština nebo angličtina. Jiná kódování se mohou používat pro více jazyků.
Ve skutečnosti je to ještě mnohem komplikovanější. Řada znaků je společná pro více různých kódování, ale každé kódování může pro jejich uložení v paměti nebo na disku používat jinou posloupnost bajtů. Takže o znakovém kódování můžete uvažovat jako o dešifrovacím klíči. Kdykoliv vám někdo poskytne posloupnost bajtů — soubor, webovou stránku, cokoliv — a bude tvrdit, že to je „text“, budete k úspěšnému dekódování bajtů na znaky chtít vědět také to, jaké kódování znaků bylo použito. Pokud vám někdo poskytne špatný klíč nebo vám dokonce nedá žádný, postaví vás před nevyhnutelný úkol rozlousknout kód sami. Může se stát, že při tom uděláte chybu a výsledek bude zmatený.
Určitě už jste viděli webové stránky s podivnými znaky podobnými otazníku na místech, kde měly být apostrofy. Obvykle to znamená, že autor stránky neuvedl jejich správné kódování a váš prohlížeč musel hádat. Výsledkem byla směs očekávaných a neočekávaných znaků. U anglického textu to vnímáme spíš jen rušivě, ale v jiných jazycích může být výsledek zcela nečitelný.
Každý význačný jazyk na světě má definováno své znakové kódování. Každé kódování znaků bylo kvůli rozdílům v jazycích optimalizováno pro konkrétní jazyk, protože paměťový a diskový prostor byly v minulosti velmi drahé. Mám tím na mysli to, že pro reprezentaci znaků jazyka používalo každé kódování stejný interval čísel (0–255). Pravděpodobně znáte například kódování ASCII, které ukládá anglické znaky jako čísla z intervalu 0 až 127. (65 je velké „A“, 97 je malé „a“ atd.) Angličtina má velmi jednoduchou abecedu, která může být úplně vyjádřena méně než 128 čísly. Pro ty z vás, kteří umí počítat ve dvojkové soustavě, na to stačí 7 z 8 bitů v bajtu.
Západoevropské jazyky, jakou jsou francouzština, španělština a němčina, používají více znaků než angličtina. Přesněji řečeno, najdete v nich písmena kombinovaná s různými diakritickými značkami, jako například u znaku ñ
používaného ve španělštině. Nejběžnějším kódováním je u těchto jazyků CP-1252. Označuje se také „windows-1252“, protože se široce používá v Microsoft Windows. Kódování CP-1252 sdílí znaky v intervalu 0–127 s ASCII, ale rozpíná se i do intervalu 128–255. Nalezneme v něm takové znaky jako n-s-vlnkou (241), u-s-přehláskou (252) atd. Pořád ale jde o jednobajtové kódování. Největší možné číslo (255) se pořád vejde do jednoho bajtu.
Pak tu ale máme jazyky, jako je čínština, japonština a korejština, které používají takové množství znaků, že vyžadují vícebajtové znakové sady. Každý jejich „znak“ je vyjádřen dvoubajtovým číslem v intervalu 0–65535. Ale u různých vícebajtových kódování se pořád setkáváme se stejným problémem, jako u různých jednobajtových kódování. Každé z nich používá stejná čísla pro vyjádření různých věcí. Používají jen širší interval čísel, protože musí vyjádřit mnohem více znaků.
Ve světě, který ještě nebyl propojen sítí a kde „text“ bylo něco, co jste si sami napsali a příležitostně vytiskli, to většinou bylo přijatelné. „Prostého textu“ jste ale moc nenašli. Zdrojové texty byly v ASCII a všichni ostatní používali textové procesory, které definovaly své vlastní (netextové) formáty. Ty si spolu s informacemi o stylu ukládaly také informaci o znakovém kódování. Lidé tyto dokumenty četli prostřednictvím stejných textových procesorů, jaké použil původní autor, takže všechno víceméně fungovalo.
Teď si představte vzestup globálních sítí s elektronickou poštou a s webem. Spousty „prostých textů“ létají kolem zeměkoule — byly napsány na jednom počítači, přeneseny přes druhý a zobrazovány na třetím počítači. Počítače vidí jen čísla. Ale čísla mohou znamenat různé věci. Ach ne! Co budeme dělat? Takže systém musel být navržen tak, aby si každý „prostý text“ s sebou nesl informaci o kódování. Připomeňme si, že jde o dešifrovací klíč, který převádí čísla srozumitelná počítači na znaky čitelné člověkem. Chybějící dešifrovací klíč vede ke zkreslenému textu, zmatkům nebo k něčemu horšímu.
Teď si představte, že bychom více kusů textu chtěli uložit na stejném místě, jako například ve stejné databázové tabulce uchovávající doručenou elektronickou poštu. Pro každý kousek musíme stejně uložit i znakové kódování, abychom text dokázali správně zobrazit. Myslíte si, že je to příliš tvrdý požadavek? Zkuste ve své e-mailové databázi vyhledávat. To znamená, že budete muset za běhu provádět převody mezi různými kódováními. Tady přestává legrace, že?
Teď si představte, že byste měli vícejazyčné dokumenty, ve kterých se znaky z různých jazyků vyskytují vedle sebe, v tom samém dokumentu. (Nápověda: Programy, které se o to pokoušely, typicky používaly pomocné kódy (escape) pro přepínání „režimů“. Prásk, teď jste v ruském režimu koi8-r, takže 241 znamená Я; bum, teď jste řeckém režimu pro Mac, takže 241 znamená ώ.) I v takových dokumentech byste samozřejmě chtěli umět vyhledávat.
Tak a teď plačte, protože vše, co jste si mysleli, že o řetězcích víte, je vám k ničemu. Nic takového jako „prostý text“ neexistuje.
⁂
Vstupte do světa Unicode.
Unicode je systém navržený tak, aby bylo možné vyjádřit každý znak z každého jazyka. Každé písmeno, znak nebo ideogram se v Unicode vyjadřují jako 4bajtové číslo. Každé číslo vyjadřuje jedinečný znak, který se používá alespoň v jednom jazyce našeho světa. (Ne všechna čísla jsou využita, ale těch použitých je více než 65535. To znamená, že dva bajty nestačí.) Znaky, které se používají ve více jazycích, mají obvykle stejné číslo — pokud neexistuje dobrý etymologický důvod, aby tomu tak nebylo. Bez ohledu na další okolnosti je ale pro každý znak vyhrazeno jedno číslo a pro každé číslo jen jeden znak. Jedno číslo vždy znamená jedinou věc. Nepoužívají se žádné dříve zmíněné „režimy“. U+0041
znamená vždy 'A'
, a to i v případech, pokud by váš jazyk 'A'
nepoužíval.
Na první pohled to vypadá jako výborná myšlenka. Jedno kódování vládne všem. Více jazyků v jednom dokumentu. Už nikdy více „přepínání režimu“ uprostřed textu jen kvůli přepnutí kódování. Ale už v této chvíli by vás měla napadnout zjevná otázka. Čtyři bajty? Pro každý jeden znak‽ To vypadá jako hrozné plýtvání. Obzvlášť pro jazyky, jako jsou angličtina nebo španělština, které k vyjádření každého používaného znaku potřebují méně než jeden bajt (256 čísel). Ve skutečnosti je to plýtvání i pro jazyky založené na ideogramech (jako je čínština), které na jeden znak nepotřebují nikdy více než dva bajty.
Existuje kódování Unicode, které používá čtyři bajty na znak. Nazývá se UTF-32, podle počtu 32 bitů, což jsou 4 bajty. UTF-32 je přímočaré kódování. Každé číslo uložené na čtyřech bajtech se reprezentuje jako Unicode znak se stejným číslem. Má to své výhody. Nejdůležitější z nich je ta, že N-tý znak řetězce můžeme zpřístupnit v konstantním čase. N-tý znak totiž začíná na 4×N-tém bajtu. Ale má to i nevýhody. Ta nejzjevnější je, že na každý podělaný znak potřebujeme čtyři bajty.
Znaků je v Unicode velmi mnoho, ale ukazuje se, že většina lidí nepoužije nikdy žádný, který by ležel mimo prvních 65535. Takže tu máme další kódování Unicode. Nazývá se UTF-16 (protože 16 bitů jsou 2 bajty). V UTF-16 se každý znak s číslem z intervalu 0–65535 kóduje do dvou bajtů. Pokud opravdu potřebujeme vyjádřit zřídka používané Unicode znaky z „astrální roviny“ (přesahující 65535), používá UTF-16 jisté špinavé triky. Nejzjevnější výhoda: UTF-16 je prostorově dvakrát efektivnější než UTF-32, protože pro uložení každého znaku potřebujeme jen dva bajty místo čtyř (s výjimkou těch, pro které to neplatí). A pokud budeme předpokládat, že řetězec neobsahuje žádné znaky z astrální roviny, můžeme snadno najít N-tý znak v konstantním čase. Ten předpoklad je docela dobrý, ale jen do doby, kdy to přestane platit.
Ale jak UTF-32, tak UTF-16 mají také méně zřejmé nevýhody. Různé počítačové systémy ukládají jednotlivé bajty různým způsobem. Tak například znak U+4E2D
by mohl být v UTF-16 uložen buď jako 4E 2D
nebo 2D 4E
. Závisí to na tom, zda systém používá přístup big-endian (na menší adrese významnější bajt) nebo little-endian (na menší adrese méně významný bajt). (Pro UTF-32 existují dokonce ještě další možnosti uspořádání bajtů.) Pokud váš dokument nikdy neopustí váš počítač, je to v suchu — různé aplikace budou na stejném počítači používat stejné pořadí bajtů. Ale v okamžiku, kdy budete chtít dokument přenášet mezi systémy, třeba prostřednictvím webu nebo něčeho takového, budeme potřebovat způsob, jak vyjádřit námi používané pořadí uložených bajtů. V opačném případě by cílový systém neuměl zjistit, zda dvoubajtová posloupnost 4E 2D
znamená U+4E2D
nebo U+2D4E
.
Vícebajtová kódování Unicode pro vyřešení tohoto problému definují „Byte Order Mark“ (značka pořadí bajtů; zkráceně BOM). Jde o speciální netisknutelný znak, který můžete vložit na začátek svého dokumentu, abyste dali najevo, v jakém pořadí jsou vaše bajty uvedeny. Pro UTF-16 je Byte Order Mark roven U+FEFF
. Pokud obdržíte dokument v UTF-16 začínající bajty FF FE
, pak víte, že jde o jedno z možných pořadí bajtů. Pokud začíná bajty FE FF
, pak víte, že pořadí bajtů je obrácené.
Přesto UTF-16 není zcela ideální. Platí to zvláště v případech, kdy používáte velké množství ASCII znaků. Když o tom popřemýšlíte, dokonce i čínské webové stránky budou obsahovat velké množství ASCII znaků — všechny ty značky a atributy, které obklopují tisknutelné čínské znaky. Pokud umíme najít N-tý znak v konstantním čase, je to fajn. Ale pořád tu máme nepříjemný problém s těmi znaky z astrální roviny. To znamená, že nemůžete zaručit, že každý znak je uložen přesně na dvou bajtech. Takže ve skutečnosti nemůžete N-tý znak najít v konstantním čase — pokud si ovšem neudržujete oddělený index. A mezi námi, ve světě se nachází ohromné množství ASCII textů…
Těmito otázkami se už zabývali jiní a přišli s řešením:
UTF-8
UTF-8 je kódovací systém s proměnnou délkou. To znamená, že různé Unicode znaky zabírají různý počet bajtů. Pro ASCII znaky (A-Z atd.) používá UTF-8 jen jeden bajt na znak. Ve skutečnosti používá přesně tentýž bajt. Prvních 128 znaků (0–127) se v UTF-8 nedá rozlišit od ASCII. Znaky z „rozšířené latinky“, jako jsou ñ a ö, budou zabírat dva bajty. (Bajty zde nevyjadřují kód z Unicode tak jednoduchým způsobem, jako je tomu u UTF-16. Je do toho zataženo trošku složitější hraní si s bity.) Čínské znaky jako 中 zabírají tři bajty. Zřídka používané znaky z „astrální roviny“ zabírají čtyři bajty.
Nevýhody: Protože každý znak zabírá různý počet bajtů, je nalezení N-tého znaku operací o složitosti O(N). To znamená, že čím je řetězec delší, tím déle budeme znak na určené pozici vyhledávat. Při kódování znaků na bajty a dekódování bajtů na znaky se musíme navíc zabývat dalšími manipulacemi s bity.
Výhody: Kódovaní běžných ASCII znaků je extrémně efektivní. Při kódování znaků z rozšířené latinky není horší než UTF-16. Pro čínské znaky je lepší než UTF-32. A díky jednoznačnému způsobu manipulace s bity zde neexistují žádné problémy s pořadím bajtů. (To mi musíte věřit, protože to tady nebudu matematicky zdůvodňovat.) Dokument kódovaný v UTF-8 používá na každém počítači přesně stejnou posloupnost bajtů.
⁂
V Pythonu 3 jsou všechny řetězce posloupnostmi znaků v Unicode. Nenajdeme zde nic takového jako pythonovský řetězec kódovaný v UTF-8 nebo pythonovský řetězec kódovaný v CP-1252. „Je tento řetězec v UTF-8?“ — toto je nesmyslná otázka. UTF-8 představuje způsob kódování znaků do posloupnosti bajtů. Pokud chcete vzít řetězec a přeměnit jej na posloupnost bajtů v určitém znakovém kódování, může vám v tom Python 3 pomoci. Pokud chcete vzít posloupnost bajtů a přeměnit ji na řetězec, pomůže vám s tím Python 3 také. Ale bajty nejsou znaky. Bajty jsou prostě bajty. Znak je abstrakce. A řetězce jsou posloupnostmi těchto abstrakcí.
>>> s = '深入 Python' ① >>> len(s) ② 9 >>> s[0] ③ '深' >>> s + ' 3' ④ '深入 Python 3'
'
; single quotes) nebo do uvozovek ("
; double quotes).
len()
vrací délku řetězce, tj. počet znaků. Je to stejná funkce, jakou používáme pro nalezení délky seznamu, n-tice, množiny nebo slovníku. Řetězec připomíná n-tici znaků.
+
provádí konkatenaci řetězců (zřetězení, spojení), stejně jako u seznamů.
⁂
Podívejme se znovu na humansize.py
:
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], ①
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
'''Convert a file size to human-readable form. ②
Keyword arguments:
size -- file size in bytes
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
if False, use multiples of 1000
Returns: string
''' ③
if size < 0:
raise ValueError('number must be non-negative') ④
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
for suffix in SUFFIXES[multiple]:
size /= multiple
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix) ⑤
raise ValueError('number too large')
'KB'
, 'MB'
, 'GB'
… to všechno jsou řetězce.
Python 3 podporuje formátování hodnot do řetězců. Možné jsou i velmi komplikované výrazy, ale nejzákladnější použití spočívá ve vložení hodnoty do řetězce s jednou oblastí náhrad.
>>> username = 'mark' >>> password = 'PapayaWhip' ① >>> "{0}'s password is {1}".format(username, password) ② "mark's password is PapayaWhip"
{0}
a {1}
jsou oblasti náhrad (replacement fields), do kterých budou dosazeny argumenty předané metodě format()
.
Předchozí příklad ukazoval nejjednodušší případ, kdy jsou v oblastech náhrad použita pouze celá čísla. Celá čísla se v oblastech náhrad považují za indexy do seznamu argumentů metody format()
. To znamená, že {0}
je nahrazena prvním argumentem (v našem případě username), {1}
je nahrazena druhým argumentem (password) atd. Můžeme použít tolik pozičních indexů, kolik máme argumentů. A argumentů můžeme mít tolik, kolik chceme. Ale oblasti náhrad jsou ještě mnohem mocnější.
>>> import humansize >>> si_suffixes = humansize.SUFFIXES[1000] ① >>> si_suffixes ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] >>> '1000{0[0]} = 1{0[1]}'.format(si_suffixes) ② '1000KB = 1MB'
humansize
si půjčíme jednu z datových struktur, která je v něm definována: seznam přípon jednotek „SI“ (mocniny čísla 1000).
{0}
se odkazuje na první argument předaný metodě format()
, tedy na si_suffixes. Ale si_suffixes má podobu seznamu. Takže {0[0]}
odkazuje na první položku seznamu, který je prvním argumentem předaným metodě format()
: 'KB'
. Podobně {0[1]}
odkazuje na druhou položku stejného seznamu: 'MB'
. Všechno vně složených závorek — včetně 1000
, rovnítka a mezer — zůstává nedotčeno. Konečným výsledkem je řetězec '1000KB = 1MB'
.
Tento příklad ukazuje, že specifikátory formátu mohou pro zpřístupnění položek a vlastností datových struktur používat (téměř) pythonovskou syntaxi. Říká se tomu složená jména oblastí (compound field names). Funkční jsou následující složená jména oblastí:
Abych vás ohromil, tady máte příklad, který vše kombinuje:
>>> import humansize >>> import sys >>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys) '1MB = 1000KB'
A teď si popíšeme, jak to funguje:
sys
v sobě udržuje informace o momentálně běžící pythonovské instanci. Protože jsme provedli jeho import, můžeme celý modul sys
předat jako argument metody format()
. Takže pole náhrad {0}
odkazuje na modul sys
.
sys.modules
je slovník všech modulů, které byly importovány touto instancí Pythonu. V roli klíčů vystupují jména modulů uvedená jako řetězce. Hodnotami jsou vlastní objekty modulů. Takže oblast náhrad {0.modules}
odkazuje na slovník importovaných modulů.
sys.modules['humansize']
odkazuje na modul humansize
module, který jsme právě importovali. Oblast náhrad {0.modules[humansize]}
odkazuje na modul humansize
. Povšimněte si zde malého rozdílu v syntaxi. Ve skutečném pythonovském kódu jsou klíči slovníku sys.modules
řetězce. Abychom se jimi mohli odkázat, musíme jméno modulu uzavřít do apostrofů (jako například 'humansize'
). Jenže uvnitř oblasti náhrad apostrofy kolem slovníkového klíče vynecháváme (tj. humansize
). Citujme PEP 3101: Advanced String Formatting, „Pravidla pro předávání klíčů položek jsou velmi jednoduchá. Pokud klíč začíná číslicí, bude chápán jako číslo. V ostatních případech bude použit jako řetězec.“
sys.modules['humansize'].SUFFIXES
je slovník definovaný na začátku modulu humansize
. Odkazuje se na něj oblast náhrad {0.modules[humansize].SUFFIXES}
.
sys.modules['humansize'].SUFFIXES[1000]
je seznam přípon jednotek SI: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
. Takže oblast náhrad {0.modules[humansize].SUFFIXES[1000]}
se odkazuje na zmíněný seznam.
sys.modules['humansize'].SUFFIXES[1000][0]
je první položkou seznamu přípon jednotek SI: 'KB'
. Z toho plyne, že celá oblast náhrad {0.modules[humansize].SUFFIXES[1000][0]}
je nahrazena dvojznakovým řetězcem KB
.
Ale počkat! Ono je toho ještě víc! Podívejme se ještě jednou na tento divný řádek kódu ze souboru humansize.py
:
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix)
{1}
je nahrazena druhým argumentem předaným metodě format()
, a tím je suffix. Ale co znamená {0:.1f}
? Jde o dvě věci: význam {0}
už znáte, ale význam :.1f
ještě ne. Druhá část (dvojtečka a to, co následuje) definuje specifikátor formátu (format specifier), který upřesňuje, jak má být dosazovaná hodnota formátována.
☞Specifikátory formátu vám dovolí upravit výsledný text do řady užitečných podob — podobně jako funkce
printf()
v jazyce C. Můžete přidat vycpávku z nul nebo z mezer, zarovnat řetězce, řídit počet desetinných míst a dokonce konvertovat čísla do šestnáctkové soustavy.
Dvojtečka (:
) uvnitř oblasti náhrad označuje začátek specifikátoru formátu. Specifikátor „.1
“ znamená „zaokrouhli na nejbližší desetiny“ (tj. zobraz jen jedno místo za desetinnou tečkou). Specifikátor „f
“ znamená „číslo s pevnou řádovou čárkou“ (jako opak k exponenciálnímu zápisu nebo k jiným způsobům reprezentace čísla). Takže pokud má size hodnotu 698.24
a suffix hodnotu 'GB'
, pak naformátovaný řetězec bude mít podobu '698.2 GB'
. Hodnota 698.24
bude zaokrouhlena na jedno desetinné místo a hodnota suffix bude připojena za číslo.
>>> '{0:.1f} {1}'.format(698.24, 'GB') '698.2 GB'
Detaily kolem specifikátorů formátů naleznete v oficiální pythonovské dokumentaci, v části Format Specification Mini-Language.
⁂
S řetězci můžeme, kromě formátování, provádět řadu dalších užitečných kousků.
>>> s = '''Finished files are the re- ① ... sult of years of scientif- ... ic study combined with the ... experience of years.''' >>> s.splitlines() ② ['Finished files are the re-', 'sult of years of scientif-', 'ic study combined with the', 'experience of years.'] >>> print(s.lower()) ③ finished files are the re- sult of years of scientif- ic study combined with the experience of years. >>> s.lower().count('f') ④ 6
splitlines()
přebírá jeden víceřádkový řetězec a vrací seznam řetězců, ve kterém každá položka reprezentuje jeden řádek z originálu. Všimněte si, že znaky konců řádků nejsou do jednotlivých řádků zahrnuty.
lower()
převádí celý řetězec na malá písmena. (Podobně zase metoda upper()
převádí řetězec na velká písmena.)
count()
vrací počet výskytů zadaného podřetězce. Ano, v uvedené větě je opravdu šest „f“!
Vezměme si další běžný případ. Dejme tomu, že máme seznam dvojic klíč-hodnota ve tvaru key1=value1&key2=value2
a my bychom je chtěli rozdělit a vytvořit z nich slovník v podobě {key1: value1, key2: value2}
.
>>> query = 'user=pilgrim&database=master&password=PapayaWhip' >>> a_list = query.split('&') ① >>> a_list ['user=pilgrim', 'database=master', 'password=PapayaWhip'] >>> a_list_of_lists = [v.split('=', 1) for v in a_list if '=' in v] ② >>> a_list_of_lists [['user', 'pilgrim'], ['database', 'master'], ['password', 'PapayaWhip']] >>> a_dict = dict(a_list_of_lists) ③ >>> a_dict {'password': 'PapayaWhip', 'user': 'pilgrim', 'database': 'master'}
split()
jsme zadali jeden argument, hodnotu oddělovače. Metoda v místech zadaného oddělovače rozdělí řetězec na seznam řetězců. Zde je jako oddělovač použit znak ampersand, ale může to být cokoliv.
split()
říká, kolikrát chceme dělení řetězce provést. Hodnota 1
znamená „rozdělit jen jednou“, takže metoda split()
vrátí dvouprvkový seznam. (Hodnota by teoreticky mohla také obsahovat znak rovnítka. Pokud bychom použili pouze 'key=value=foo'.split('=')
, dostali bychom seznam s třemi prvky ['key', 'value', 'foo']
.)
dict()
.
☞Předchozí příklad se hodně podobá získávání parametrů dotazu uvedeného v URL, ale rozklad opravdu používaných URL je ve skutečnosti složitější. Pokud se máte zabývat parametry dotazu v URL, pak pro vás bude mnohem lepší, když použijete funkci
urllib.parse.parse_qs()
. Ta je schopná zvládnout i některé ne příliš zřejmé hraniční případy.
Jakmile máme vytvořen řetězec, můžeme získat jakoukoliv jeho část v podobě nového řetězce. Anglicky se tomu říká „slicing the string“, což můžeme přeložit jako „vykrajování z řetězce“ nebo „výřez z řetězce“. Vykrajování podřetězců funguje naprosto stejně jako vykrajování podseznamů. Ono to dává smysl, protože řetězce jsou prosté posloupnosti znaků.
>>> a_string = 'My alphabet starts where your alphabet ends.' >>> a_string[3:11] ① 'alphabet' >>> a_string[3:-3] ② 'alphabet starts where your alphabet en' >>> a_string[0:2] ③ 'My' >>> a_string[:18] ④ 'My alphabet starts' >>> a_string[18:] ⑤ ' where your alphabet ends.'
a_string[0:2]
vrací první dva znaky řetězce počínaje znakem a_string[0]
až po a_string[2]
vyjma (ten už ve výsledku nebude).
a_string[:18]
je stejný jako a_string[0:18]
. Počáteční nula se dosadí jako implicitní hodnota.
a_string[18:]
je totéž jako a_string[18:44]
, protože v tomto řetězci se nachází 44 znaků. A najdeme zde opět potěšitelnou symetrii. Pro tento 44znakový řetězec vrací zápis a_string[:18]
prvních 18 znaků a a_string[18:]
vrací vše kromě prvních 18 znaků. Obecně platí, že a_string[:n]
vždy vrátí prvních n znaků a a_string[n:]
vrátí zbytek — nezávisle na délce řetězce.
⁂
Bajty jsou bajty, znaky jsou abstrakce. Neměnitelná posloupnost Unicode znaků se nazývá řetězec. Neměnitelná posloupnost čísel z intervalu 0–255 se nazývá objekt typu bytes.
>>> by = b'abcd\x65' ① >>> by b'abcde' >>> type(by) ② <class 'bytes'> >>> len(by) ③ 5 >>> by += b'\xff' ④ >>> by b'abcde\xff' >>> len(by) ⑤ 6 >>> by[0] ⑥ 97 >>> by[0] = 102 ⑦ Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'bytes' object does not support item assignment
bytes
definujeme použitím b''
, tedy syntaxe pro „bajtový literál“ . Každý bajt uvnitř bajtového literálu může být buď ASCII znak, nebo zakódované šestnáctkové číslo od \x00
do \xff
(0–255).
bytes
.
bytes
můžeme získat zabudovanou funkcí len()
, tedy stejně jako u seznamů a řetězců.
bytes
můžeme použít operátor +
. Výsledkem je nový objekt typu bytes
.
bytes
vznikne 6bajtový objekt typu bytes
.
bytes
zpřístupnit indexovou notací. Položkami řetězců jsou znaky, položkami objektu typu bytes
jsou čísla. Konkrétně jsou to celá čísla z intervalu 0–255.
bytes
je neměnitelný (immutable). Jednotlivým bajtům nemůžeme nic přiřadit. Pokud potřebujete měnit jednotlivé bajty, můžete buď použít výřezy (slicing) a operátor konkatenace (fungují stejně jako u řetězců), nebo můžete objekt typu bytes
konvertovat na objekt typu bytearray
.
>>> by = b'abcd\x65' >>> barr = bytearray(by) ① >>> barr bytearray(b'abcde') >>> len(barr) ② 5 >>> barr[0] = 102 ③ >>> barr bytearray(b'fbcde')
bytes
na objekt měnitelného typu bytearray
použijte zabudovanou funkci bytearray()
.
bytes
, můžete provádět i s objektem typu bytearray
.
bytearray
můžete při využití indexové notace přiřazovat hodnoty jednotlivým bajtům. Přiřazovaná hodnota musí být celé číslo v intervalu 0–255.
Jednou z věcí, které nikdy nemůžete udělat, je míchání bajtů s řetězci.
>>> by = b'd' >>> s = 'abcde' >>> by + s ① Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't concat bytes to str >>> s.count(by) ② Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't convert 'bytes' object to str implicitly >>> s.count(by.decode('ascii')) ③ 1
A tady máme spojení mezi řetězci a bajty: objekt typu bytes
má metodu decode()
, která přebírá znakové kódování a vrací řetězec. A řetězce zase mají metodu encode()
, která přebírá znakové kódování a vrací objekt typu bytes
. V předchozím případě bylo dekódování poměrně přímočaré — co se týká konverze posloupnosti bajtů v kódování ASCII na řetězec znaků. Ale stejný postup funguje pro libovolné kódování, které odpovídá znakům řetězce. Platí to dokonce i pro historická (ne Unicode) kódování.
>>> a_string = '深入 Python' ① >>> len(a_string) 9 >>> by = a_string.encode('utf-8') ② >>> by b'\xe6\xb7\xb1\xe5\x85\xa5 Python' >>> len(by) 13 >>> by = a_string.encode('gb18030') ③ >>> by b'\xc9\xee\xc8\xeb Python' >>> len(by) 11 >>> by = a_string.encode('big5') ④ >>> by b'\xb2`\xa4J Python' >>> len(by) 11 >>> roundtrip = by.decode('big5') ⑤ >>> roundtrip '深入 Python' >>> a_string == roundtrip True
bytes
. Obsahuje 13 bajtů. Posloupnost bajtů vznikla zakódováním řetězce a_string do UTF-8.
bytes
obsahuje 11 bajtů. Vznikl zakódováním řetězce a_string v kódování GB18030.
bytes
. Má 11 bajtů. Jde o zcela jinou posloupnost bajtů, která vznikla zakódováním řetězce a_string v kódování Big5.
⁂
Python 3 předpokládá, že váš zdrojový kód — tj. každý soubor s příponou .py
— je uložen v kódování UTF-8.
☞V Pythonu 2 bylo u souborů s příponou
.py
výchozím kódováním ASCII. V Pythonu 3 je výchozím kódováním UTF-8.
Pokud byste ve svých zdrojových textech chtěli používat jiné kódování, můžete na první řádek souboru vložit deklaraci použitého kódování. Tato deklarace říká, že soubor .py
používá kódování windows-1252:
# -*- coding: windows-1252 -*-
Z technického pohledu můžete deklaraci použitého kódování umístit i na druhý řádek. Na prvním řádku se může vyskytovat UNIXovský magický příkazový komentář (hash-bang command).
#!/usr/bin/python3
# -*- coding: windows-1252 -*-
Více informací naleznete v PEP 263: Defining Python Source Code Encodings.
⁂
O Unicode v jazyce Python:
O Unicode obecně:
O znakovém kódování v jiných formátech:
O řetězcích a jejich formátování:
string
— Common string operations
© 2001–11 Mark Pilgrim