Você está aqui: Início ‣ Mergulhar Em Python 3 ‣
Nível de Dificuldade: ♦♦♦♢♢
❝ I’m telling you this ’cause you’re one of my friends.
My alphabet starts where your alphabet ends! ❞
— Dr. Seuss, On Beyond Zebra!
Poucas pessoas pensam nisto, mas texto é incrivelmente complicado. Começando pelo alfabeto. As pessoas de Bougainville têm o alfabeto mais pequeno do mundo; o seu alfabeto Rotokas é composto por apenas 12 letras: A, E, G, I, K, O, P, R, S, T, U, e V. No outro lado do espectro, línguas como o Chinês, Japonês, e Coreano têm milhares de caracteres. O Inglês, claro, tem 26 letras — 52 se contar maiúsculas e minúsculas separadamente — mais uma mão cheia de sinais de pontuação !@#$%&.
Quando fala de “texto,” está provavelmente a pensar em “caracteres e símbolos no ecrã do meu computador.” Mas os computadores não trabalham em caracteres e símbolos; eles trabalham em bits e bytes. Qualquer bocado de texto que já se tenha visto no ecrã de um computador está na realidade armazenado numa certa codificação de caracteres. Falando informalmente, a codificação de caracteres fornece um mapeamento entre o que nós vemos nos nossos ecrãs e o que os nossos computadores realmente armazenam em memória ou em disco. Há muitas codificações de caracteres diferentes, algumas optimizadas para determinadas línguas como Russo ou Chinês ou Inglês, e outras que podem ser usadas para várias línguas.
Na realidade, é mais complicado que isso. Muitos caracteres são comuns a várias codificações, mas cada codificação pode usar uma sequência de bytes diferente para realmente armazenar esses caracteres em memória ou em disco. Podemos então pensar na codificação de caracteres como uma espécie de chave de desencriptação. Quando alguém nos dá uma sequência de bytes — um ficheiro, uma página web, qualquer coisa — e afirma que é “texto,” nós precisamos de saber que codificação de caracteres eles usaram para que possamos descodificar os bytes para caracteres. Se nos derem a chave errada ou nenhuma chave, ficamos com a desagradável tarefa de quebrar o código. O mais provável será errarmos, e o resultado ser lixo.
Certamente já viu páginas web como esta, com uns caracteres estranhos parecidos com pontos de interrogação onde deveriam estar apóstrofes. Isso geralmente significa que o autor da página não declarou a sua condificação de caracteres correctamente, o seu browser teve que adivinhar, e o resultado foi uma mistura de caracteres esperados e inesperados. Em Inglês é apenas incómodo; em outras línguas, o resultado pode ser completamente ilegível.
Há codificações de caracteres para cada língua principal no mundo. Uma vez que cada língua é diferente, e espaço em memória e em disco tem sido caro historicamente, cada codificação de caracteres é optimizada para uma língua em particular. Com isto, eu quero dizer que cada codificação usa os mesmos números (0–255) para representar os caracteres dessa língua. Por exemplo, provavelmente já deve estar familiarizado com a codificação ASCII, que armazena caracteres ingleses como números que variam de 0 a 127. (65 é um “A” maiúsculo, 97 é um “a” minúsculo, etc.) O Inglês tem um alfabeto muito simples, por isso pode ser completamente expresso em menos de 128 números. Para os que conseguem contar em base 2, isso é 7 em 8 bits num byte.
As línguas da Europa Ocidental como o Francês, o Espanhol, e o Alemão têm mais letras que o Inglês. Ou, mais precisamente, eles têm letras combinadas com vários sinais diacríticos, como o caracter ñ
em Espanhol. A codificação mais comum para estas línguas é CP-1252, também chamada “windows-1252” porque foi amplamente usada em Microsoft Windows. A codificação CP-1252 partilha caracteres com ASCII no intervalo 0–127, mas depois prolonga-se no intervalo 128–255 para caracteres como o n-com-um-til-por-cima (241), o u-com-um-trema-por-cima (252), etc. Mas continua a ser uma codificação de um só byte; o maior número possível, 255, continua a caber num byte.
Depois há línguas como o Chinês, o Japonês, e o Coreano, que têm tantos caracteres que requerem conjuntos de caracteres de múltiplos bytes. Isto é, cada “caracter” é representado por um número de dois bytes de 0–65535. Mas diferentes codificações de múltiplos bytes também partilham o mesmo problema que diferentes codificações de um só byte, nomeadamente todas usam os mesmos números com significados diferentes. Simplesmente o intervalo de números é mais amplo, porque há muitos mais caracteres a representar.
Isto era bastante aceitável num mundo não interligado, onde “texto” era qualquer coisa que nós escreviamos e ocasionalmente imprimiamos. Não havia muito “texto simples”. Código fonte era ASCII, e todas as outras pessoas usavam processadores de texto, que definiam os seus próprios formatos (não textuais) que geriam a informação da codificação de caracteres juntamente com a formatação rica, etc. As pessoas lêem estes documentos com o mesmo programa de processamento de texto que o autor original, portanto tudo funcionava, mais coisa ou menos coisa.
Agora pensemos no aumento das redes globais como o email e a web. Montes de “texto simples” a voar pelo mundo, sendo criados num computador, transmitidos por um segundo computador, e recebidos e apresentados por um terceiro computador. Os computadores só conseguem ver números, mas os números podem significar coisas diferentes. Oh não! O que fazemos? Bem, sistemas tiveram que ser desenhados para transportar a informação da codificação juntamente com cada pedaço de “texto simples.” Recorda-se que é a chave de desencriptação que mapeia os números lidos pelo computador para os caracteres lidos pelos humanos. Uma chave de desencriptação em falta significa texto misturado, lixo, ou pior.
Agora pensemos em tentar armazenar vários bocados de texto no mesmo sítio, por exemplo na mesma tabela de uma base de dados que contém todos os emails que alguma vez recebeu. Ainda precisa de armazenar a codificação de caracteres ao lado de cada bocado de texto para o poder apresentar correctamente. Parece difícil? Experimente pesquisar a base de dados do seu email, o que significa conversões entre várias codificações na hora. Não parece divertido?
Agora pensemos na possibilidade de documentos com várias línguas, onde os caracteres de diferentes línguas estão seguidos uns dos outros no mesmo documento. (Sugestão: programas que tentavam fazer isto tipicamente usavam códigos de escape para trocar “modos.” Puff, estamos no modo koi8-r Russo, logo 241 corresponde a Я; puff, agora estamos no modo Mac Greek, logo 241 corresponde a ώ.) E claro vamos querer pesquisar nesses documentos, também.
Agora chore bastante, porque tudo o que pensava saber sobre strings está errado, e “texto simples” não existe.
⁂
Inserir Unicode.
Unicode é um sistema desenhado para representar todos os caracteres de todas as línguas. Unicode representa cada letra, caracter, ou ideograma como um número de 4 bytes. Cada número representa um caracter único usado em pelo menos uma das línguas do mundo. (Nem todos os números são usados, mas mais de 65535 são, portanto 2 bytes não seria suficiente.) Os caracteres que são usados em várias línguas geralmente têm o mesmo número, a não ser que haja uma boa razão etimológica para isto não acontecer. Independentemente disso, há exactamente 1 número por caracter, e exactamente 1 caracter por número. Cada número significa sempre apenas uma coisa; não há “modos” para ir acompanhando. U+0041
é sempre 'A'
, mesmo que a nossa língua não tenha um 'A'
.
À primeira vista, isto parece uma boa ideia. Uma codificação para dominar tudo. Várias línguas por documento. Sem “trocas de modos” para alternar entre codificações a meio do texto. Mas imediatamente, a questão óbvia deveria saltar à vita. Quatro bytes? Por cada caracter‽ Isso parece um desperdício terrível, especialmente em línguas como o Inglês e o Espanhol, que precisam de menos de um byte (256 números) para representar cada caracter possível. Na verdade, é um desperdício mesmo em línguas baseadas em ideogramas (como o Chinês), que nunca precisam de mais de dois bytes por caracter.
Há uma codificação Unicode que usa quatro bytes por caracter. É chamada de UTF-32, porque 32 bits = 4 bytes. UTF-32 é uma codificação directa; pega em cada caracter Unicode (um número de 4 bytes) e representa o caracter com esse mesmo número. Isto tem algumas vantagens, sendo a mais importante poder-se encontrar o N-ésimo caracter de uma string em tempo constante, porque o N-ésimo caracter começa no 4×N-ésimo byte. Isto também tem várias desvantagens, sendo a mais óbvia que leva quatro malditos bytes para guardar cada maldito caracter.
Apesar de haverem muitos caracteres Unicode, parece que maioria das pessoas nunca vai usar o que quer que seja para além dos primeiros 65535. Logo, há outra codificação Unicode, chamada UTF-16 (porque 16 bits = 2 bytes). UTF-16 codifica cada caracter de 0–65535 como dois bytes, depois usa alguns “hacks” manhosos se realmente for preciso representar os raramente usados caracteres Unicode do “plano astral” para além de 65535. Vantagem mais óbvia: UTF-16 é duas vezes mais eficiente em espaço que UTF-32, porque cada caracter requer apenas dois bytes para guardar em vez de quatro bytes (excepto os que não requerem). E continua a ser fácil encontrar o N-ésimo caracter de uma string em tempo constante, se se assumir que a string não inclui caracteres do plano astral, o que é uma boa assunção até ao momento em que deixa de ser.
Mas também há desvantagens pouco óbvias para ambos o UTF-32 e o UTF-16. Diferentes sistemas de computadores armazenam bytes individuais de diferentes maneiras. Isso significa que o caracter U+4E2D
pode ser armazenado em UTF-16 como 4E 2D
ou 2D 4E
, dependendo se o sistema é “big-endian” ou “little-endian”. (Para UTF-32, há ainda mais ordenações de bytes possíveis.) Desde que os nossos documentos nunca deixem o nosso computador, estamos safos — aplicações diferentes no mesmo computador vão todas usar a mesma ordem de bytes. Mas no minuto em que quisermos transferir documentos entre sistemas, talvez em algum tipo de rede a nível mundial, nós vamos precisar de uma forma de indicar qual a ordem pela qual os bytes estão guardados. Caso contrário, o receptor não tem como saber se a sequência de dois bytes 4E 2D
significa U+4E2D
ou U+2D4E
.
Para resolver este problema, as codificações Unicode de vários bytes definem uma “Byte Order Mark,” (Marca de Ordem de Byte) que é um caracter especial não-imprimível que podemos incluir no início do nosso documento para indicar qual a ordem a que os nossos bytes estão. Para UTF-16, a Byte Order Mark é U+FEFF
. Se recebermos um documento UTF-16 que começa com os bytes FF FE
, sabemos que a ordenação dos bytes é de uma maneira; se começa com FE FF
, sabemos que a ordenação dos bytes é ao contrário.
Ainda assim, UTF-16 não é exactamente ideal, especialmente se estivermos a lidar com muitos caracteres ASCII. Se pensarmos nisso, até uma página web chinesa vai ter muitos caracteres ASCII — todos os elementos e atributos à volta dos caracteres chineses imprimíveis. Ser capaz de se encontrar o N-ésimo caracter em tempo constante é bom, mas ainda existe o problema chato daqueles caracteres do plano astral, o que significa que nós não conseguimos guarantir que cada caracter tem exactamente dois bytes, portanto não conseguimos realmente encontrar o N-ésimo caracter em tempo constante a não ser que mantenhamos um índice separado. E há muito texto ASCII pelo mundo…
Outras pessoas ponderaram estas questões, e arranjaram uma solução:
UTF-8
UTF-8 é um sistema de codificação de tamanho variável para o Unicode. Ou seja, caracteres diferentes têm um número diferente de bytes. Para caracters ASCII (A-Z, etc.) UTF-8 usa apenas um byte por caracter. Na realidade, usa exactamente os mesmos bytes; os primeiros 128 caracteres (0–127) em UTF-8 são indistinguíveis de ASCII. Caracteres “derivados do alfabeto latino” com o ñ e o ö acabam por usar dois bytes. (Os bytes não são simplesmente o valor Unicode como seriam em UTF-16; há uma complicada manipulação de bits envolvida.) Caracteres chineses como 中 acabam por ter três bytes. Os caracteres de “plano astral” raramente usados levam quatro bytes.
Desvantagens: por cada caracter levar um número diferente de bytes, encontrar o N-ésimo caracter é uma operação O(N) — isto é, quanto mais longa a string, mais tempo se leva a encontrar um caracter específico. Além disso, há manipulação de bits envolvida para codificar caracteres em bytes e descodificar bytes em caracteres.
Vantagens: codificação super-eficiente de caracteres ASCII comuns. Não é pior que UTF-16 para caracteres derivados do alfabeto latino. Melhor que UTF-32 para caracteres chineses. Adicionalmente (e vai ter que confiar em mim nisto, porque não lhe vou mostrar a matemática), devido à natureza exacta da manipulação de bits, não há problemas na ordenação de bytes. Um documento codificado em UTF-8 usa exactamente a mesma sequência de bytes em qualquer computador.
⁂
Em Python 3, todas as strings são sequências de caracteres Unicode. Não existem strings de Python codificadas em UTF-8, ou strings de Python codificadas como CP-1252. “Esta string é UTF-8?” é uma pergunta inválida. UTF-8 é uma forma de codificar caracteres como uma sequência de bytes. Se quisermos pergar numa string e torná-la numa sequência de bytes numa codificação de caracteres em particular, o Python 3 pode ajudar-nos com isso. Se quisermos pegar numa sequência de bytes e torná-la numa string, o Python 3 pode ajudar-nos com isso também. Bytes não são caracteres; bytes são bytes. Caracteres são uma abstração. Uma string é uma sequência dessas abstrações.
>>> s = '深入 Python' ① >>> len(s) ② 9 >>> s[0] ③ '深' >>> s + ' 3' ④ '深入 Python 3'
'
) ou aspas ("
).
len()
devolve o comprimento da string, i.e. o número de caracteres. Esta é a mesma função que usamos para encontrar o tamanho de uma lista, tuplo, conjunto, ou dicionário. Uma string é como um tuplo de caracteres.
+
.
⁂
Let’s take another look at 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'
… those are each strings.
Python 3 supports formatting values into strings. Although this can include very complicated expressions, the most basic usage is to insert a value into a string with a single placeholder.
>>> username = 'mark' >>> password = 'PapayaWhip' ① >>> "{0}'s password is {1}".format(username, password) ② "mark's password is PapayaWhip"
{0}
and {1}
are replacement fields, which are replaced by the arguments passed to the format()
method.
The previous example shows the simplest case, where the replacement fields are simply integers. Integer replacement fields are treated as positional indices into the argument list of the format()
method. That means that {0}
is replaced by the first argument (username in this case), {1}
is replaced by the second argument (password), &c. You can have as many positional indices as you have arguments, and you can have as many arguments as you want. But replacement fields are much more powerful than that.
>>> 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
module, you’re just grabbing one of the data structures it defines: the list of “SI” (powers-of-1000) suffixes.
{0}
would refer to the first argument passed to the format()
method, si_suffixes. But si_suffixes is a list. So {0[0]}
refers to the first item of the list which is the first argument passed to the format()
method: 'KB'
. Meanwhile, {0[1]}
refers to the second item of the same list: 'MB'
. Everything outside the curly braces — including 1000
, the equals sign, and the spaces — is untouched. The final result is the string '1000KB = 1MB'
.
What this example shows is that format specifiers can access items and properties of data structures using (almost) Python syntax. This is called compound field names. The following compound field names “just work”:
Just to blow your mind, here’s an example that combines all of the above:
>>> import humansize >>> import sys >>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys) '1MB = 1000KB'
Here’s how it works:
sys
module holds information about the currently running Python instance. Since you just imported it, you can pass the sys
module itself as an argument to the format()
method. So the replacement field {0}
refers to the sys
module.
sys.modules
is a dictionary of all the modules that have been imported in this Python instance. The keys are the module names as strings; the values are the module objects themselves. So the replacement field {0.modules}
refers to the dictionary of imported modules.
sys.modules['humansize']
is the humansize
module which you just imported. The replacement field {0.modules[humansize]}
refers to the humansize
module. Note the slight difference in syntax here. In real Python code, the keys of the sys.modules
dictionary are strings; to refer to them, you need to put quotes around the module name (e.g. 'humansize'
). But within a replacement field, you skip the quotes around the dictionary key name (e.g. humansize
). To quote PEP 3101: Advanced String Formatting, “The rules for parsing an item key are very simple. If it starts with a digit, then it is treated as a number, otherwise it is used as a string.”
sys.modules['humansize'].SUFFIXES
is the dictionary defined at the top of the humansize
module. The replacement field {0.modules[humansize].SUFFIXES}
refers to that dictionary.
sys.modules['humansize'].SUFFIXES[1000]
is a list of SI suffixes: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
. So the replacement field {0.modules[humansize].SUFFIXES[1000]}
refers to that list.
sys.modules['humansize'].SUFFIXES[1000][0]
is the first item of the list of SI suffixes: 'KB'
. Therefore, the complete replacement field {0.modules[humansize].SUFFIXES[1000][0]}
is replaced by the two-character string KB
.
But wait! There’s more! Let’s take another look at that strange line of code from humansize.py
:
if size < multiple:
return '{0:.1f} {1}'.format(size, suffix)
{1}
is replaced with the second argument passed to the format()
method, which is suffix. But what is {0:.1f}
? It’s two things: {0}
, which you recognize, and :.1f
, which you don’t. The second half (including and after the colon) defines the format specifier, which further refines how the replaced variable should be formatted.
☞Format specifiers allow you to munge the replacement text in a variety of useful ways, like the
printf()
function in C. You can add zero- or space-padding, align strings, control decimal precision, and even convert numbers to hexadecimal.
Within a replacement field, a colon (:
) marks the start of the format specifier. The format specifier “.1
” means “round to the nearest tenth” (i.e. display only one digit after the decimal point). The format specifier “f
” means “fixed-point number” (as opposed to exponential notation or some other decimal representation). Thus, given a size of 698.24
and suffix of 'GB'
, the formatted string would be '698.2 GB'
, because 698.24
gets rounded to one decimal place, then the suffix is appended after the number.
>>> '{0:.1f} {1}'.format(698.24, 'GB') '698.2 GB'
For all the gory details on format specifiers, consult the Format Specification Mini-Language in the official Python documentation.
⁂
Besides formatting, strings can do a number of other useful tricks.
>>> 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()
method takes one multiline string and returns a list of strings, one for each line of the original. Note that the carriage returns at the end of each line are not included.
lower()
method converts the entire string to lowercase. (Similarly, the upper()
method converts a string to uppercase.)
count()
method counts the number of occurrences of a substring. Yes, there really are six “f”s in that sentence!
Here’s another common case. Let’s say you have a list of key-value pairs in the form key1=value1&key2=value2
, and you want to split them up and make a dictionary of the form {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()
string method has one required argument, a delimiter. The method splits a string into a list of strings based on the delimiter. Here, the delimiter is an ampersand character, but it could be anything.
split()
method is the number of times you want to split. 1
means “only split once,” so the split()
method will return a two-item list. (In theory, a value could contain an equals sign too. If you just used 'key=value=foo'.split('=')
, you would end up with a three-item list ['key', 'value', 'foo']
.)
dict()
function.
☞The previous example looks a lot like parsing query parameters in a URL, but real-life URL parsing is actually more complicated than this. If you’re dealing with URL query parameters, you’re better off using the
urllib.parse.parse_qs()
function, which handles some non-obvious edge cases.
Once you’ve defined a string, you can get any part of it as a new string. This is called slicing the string. Slicing strings works exactly the same as slicing lists, which makes sense, because strings are just sequences of characters.
>>> 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]
returns the first two items of the string, starting at a_string[0]
, up to but not including a_string[2]
.
a_string[:18]
is the same as a_string[0:18]
, because the starting 0 is implied.
a_string[18:]
is the same as a_string[18:44]
, because this string has 44 characters. There is a pleasing symmetry here. In this 44-character string, a_string[:18]
returns the first 18 characters, and a_string[18:]
returns everything but the first 18 characters. In fact, a_string[:n]
will always return the first n characters, and a_string[n:]
will return the rest, regardless of the length of the string.
⁂
Bytes are bytes; characters are an abstraction. An immutable sequence of Unicode characters is called a string. An immutable sequence of numbers-between-0-and-255 is called a bytes object.
>>> 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
object, use the b''
“byte literal” syntax. Each byte within the byte literal can be an ASCII character or an encoded hexadecimal number from \x00
to \xff
(0–255).
bytes
object is bytes
.
bytes
object with the built-in len()
function.
+
operator to concatenate bytes
objects. The result is a new bytes
object.
bytes
object and a 1-byte bytes
object gives you a 6-byte bytes
object.
bytes
object. The items of a string are strings; the items of a bytes
object are integers. Specifically, integers between 0–255.
bytes
object is immutable; you can not assign individual bytes. If you need to change individual bytes, you can either use string slicing and concatenation operators (which work the same as strings), or you can convert the bytes
object into a bytearray
object.
>>> by = b'abcd\x65' >>> barr = bytearray(by) ① >>> barr bytearray(b'abcde') >>> len(barr) ② 5 >>> barr[0] = 102 ③ >>> barr bytearray(b'fbcde')
bytes
object into a mutable bytearray
object, use the built-in bytearray()
function.
bytes
object, you can do on a bytearray
object too.
bytearray
object, you can assign individual bytes using index notation. The assigned value must be an integer between 0–255.
The one thing you can never do is mix bytes and strings.
>>> 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
And here is the link between strings and bytes: bytes
objects have a decode()
method that takes a character encoding and returns a string, and strings have an encode()
method that takes a character encoding and returns a bytes
object. In the previous example, the decoding was relatively straightforward — converting a sequence of bytes in the ASCII encoding into a string of characters. But the same process works with any encoding that supports the characters of the string — even legacy (non-Unicode) encodings.
>>> 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
object. It has 13 bytes. It is the sequence of bytes you get when you take a_string and encode it in UTF-8.
bytes
object. It has 11 bytes. It is the sequence of bytes you get when you take a_string and encode it in GB18030.
bytes
object. It has 11 bytes. It is an entirely different sequence of bytes that you get when you take a_string and encode it in Big5.
⁂
Python 3 assumes that your source code — i.e. each .py
file — is encoded in UTF-8.
☞In Python 2, the default encoding for
.py
files was ASCII. In Python 3, the default encoding is UTF-8.
If you would like to use a different encoding within your Python code, you can put an encoding declaration on the first line of each file. This declaration defines a .py
file to be windows-1252:
# -*- coding: windows-1252 -*-
Technically, the character encoding override can also be on the second line, if the first line is a UNIX-like hash-bang command.
#!/usr/bin/python3
# -*- coding: windows-1252 -*-
For more information, consult PEP 263: Defining Python Source Code Encodings.
⁂
On Unicode in Python:
On Unicode in general:
On character encoding in other formats:
On strings and string formatting:
string
— Common string operations
© 2001–11 Mark Pilgrim