Curso

O que é o Zen of Python?
O Zen of Python é um conjunto de dezenove aforismos que servem como princípios norteadores do design do Python. Na verdade, era para serem vinte; mas Guido van Rossum, criador do Python, ainda não adicionou o último aforismo como pretendia Tim Peters, autor do Zen of Python. Segundo relatos, Guido disse que o vigésimo aforismo ausente é “uma piada interna bizarra do Tim Peters”.
Apesar do vigésimo aforismo faltante, o Zen of Python foi padronizado como PEP 20 em 2004 devido à sua forte influência no processo de desenvolvimento dos programadores Python. Seguir o Zen of Python não é obrigatório, mas conhecer e ter esses princípios em mente é altamente recomendado. Se esquecer de alguma lição, é fácil refrescar a memória executando import this no interpretador do Python.
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Neste artigo, vamos explorar cada lição em mais detalhes.
#1 Bonito é melhor que feio
Se você é programador, não há dúvida de que é altamente habilidoso. Resolver problemas com código não é tarefa simples, mas, como Pythonista, espera-se mais de você. Código bonito é melhor do que código feio. A ascensão meteórica do Python se deve em parte à sua acessibilidade: é simples, legível e elegante. Como desenvolvedor Python, você tem a responsabilidade de manter o padrão “pythônico” escrevendo código bonito.
O que é código bonito? Bem, é subjetivo — beleza está nos olhos de quem vê e por aí vai. Uma regra prática para se manter no caminho é escrever código limpo e legível, que outros desenvolvedores consigam entender com facilidade. Por exemplo:
"""
Initial code was created by Vishal Sharma
See: https://towardsdatascience.com/the-zen-of-python-a-guide-to-pythons-design-principles-93f3f76d088a
"""
def collatz(num):
if num % 2 == 0:
return num // 2
else:
return 3 * num + 1
number = input("Enter a number: ")
while number != 1:
number = collatz(int(number))
print(number)
"""
Enter a number: 5
16
8
4
2
1
"""
O código acima funciona perfeitamente, mas não é necessariamente bonito. Há um else desnecessário na função collatz que pode ser removido assim:
def collatz(num):
if num % 2 == 0:
return num // 2
return 3 * num + 1
Portanto, quando você tiver duas versões funcionando, opte pela mais simples, legível e fácil de entender.
#2 Explícito é melhor que implícito
Dizer que um aforismo é “autoexplicativo” é um baita equívoco — e mesmo assim muita gente faz isso. A ideia por trás de “explícito é melhor que implícito” é que código verboso é preferível a código indireto. Faça o possível para que a funcionalidade do seu código não fique escondida atrás de construções obscuras. Alguém sem contexto prévio do seu programa ainda deve conseguir entender o que está acontecendo.
#3 Simples é melhor que complexo
Você provavelmente riria se alguém pegasse uma lavadora de alta pressão para lavar a louça do jantar. Além de ser uma solução nada prática, a chance de quebrar os pratos é grande. Do mesmo jeito, aplicar uma solução extremamente complexa a um problema simples de programação é impraticável. Não complique à toa só para parecer esperto — você pode causar mais problemas do que resolver, e isso não é valorizado em Python.
Veja esta função que inverte uma string:
def reverse_string(string):
if len(string) == 1:
return string
else:
return reverse_string(string[1:]) + string[0]
string = "kurtis"
print(reverse_string(string))
"""
sitruk
"""
O código acima resolve o problema, mas é desnecessariamente complexo. Se você domina Python, sabe que dá para inverter uma string com indexação.
string = "kurtis"
# solução com função anônima
reverse_string = lambda x: x[::-1]
# solução com função
def reverse(string):
return string[::-1]
print(reverse_string(string))
print(reverse(string))
"""
sitruk
sitruk
"""
#4 Complexo é melhor que complicado
Lavar pratos com uma lavadora de alta pressão é impraticável: água corrente resolve melhor. Mas e se o problema fosse lavar uma Range Rover 4x4? Os aforismos anteriores lembram que técnicas simples e complexas podem resolver um mesmo problema. Lavar uma 4x4 não é simples e tentar usar as mesmas técnicas da pia pode até funcionar, mas é mais complicado do que usar a lavadora. Assim, favoreça a simplicidade; porém, quando ela for impraticável, opte pelo complexo — conheça os limites da simplicidade.
#5 Plano é melhor que aninhado
Programadores adoram organizar coisas em categorias, subcategorias e sub-subcategorias para separar funcionalidades. Embora pareça organizado, estruturar o código assim pode gerar mais confusão do que ordem.
Não há problema em colocar todo o código em um módulo de camada superior: assim você evita fazer algo como from spam.foo.bar.john.doe import chicken para acessar uma funcionalidade específica. Quanto mais níveis você adiciona, mais complicado o código fica. Sempre que possível, mantenha uma estrutura plana.
#6 Espaçado é melhor que denso
Programadores são vistos como pessoas muito inteligentes, então não há por que reforçar isso com malabarismos rebuscados. Um clichê comum é “como fazer [tarefa complexa] em 1 linha de código”. Às vezes, one-liners fazem sentido, mas evite comprometer a legibilidade só para encaixar tudo em uma única linha.
Veja este trecho como exemplo:
"""
Code source Al Sweigart
See: https://inventwithpython.com/blog/author/al-sweigart.html0
"""
print('\n'.join("%i bytes = %i bits which has %i possible values." % (j, j*8, 256**j-1) for j in (1 << i for i in range(8))))
"""
1 bytes = 8 bits which has 255 possible values.
2 bytes = 16 bits which has 65535 possible values.
4 bytes = 32 bits which has 4294967295 possible values.
8 bytes = 64 bits which has 18446744073709551615 possible values.
16 bytes = 128 bits which has 340282366920938463463374607431768211455 possible values.
32 bytes = 256 bits which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values.
64 bytes = 512 bits which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values.
128 bytes = 1024 bits which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values.
"""
Funciona, mas é um pesadelo de entender: tudo espremido e difícil de ler.
Veja como fica o mesmo código escrito de forma mais espaçada:
# Exemplo mais espaçado
bytes_and_bits = {j: j*8 for j in (1 << i for i in range(8))}
for bytes, bits in bytes_and_bits.items():
print(f"{bytes} bytes = {bits} which has {256**bytes-1} possible values")
"""
1 bytes = 8 which has 255 possible values
2 bytes = 16 which has 65535 possible values
4 bytes = 32 which has 4294967295 possible values
8 bytes = 64 which has 18446744073709551615 possible values
16 bytes = 128 which has 340282366920938463463374607431768211455 possible values
32 bytes = 256 which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values
64 bytes = 512 which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values
128 bytes = 1024 which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values
"""
Assim, o código fica muito mais legível e faz exatamente a mesma coisa que o one-liner.
#7 Legibilidade conta
Se ainda não ficou claro, em Python a legibilidade é fundamental. Seu trabalho é escrever o código uma vez. Já a leitura dele provavelmente acontecerá muitas vezes. Levando isso em conta, não vale a pena tirar vogais de nomes de variáveis e funções: se você pode nomear uma função como create_lst ou create_list, fique com a segunda.
#8 Casos especiais não são especiais a ponto de quebrar as regras
Python [e a programação em geral] está cheio de boas práticas a serem seguidas. É melhor seguir padrões consolidados do que “fazer do seu jeito”, pois isso geralmente leva a código inconsistente e pouco legível.
#9 Embora a praticidade supere a pureza
A lição nove complementa a oito. Sim, é melhor seguir as boas práticas, mas forçar a barra para obedecer regras ao pé da letra também pode resultar em código pouco legível. Toda regra pode ter exceção. Se a sua forma de resolver um problema é mais prática, legível e fácil de entender, vale a pena se desviar do padrão estabelecido.
#10 Erros nunca devem passar silenciosamente
Um erro silencioso ocorre quando o programa retorna um código de erro ou None em vez de levantar uma exceção. É melhor o programa quebrar do que esconder o erro e continuar rodando. No longo prazo, silenciar erros pode gerar bugs bem mais difíceis de caçar.
#11 A menos que sejam silenciados explicitamente
A lição onze complementa a dez. Existem situações em que você pode optar por ignorar certos erros. Nesses casos, a boa prática é silenciar o erro explicitamente no código.
#12 Diante da ambiguidade, resista à tentação de adivinhar
Computadores fazem apenas o que mandamos: se seu código não se comporta como você quer, é porque está fazendo exatamente o que você disse. Tentar corrigir o comportamento testando cegamente várias soluções até uma “colar” é uma má estratégia — você pode mascarar o problema em vez de resolvê-lo. Resista à tentação. Em vez disso, pense na lógica, aplique raciocínio crítico e chegue a uma solução adequada.
#13 Deve haver uma — e de preferência apenas uma — maneira óbvia de fazer
O lema da linguagem Perl é: “Há mais de uma maneira de fazer isso!”. Opções demais levam à sobrecarga de escolha. Algo parecido acontece quando existem várias formas de escrever código para alcançar o mesmo objetivo. Você ganha flexibilidade, mas precisa aprender todos os jeitos possíveis para conseguir ler o código dos outros — esse esforço extra é desnecessário.
#14 Embora essa maneira possa não ser óbvia à primeira vista, a menos que você seja holandês
Este aforismo mostra o bom humor de Tim Peters: Guido van Rossum, criador do Python e Benevolent Dictator For Life (BDFL) da linguagem, é holandês. É uma piada para lembrar que entender e lembrar todas as regras da linguagem é difícil para qualquer um — exceto para o criador.
#15 Agora é melhor do que nunca
Este aforismo nos diz que código preso em loop infinito ou que fica travado é pior do que código que roda e termina.
#16 Embora “nunca” muitas vezes seja melhor do que “agora”
Dando sequência: é melhor esperar o programa terminar a execução do que interrompê-lo no meio e obter resultados incorretos.
#17 Se a implementação é difícil de explicar, é uma má ideia
Não basta você mesmo entender a sua implementação — “eu sei o que quis dizer” não resolve. Programar é um trabalho em equipe e, se você não consegue explicar sua solução para o time, é bem provável que ela esteja complexa demais.
#18 Se a implementação é fácil de explicar, pode ser uma boa ideia
No entanto, ser fácil de explicar não garante que o código seja bom — só indica que é simples de comunicar. Ainda pode haver problemas, mas o fato de ser claro mostra que você está no caminho certo.
#19 Namespaces são uma baita ideia — vamos usar mais deles!
Um namespace é uma abstração usada no Python para organizar os nomes atribuídos a objetos no programa. Dado um namespace e um escopo, o Python consegue determinar a que objeto você está se referindo ao chamar um nome simbólico. Em resumo, este aforismo diz que a forma como o Python organiza os nomes por baixo dos panos é ótima.
Conclusão
Neste artigo, apresentamos nossa interpretação do Zen of Python, diretrizes criadas para incentivar programadores Python a escrever código limpo e legível. Enquanto alguns veem o Zen of Python como o roteiro definitivo para escrever código sem atritos, outros levam menos a sério. Nossa sugestão é: aplique os princípios no seu próprio código e veja, na prática, como eles podem elevar a qualidade do seu trabalho. Se quiser aprender mais sobre como escrever código otimizado, confira o curso da DataCamp Writing Efficient Python Code.