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
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
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
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
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
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
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!
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
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]'
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)
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'
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))
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")())
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
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__
Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04
Parte 2Parte 2
TestesTestes
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
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"))
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
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
!
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
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
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'
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...
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
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)
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
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
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
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
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
Danilo J. S. Bellini – fisl 14 – 2013-07-04Danilo J. S. Bellini – fisl 14 – 2013-07-04
Parte 4Parte 4
FinalizaçãoFinalização
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
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
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
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']

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

  • 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']