(2013-07-05) [fisl] compatibilidade entre python 2 e 3

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

If you can't read please download the document

Upload: danilo-bellini

Post on 28-Jun-2015

444 views

Category:

Technology


0 download

DESCRIPTION

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.

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 cdigo em Python 2.x para o Python 3.x sem torn-lo incompatvel com o Python 2.x? Com base na histria 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? Verses futuras do Python Ampliar o pblico-alvo de seu projeto AudioLazy https://pypi.python.org/pypi/audiolazy/ Presso social e tecnoflicos! Software para uso cientfico NumPy MatPlotLib SciPy Notcias recentes Flask! TODOS j so compatveis 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 nmerosAlguns nmeros Valores coletados dia 2013-07-02 Compatibilidade entre Python 2.5 e outras verses Compatibilidade entre Python 3 e outras verses 1459 2392 4. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 Por onde comearPor onde comear Sute de testes Conhecimento sobre as diferenas entre verses Ler, estudar Fuar, brincar, remoer, torturar a linguagem Outras ferramentas e pacotes J solucionaram o mesmo problema? Como? Pacotes de auxlio compatibilizao Dependncias funcionam em quais verses do Python? Diminuir restries 5. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 Parte 1Parte 1 Tipos de diferenasTipos de diferenas 6. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 Nomes e localizaesNomes e localizaes 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 localizaesNomes e localizaes 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 Atribuio H critrios para uso do nome? PEP8 Nome no Python 3 Verses futuras Nome no Python 2 Atual hbito Ausente no Python 3 Quais nomes foram trocados? Documentao para desenvolvedores! 8. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 Nomes e localizaesNomes e localizaes com verificao prviacom verificao prvia 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 Mdulo sysMdulo 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 localizaesNomes e localizaes com getattrcom getattr Funes so objetos Anlogo ao mtodo get de dicionrios 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 atribuies (no try...except) Compatibilizar cdigo de terceiros sem mud-los Nem sempre possvel (tipos bsicos) e.g. Mtodo 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 Funes e outros objetosFunes 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 Mtodos ausentesMtodos ausentes Iterao sobre dicionrios Itervel 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 GeneralizaesGeneralizaes 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)) Utilizao comisinstance 15. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 InternalidadesInternalidades Iteradores (e geradores) Mtodo next no Python 2 Mtodo __next__ no Python 3 Avaliao if obj: segue um mtodo de obj __nonzero__ no Python 2 __bool__ no Python 3 Funo do mtodo (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 documentao Cobertura de cdigo Confiabilidade Dependncias skip xfail Acompanhar dependncia Testes passando Testes falhando 18. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 Skip automtico comSkip automtico 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 Diferenas importantesDiferenas importantes ! 21. Danilo J. S. Bellini fisl 14 2013-07-04Danilo J. S. Bellini fisl 14 2013-07-04 MetaclassesMetaclasses Classe cujas instncias so 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 Soluo padro: Criar uma classe vazia usando a metaclasse, e coloc- la junto s bases Problemas: Construtor da classe pode falhar Soluo alternativa Metaclasse falsa nica base da nova classe Construtor da metaclasse com 2 comportamentos Antes da obteno do dicionrio da classe Depois (real instanciao) Funo 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 Funo print(string, file = f) print(a, b, sep= ) print(string, end= ) Soluo (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 varivel 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, obtm 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!!! utexto (Python 3.3 e 2.x) from __future__ import unicode_literals Funciona no Python 3.2 Converso manual (testar tipo) Provavelmente o aspecto mais difcil durante a compatibilizao 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 No 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 DivisoDiviso 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) Soluo 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 Diferenas inusitadasDiferenas 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 Soluo? 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 FinalizaoFinalizao 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 compatibilizao Funes para iterar em dicionrios Constantes com tipos para uso com isinstance callable (Ausente no Python 3 at o 3.1) Preocupao com Python 2.4 e 2.5 Avaliao tardia No importa nada toa Engana anlise para auto-complete Metaclasse (mantm um nvel hierrquico 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 compatibilizaoAlternativas compatibilizao Converso automtica Distribute com 2to3 ou 3to2 Converso manual Branches para cada verso Incompatibilidade Cdigo restrito a verses especficas 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']