$30 off During Our Annual Pro Sale. View Details »

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. Coisas que aprendi portando
    código para Python 3
    Elias Dorneles
    @eliasdorneles

    View Slide

  2. Não há motivo pra
    ter vergonha por
    estar usando
    exclusivamente
    Python 2!

    View Slide

  3. A despeito do
    que a Internet
    esteja dizendo
    no momento :)

    View Slide

  4. 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

    View Slide

  5. Estratégias de migração

    View Slide

  6. 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

    View Slide

  7. Vamos focar em Python 2 & 3
    com o mesmo código

    View Slide

  8. 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

    View Slide

  9. Foque em
    Python 2.7 e 3.3+

    View Slide

  10. 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)

    View Slide

  11. 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

    View Slide

  12. 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)

    View Slide

  13. Sintaxe é fácil de
    arrumar!
    O desafio mesmo é
    unicode vs bytes.

    View Slide

  14. 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!)

    View Slide

  15. View Slide

  16. Mojibake:

    View Slide

  17. Erros de codificação em Python 2
    >>> s = 'coração'
    >>> s
    'cora\xc3\xa7\xc3\xa3o'
    >>> type(s)

    >>> unicode(s)
    Traceback (most recent call last):
    File "", line 1, in
    UnicodeDecodeError: 'ascii' codec can't decode byte
    0xc3 in position 4: ordinal not in range(128)

    View Slide

  18. Erros de codificação em Python 2
    >>> s = 'coração'
    >>> s.decode('utf-8')
    u'cora\xe7\xe3o'
    >>> type(s.decode('utf-8'))

    >>> s.decode('utf-8').encode('utf-8')
    'cora\xc3\xa7\xc3\xa3o'
    >>> type(s.decode('utf-8').encode('utf-8'))

    View Slide

  19. 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 "", line 1, in
    UnicodeDecodeError: 'ascii' codec can't decode byte
    0xc3 in position 4: ordinal not in range(128)

    View Slide

  20. Erros de codificação em Python 3
    >>> s = 'coração'
    >>> s
    'coração'
    >>> type(s)

    >>> s.encode('utf-8')
    b'cora\xc3\xa7\xc3\xa3o'
    >>> type(s.encode('utf-8'))

    View Slide

  21. 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 "", line 1, in
    UnicodeDecodeError: 'utf-8' codec can't decode byte
    0xe7 in position 4: invalid continuation byte

    View Slide

  22. 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.

    View Slide

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

    View Slide

  24. Comparações de tipos diferentes falham em PY3
    >>> '' == b''
    True
    >>> '' == b''
    False
    Python 2
    Python 3

    View Slide

  25. foo == 'bar'
    Cuidado com testes
    com asserções:
    Pode passar em Python 3 mas ainda estar incorreto!

    View Slide

  26. foo == b'bar'
    Talvez o teste devesse
    ter sido escrito com:

    View Slide

  27. 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
    )

    View Slide

  28. 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

    View Slide

  29. 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

    View Slide

  30. Now, go forth
    and port!

    View Slide

  31. Obrigado.
    Perguntas?
    Elias Dorneles
    @eliasdorneles

    View Slide