(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3

on

  • 658 views

Slides da apresentação realizada no fisl14 no dia 2013-07-04 acerca da escrita de código Python único para funcionamento em ambos o Python 2.x e 3.x, enfatizando as versões 2.6, 2.7, 3.2 e 3.3 ...

Slides da apresentação realizada no fisl14 no dia 2013-07-04 acerca da escrita de código Python único para funcionamento em ambos o Python 2.x e 3.x, enfatizando as versões 2.6, 2.7, 3.2 e 3.3 principalmente.

Statistics

Views

Total Views
658
Views on SlideShare
657
Embed Views
1

Actions

Likes
1
Downloads
7
Comments
0

1 Embed 1

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3 Presentation Transcript

  • 1. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Compatibilidade entreCompatibilidade entre Python 2 e 3Python 2 e 3 Como portar seu código em Python 2.x para o Python 3.x sem torná-lo incompatível com o Python 2.x? Com base na história do pacote AudioLazy
  • 2. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Por quê?Por quê? ● Versões futuras do Python ● Ampliar o público-alvo de seu projeto – AudioLazy ● https://pypi.python.org/pypi/audiolazy/ ● Pressão social e tecnofílicos! – Software para uso científico ● NumPy ● MatPlotLib ● SciPy – Notícias recentes ● Flask! TODOS já são compatíveis com o Python 3.x! E outros 2300+ pacotes no PyPI... Python 2.x is the status quo, Python 3.x is the present and future of the language. www.python.org
  • 3. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Alguns númerosAlguns números Valores coletados dia 2013-07-02 Compatibilidade entre Python 2.5 e outras versões Compatibilidade entre Python 3 e outras versões 1459 2392
  • 4. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Por onde começarPor onde começar ● Suíte de testes ● Conhecimento sobre as diferenças entre versões – Ler, estudar – Fuçar, brincar, remoer, torturar a linguagem ● Outras ferramentas e pacotes – Já solucionaram o mesmo problema? Como? – Pacotes de auxílio à compatibilização – Dependências funcionam em quais versões do Python? ● Diminuir restrições
  • 5. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Parte 1Parte 1 Tipos de diferençasTipos de diferenças
  • 6. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Nomes e localizaçõesNomes e localizações import Tkinter master = Tkinter.Tk() master.mainloop() import Tkinter master = Tkinter.Tk() master.mainloop() import tkinter master = tkinter.Tk() master.mainloop() import tkinter master = tkinter.Tk() master.mainloop() Apenas Python 2 Apenas Python 3 Traceback (most recent call last): [...] ImportError: No module named Tkinter Traceback (most recent call last): [...] ImportError: No module named Tkinter Rodando no Python 3 Rodando no Python 2 Traceback (most recent call last): [...] ImportError: No module named tkinter Traceback (most recent call last): [...] ImportError: No module named tkinter
  • 7. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Nomes e localizaçõesNomes e localizações com try...exceptcom try...except try: import tkinter except ImportError: import Tkinter as tkinter master = tkinter.Tk() master.mainloop() try: import tkinter except ImportError: import Tkinter as tkinter master = tkinter.Tk() master.mainloop() ● Nome único – “as” no import – Atribuição ● Há critérios para uso do nome? – PEP8 – Nome no Python 3 ● Versões futuras – Nome no Python 2 ● Atual hábito ● Ausente no Python 3 Quais nomes foram “trocados”? Documentação para desenvolvedores!
  • 8. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Nomes e localizaçõesNomes e localizações com verificação préviacom verificação prévia ● sys.version_info ● sys.modules import sys PYTHON2 = sys.version_info.major == 2 if PYTHON2: builtins = sys.modules["__builtin__"] else: import builtins import sys PYTHON2 = sys.version_info.major == 2 if PYTHON2: builtins = sys.modules["__builtin__"] else: import builtins
  • 9. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Módulo sysMódulo sys In [1]: import sys In [2]: sys.version_info Out[2]: sys.version_info(major=3, minor=2, micro=4, releaselevel='final', serial=0) In [3]: sys.version_info >= (3, 2) Out[3]: True In [4]: sys.version_info >= (3, 3) Out[4]: False In [5]: sys.version Out[5]: '3.2.4 (default, May 8 2013, 20:55:18) n[GCC 4.7.3]' In [1]: import sys In [2]: sys.version_info Out[2]: sys.version_info(major=3, minor=2, micro=4, releaselevel='final', serial=0) In [3]: sys.version_info >= (3, 2) Out[3]: True In [4]: sys.version_info >= (3, 3) Out[4]: False In [5]: sys.version Out[5]: '3.2.4 (default, May 8 2013, 20:55:18) n[GCC 4.7.3]'
  • 10. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Nomes e localizaçõesNomes e localizações com getattrcom getattr ● Funções são objetos ● Análogo ao método “get” de dicionários import itertools xzip = getattr(itertools, "izip", zip) xmap = getattr(itertools, "imap", map) xfilter = getattr(itertools, "ifilter", filter) # Usando o builtins visto anteriormente xrange = getattr(builtins, "xrange", range) import itertools xzip = getattr(itertools, "izip", zip) xmap = getattr(itertools, "imap", map) xfilter = getattr(itertools, "ifilter", filter) # Usando o builtins visto anteriormente xrange = getattr(builtins, "xrange", range)
  • 11. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Monkeypatch / MockMonkeypatch / Mock ● Usando getattr ou atribuições (no try...except) ● Compatibilizar código de terceiros sem mudá-los ● Nem sempre é possível (tipos básicos) – e.g. Método to_bytes do int (apenas Python 3) import operator operator.div = getattr(operator, "div", operator.truediv) import operator operator.div = getattr(operator, "div", operator.truediv) In [1]: (317215).to_bytes(5, "big") Out[1]: b'x00x00x04xd7x1f' In [1]: (317215).to_bytes(5, "big") Out[1]: b'x00x00x04xd7x1f'
  • 12. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Funções e outros objetosFunções e outros objetos ausentesausentes ● Reconstruir ● Criar pela primeira vez – e.g. itertools.accumulate ● audiolazy.accumulate from functools import wraps @wraps(range) def orange(*args, **kwargs): return list(range(*args, **kwargs)) from functools import wraps @wraps(range) def orange(*args, **kwargs): return list(range(*args, **kwargs))
  • 13. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Métodos ausentesMétodos ausentes ● Iteração sobre dicionários ● Iterável VS Iterador – Gotcha! def iteritems(dictionary): try: return getattr(dictionary, "iteritems")() except AttributeError: return iter(getattr(dictionary, "items")()) def iteritems(dictionary): try: return getattr(dictionary, "iteritems")() except AttributeError: return iter(getattr(dictionary, "items")())
  • 14. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 GeneralizaçõesGeneralizações ● String? – str no Python 3 – (unicode, str) no Python 2 ● builtins.basestring ● Inteiro? – int no Python 3 – (long, int) no Python 2 INT_TYPES = (int, getattr(builtins, "long", None)) if PYTHON2 else (int,) print(isinstance(something_here, INT_TYPES)) INT_TYPES = (int, getattr(builtins, "long", None)) if PYTHON2 else (int,) print(isinstance(something_here, INT_TYPES)) Utilização comisinstance
  • 15. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 InternalidadesInternalidades ● Iteradores (e geradores) – Método next no Python 2 – Método __next__ no Python 3 ● Avaliação “if obj:” segue um método de obj – __nonzero__ no Python 2 – __bool__ no Python 3 ● Função do método (“unbound”) – Python 2 ● classe.metodo.im_func ● objeto.metodo.im_func – Python 3 ● classe.metodo ● objeto.metodo.__func__
  • 16. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Parte 2Parte 2 TestesTestes
  • 17. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 TestesTestes ● Automatizados – py.test – nose – unittest – doctest ● Apenas para documentação ● Cobertura de código – Confiabilidade – Dependências ● skip ● xfail ● Acompanhar dependência Testes passando Testes falhando
  • 18. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Skip automático comSkip automático com py.testpy.test import pytest def skipper(msg="There's something not supported " "in this environment"): def skip(*args, **kwargs): pytest.skip(msg.format(*args, **kwargs)) return skip operator.div = getattr(operator, "div", skipper("There's no " "operator.div")) import pytest def skipper(msg="There's something not supported " "in this environment"): def skip(*args, **kwargs): pytest.skip(msg.format(*args, **kwargs)) return skip operator.div = getattr(operator, "div", skipper("There's no " "operator.div"))
  • 19. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 toxtox [tox] envlist = py26,py27 [testenv] deps=pytest commands=py.test [tox] envlist = py26,py27 [testenv] deps=pytest commands=py.test ● “Standardize testing in Python” ● tox.ini
  • 20. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Parte 3Parte 3 Diferenças importantesDiferenças importantes !
  • 21. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 MetaclassesMetaclasses ● Classe cujas instâncias são classes ● Sintaxe diferenciada no Python 2 e 3 # Python 3 bases = (object,) MyMeta = type class A(*bases, metaclass=MyMeta): pass # Python 2 class A(*bases): __metaclass__ = MyMeta # Python 3 bases = (object,) MyMeta = type class A(*bases, metaclass=MyMeta): pass # Python 2 class A(*bases): __metaclass__ = MyMeta
  • 22. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 MetaclassesMetaclasses ● Solução padrão: – Criar uma classe vazia usando a metaclasse, e colocá- la junto às bases ● Problemas: – Construtor da classe pode falhar ● Solução alternativa – Metaclasse falsa ● Única base da nova classe – Construtor da metaclasse com 2 comportamentos ● Antes da obtenção do dicionário da classe ● Depois (real instanciação) – Função audiolazy.meta
  • 23. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04>>> class BadMeta(type): ... def __new__(mcls, name, bases, namespace): ... if "bad" not in namespace: ... raise Exception("Oops, not bad enough") ... value = len(name) ... def really_bad(self): ... return self.bad() * value ... namespace["really_bad"] = really_bad ... return super(BadMeta, mcls).__new__(mcls, name, bases, ... namespace) ... >>> class Bady(meta(object, metaclass=BadMeta)): ... def bad(self): ... return "HUA " ... >>> class BadGuy(Bady): ... def bad(self): ... return "R" ... >>> issubclass(BadGuy, Bady) True >>> Bady().really_bad() # value = 4 'HUA HUA HUA HUA ' >>> BadGuy().really_bad() # value = 6 'RRRRRR' >>> class BadMeta(type): ... def __new__(mcls, name, bases, namespace): ... if "bad" not in namespace: ... raise Exception("Oops, not bad enough") ... value = len(name) ... def really_bad(self): ... return self.bad() * value ... namespace["really_bad"] = really_bad ... return super(BadMeta, mcls).__new__(mcls, name, bases, ... namespace) ... >>> class Bady(meta(object, metaclass=BadMeta)): ... def bad(self): ... return "HUA " ... >>> class BadGuy(Bady): ... def bad(self): ... return "R" ... >>> issubclass(BadGuy, Bady) True >>> Bady().really_bad() # value = 4 'HUA HUA HUA HUA ' >>> BadGuy().really_bad() # value = 6 'RRRRRR'
  • 24. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 PrintPrint ● Python 2 – Statement / comando – print >>f, “string” – print “a”, “b” – print “string”, ● Python 3 – Função – print(“string”, file = f) – print(“a”, “b”, sep=“ ”) – print(“string”, end=“ ”) ● Solução (parcial) imediata – from __future__ import print_function Almost there...
  • 25. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Unicode!!!Unicode!!! ● Nomes de variável em unicode ● *.py em UTF-8 (Python 3) – No Python 2, em uma das 2 primeiras linhas: # coding: utf-8 ● Pensar no unicode (str do Python 3) como um objeto. – Encode: codifica o unicode para uma string de bytes – Decode: dos bytes, obtém o unicode ● The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) http://www.joelonsoftware.com/articles/Unicode.html
  • 26. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Unicode!!!Unicode!!! ● u“texto” (Python 3.3 e 2.x) ● from __future__ import unicode_literals – Funciona no Python 3.2 ● Conversão manual (testar tipo) ● Provavelmente o aspecto mais difícil durante a compatibilização – os.urandom no simplekv (flask-kvsession)
  • 27. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Itertools e functoolsItertools e functools ● reduce – from functools import reduce ● zip, map, filter (e zip_longest) – Python 2: Listas – Python 3: Comportamento tardio (lazy), similar ao izip, imap, ifilter do itertools do Python 2 ● Itertools – Não possui mais izip, imap, ifilter, izip_longest – Novo accumulate
  • 28. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 DivisãoDivisão ● 1 / 2 – 0 no Python 2 (int) – 0.5 no Python 3 (float) ● 1 // 2 – 0 no Python 2 (int) – 0 no Python 3 (int) ● Solução imediata – from __future__ import division
  • 29. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Parte 4Parte 4 Diferenças inusitadasDiferenças inusitadas
  • 30. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Arredondamento de pontoArredondamento de ponto flutuanteflutuante In [1]: round(.5) Out[1]: 1.0 In [2]: round(-.5) Out[2]: -1.0 In [1]: round(.5) Out[1]: 1.0 In [2]: round(-.5) Out[2]: -1.0 ● Python 2 ● Python 3 ● Solução? Depende do comportamento desejado – audiolazy.rint In [1]: round(.5) Out[1]: 0 In [2]: round(-.5) Out[2]: 0 In [1]: round(.5) Out[1]: 0 In [2]: round(-.5) Out[2]: 0
  • 31. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Namespace da classeNamespace da classe ● Python 2 – Funciona ok ● Python 3 – NameError: global name 'data' is not defined class A(object): data = [1, 2, 3] data_powers = [[x ** n for x in data] for n in range(3)] class A(object): data = [1, 2, 3] data_powers = [[x ** n for x in data] for n in range(3)] ● Compatibilizar – data_powers = (lambda data: […])(data) – Deixar fora da classe – Colocar no __init__ ou no __new__ da metaclasse
  • 32. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Parte 4Parte 4 FinalizaçãoFinalização
  • 33. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Python 2.6 e 2.7Python 2.6 e 2.7 ● Apenas no Python 2.7 – Dict comprehension ● dict((k, v) for k, v in my_iterable) – Set comprehension ● set(el for el in my_iterable) – collections.OrderedDict ● pip install ordereddict ● Outros features do Python 3.1 (backported) http://docs.python.org/dev/whatsnew/2.7.html Comprehension com {}: apenas Python 2.7, 3.1 e mais recentes
  • 34. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 sixsix ● Pacote de compatibilização – Funções para iterar em dicionários – Constantes com tipos para uso com isinstance – callable (Ausente no Python 3 até o 3.1) – Preocupação com Python 2.4 e 2.5 ● Avaliação tardia – Não importa nada à toa – Engana análise para auto-complete ● Metaclasse (mantém um nível hierárquico adicional) – class A(with_metaclass(Meta, Base)) # Apenas uma base – Neste caso, a audiolazy.meta é mais geral Utilizado peloMatPlotLib
  • 35. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Alternativas à compatibilizaçãoAlternativas à compatibilização ● Conversão automática – Distribute com 2to3 ou 3to2 ● Conversão manual – Branches para cada versão ● Incompatibilidade – Código restrito a versões específicas
  • 36. Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04 Obrigado!Obrigado! Perguntas? >>> from audiolazy import lazy_compat as compat >>> dir(compat) ['INT_TYPES', 'NEXT_NAME', 'PYTHON2', 'SOME_GEN_TYPES', 'STR_TYPES', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__name__', '__package__', 'builtins', 'im_func', 'it', 'iteritems', 'itervalues', 'meta', 'orange', 'sys', 'types', 'xfilter', 'xmap', 'xrange', 'xzip', 'xzip_longest'] >>> from audiolazy import lazy_compat as compat >>> dir(compat) ['INT_TYPES', 'NEXT_NAME', 'PYTHON2', 'SOME_GEN_TYPES', 'STR_TYPES', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__name__', '__package__', 'builtins', 'im_func', 'it', 'iteritems', 'itervalues', 'meta', 'orange', 'sys', 'types', 'xfilter', 'xmap', 'xrange', 'xzip', 'xzip_longest']