Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Coisas que aprendi portando código para Python 3

Coisas que aprendi portando código para Python 3

Palestra a apresentar no encontro da comunidade PythonRio: http://pythonrio.python.org.br
Atualizada em 15 Set 2016, para apresentação na Python Floripa

Elias Dorneles

June 25, 2016
Tweet

More Decks by Elias Dorneles

Other Decks in Programming

Transcript

  1. Por que Python 3? • É uma linguagem melhor ◦

    tuple unpacking ◦ APIs mais consistentes ◦ async/await ◦ sintaxe para tipagem gradual ◦ mais fácil para iniciantes • É o futuro do ecossistema ◦ seus usuários querem PY3
  2. Estratégias de migração 1. Migrar de vez para Python 3

    ◦ para código com baixo risco 2. Fork para versão Python 3 ◦ para código estável, que receba poucas modificações 3. Python 2 & 3 com mesma base de código ◦ para código mantido e sendo usado por outros
  3. Importante ter uma boa cobertura de testes • Não precisa

    ser 100%, mas é bom ter o suficiente para pegar regressões importantes • Rode os testes em Python 2 & Python 3 ◦ comece ignorando os que ainda não passam em Python 3, vá consertando aos poucos • Lembre que os testes podem estar incorretos em Python 3 e precisarem mudar também
  4. Foque em 2.7 e 3.3+ • Caso ainda esteja em

    2.6 ou anterior, migre primeiro para 2.7+ • Ignore 3.x menores que 3.3 ◦ não tinham suporte apropriado (sintático & stdlib) para fazer código compatível com 2 ◦ vendors (distros) em geral suportam 3.3+ • Dica para instalar várias versões de Python: ◦ http://saghul.github.io/pythonz (CPython, PyPy, etc)
  5. Use six! https://pypi.python.org/pypi/six • Melhor biblioteca para Python 2 &

    3 no mesmo código* • Tudo em um arquivo, fácil de copiar e colar dentro do projeto se necessário • Funções utils, constantes, shims, aliases • Vocabulário para portar • Learn it, love it! <3
  6. Retrocompatibilidade deixa tudo mais difícil • Em alguns casos, pode

    ser necessário quebrar ◦ unicode vs bytes força corrigir alguns problemas ◦ quando for bug mesmo, é aceitável quebrar • Prepare-se para fazer alguns ciclos de depreciação ◦ marcar código como obsoleto, emitindo warnings ◦ dica: DeprecationWarning é ignorada por default, crie uma nova class MyDeprecationWarning(Warning)
  7. Vamos falar de codificação de caracteres! “O Mínimo Absoluto Que

    Todo Desenvolvedor De Software Absolutamente, Positivamente Precisa Saber Sobre Unicode E Conjuntos de Caracteres (Sem Desculpas!)” by Joel Spolsky Em inglês: http://www.joelonsoftware.com/articles/Unicode.html Tradução: http://local.joelonsoftware.com/wiki/O_M%C3%ADnimo_Absoluto_Que_Todo_Desenvolvedor_De_Soft ware_Absolutamente,_Positivamente_Precisa_Saber_Sobre_Unicode_E_Conjuntos_de_Caracteres_(S em_Desculpas!)
  8. Erros de codificação em Python 2 >>> s = 'coração'

    >>> s 'cora\xc3\xa7\xc3\xa3o' >>> type(s) <type 'str'> >>> unicode(s) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
  9. Erros de codificação em Python 2 >>> s = 'coração'

    >>> s.decode('utf-8') u'cora\xe7\xe3o' >>> type(s.decode('utf-8')) <type 'unicode'> >>> s.decode('utf-8').encode('utf-8') 'cora\xc3\xa7\xc3\xa3o' >>> type(s.decode('utf-8').encode('utf-8')) <type 'str'>
  10. Mojibake em Python 2 >>> s = 'coração' >>> s.decode('latin1')

    u'cora\xc3\xa7\xc3\xa3o' >>> print s.decode('latin1') coração >>> s.encode('latin1') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
  11. Erros de codificação em Python 3 >>> s = 'coração'

    >>> s 'coração' >>> type(s) <class 'str'> >>> s.encode('utf-8') b'cora\xc3\xa7\xc3\xa3o' >>> type(s.encode('utf-8')) <class 'bytes'>
  12. Mojibake em Python 3 >>> s = 'coração' >>> s.encode('utf-8').decode('latin1')

    # Mojibake! 'coração' >>> s.encode('latin1') b'cora\xe7\xe3o' >>> s.encode('latin1').decode('utf-8') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe7 in position 4: invalid continuation byte
  13. Unicode vs bytes: o desafio Para cada “string”, você precisa

    decidir se: • deve ser só texto? (unicode em PY2, str em PY3) • deve ser só binário? (str/bytes em PY2, bytes em PY3) • deve ser string nativa? (str em PY2 & PY3) Fica mais simples quando se escolhe ou texto ou binário. É importante boa cobertura, e checar corretude dos testes também.
  14. Comparações de tipos diferentes falham em PY3 >>> max(1, 2,

    '3') '3' >>> max(1, 2, '3') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: str() > int() Python 2 Python 3
  15. Comparações de tipos diferentes falham em PY3 >>> '' ==

    b'' True >>> '' == b'' False Python 2 Python 3
  16. foo == 'bar' Cuidado com testes com asserções: Pode passar

    em Python 3 mas ainda estar incorreto!
  17. Use os imports do __future__ • Exceção: evite unicode_literals ◦

    funções da stdlib em PY2 esperando bytes acabam recebendo um objeto unicode ◦ mais interessante quando portando de PY3 -> PY2 from __future__ import ( print_function, absolute_import, division )
  18. Para projetos grandes, comece pelas beiradas • Comece a portar

    as partes com menos dependências • Exemplo: ◦ escolha um módulo em utils ◦ revise o código e os testes ◦ corrija os testes, adicione mais alguns ◦ porte • É uma boa documentar decisões sobre bytes vs unicode ◦ Scrapy: começou com utils, depois Request/Response
  19. Recursos na Web (em inglês) • Livro gratuito: http://python3porting.com •

    Guia opinionado: https://docs.python.org/dev/howto/pyporting.html • Razões para usar Python 3: http://asmeurer.github.io/python3-presentation/slides.html • Sobre unicode_literals: http://python-future.org/imports.html#should-i-import-unico de-literals