Muitos utilizadores iniciantes de Python estão a perguntar-se com que versão de Python devem começar. A minha resposta a esta pergunta é normalmente algo do tipo “basta ir com a versão em que o seu tutorial favorito foi escrito, e verificar as diferenças mais tarde”
Mas e se estiver a iniciar um novo projecto e tiver a escolha de escolher? Eu diria que actualmente não há “certo” ou “errado” desde que tanto Python 2.7.x como Python 3.x apoiem as bibliotecas que está a planear utilizar. No entanto, vale a pena analisar as principais diferenças entre essas duas versões mais populares de Python para evitar armadilhas comuns ao escrever o código para qualquer uma delas, ou se está a planear portar o seu projecto.
Seções
- Seções
- O módulo
__future__
módulo - A função de impressão
- Python 2
- Python 3
- Divisão inteira
- Python 2
- Python 3
- Unicode
- Python 2
- Python 3
- Python 2
- Python 3
- O
__contains__
método pararange
objectos em Python 3- Nota sobre as diferenças de velocidade em Python 2 e 3
python 3 xrange
- Python 2
- Python 3
- Python 2
- Python 3
Python 3
- Python 2
- Python 3
- Python 2
- Python 3
- Python 2
- Python 3
- Python 2
- Python 3
- Python 2
- Python 3
O módulo __futuro__
Python 3.x introduziu algumas palavras-chave e características incompatíveis com Python 2 que podem ser importadas através do módulo __future__
em Python 2. Recomenda-se usar __future__
importa se estiver a planear o suporte Python 3.x para o seu código. Por exemplo, se quisermos o Python 3.O comportamento da divisão inteira do x em Python 2, podemos importá-lo através de
from __future__ import division
Mais características que podem ser importadas do módulo __future__
estão listadas na tabela abaixo:
>
nested_scopes | 2.1.0b1 | 2.2 | PEP 227:Escopos de Geração Estaticamente Aninhados |
generadores | 2.2.0a1 | 2.3 | PEP 255:Geradores Simples |
divisão | 2.2.0a2 | 3.0 | PEP 238:Mudança do Operador de Divisão |
absoluta_importação | 2.5.0a1 | 3.0 | PEP 328:Importações: Multi-Linha e Absoluta/Relativa |
with_statement | 2.5.0a1 | 2.6 | PEP 343:A Declaração “com” |
print_function | 2.6.0a2 | 3.0 | PEP 3105:Fazer imprimir uma função |
unicode_literals | 2.6.0a2 | 3.0 | PEP 3112:Bytes literais em Python 3000 |
from platform import python_version
A função de impressão
Muito trivial, e a alteração da sintaxe da impressão é provavelmente a alteração mais conhecida, mas mesmo assim vale a pena mencionar: A declaração de impressão de Python 2 foi substituída pela função print()
, o que significa que temos de embrulhar o objecto que queremos imprimir em paranteses.
Python 2 não tem problemas com paranteses adicionais, mas em contraste, Python 3 levantaria uma SyntaxError
se chamássemos à função de impressão a Python 2-way sem os parênteses.
Python 2
print 'Python', python_version()print 'Hello, World!'print('Hello, World!')print "text", ; print 'print more text on the same line'
>div>>
Python 2.7.6Hello, World!Hello, World!text print more text on the same line
Python 3
print('Python', python_version())print('Hello, World!')print("some text,", end="")print(' print more text on the same line')
Python 3.4.1Hello, World!some text, print more text on the same line
File "<ipython-input-3-139a7c5835bd>", line 1 print 'Hello, World!' ^SyntaxError: invalid syntax
Nota:
p> Impressão “Olá, Mundo” acima via Python 2 parecia bastante “normal”. No entanto, se tivermos vários objectos dentro das paranteses, criaremos um tuple, uma vez que print
é uma “afirmação” em Python 2, não uma chamada de função.
print 'Python', python_version()print('a', 'b')print 'a', 'b'
Python 2.7.7('a', 'b')a b
Integer division
Esta alteração é particularmente perigosa se se estiver a portar código, ou se estiver a executar o código Python 3 em Python 2, uma vez que a mudança no comportamento da divisão inteira pode muitas vezes passar despercebida (não levanta um SyntaxError
).
Assim, ainda tendo a usar um float(3)/2
ou 3/2.0
em vez de um 3/2
nos meus scripts Python 3 para poupar aos tipos Python 2 alguns problemas (e vice-versa, Recomendo um from __future__ import division
nos vossos guiões Python 2).
Python 2
print 'Python', python_version()print '3 / 2 =', 3 / 2print '3 // 2 =', 3 // 2print '3 / 2.0 =', 3 / 2.0print '3 // 2.0 =', 3 // 2.0
Python 2.7.63 / 2 = 13 // 2 = 13 / 2.0 = 1.53 // 2.0 = 1.0
Python 3
print('Python', python_version())print('3 / 2 =', 3 / 2)print('3 // 2 =', 3 // 2)print('3 / 2.0 =', 3 / 2.0)print('3 // 2.0 =', 3 // 2.0)
Python 3.4.13 / 2 = 1.53 // 2 = 13 / 2.0 = 1.53 // 2.0 = 1.0
Unicode
Python 2 tem ASCII str()
tipos, separate unicode()
, mas não byte
type.
Agora, em Python 3, temos finalmente Unicode (utf-8) str
ings, e 2 classes de bytes: byte
e bytearray
s.
Python 2
print 'Python', python_version()
>div>>
Python 2.7.6
>div>>
print type(unicode('this is like a python3 str type'))
<type 'unicode'>
print type(b'byte type does not exist')
/div>
<type 'str'>
print 'they are really' + b' the same'
they are really the same
print type(bytearray(b'bytearray oddly does exist though'))
<type 'bytearray'>
Python 3
print('Python', python_version())print('strings are now utf-8 \u03BCnico\u0394é!')
Python 3.4.1strings are now utf-8 μnicoΔé!
print('Python', python_version(), end="")print(' has', type(b' bytes for storing data'))
Python 3.4.1 has <class 'bytes'>
print('and Python', python_version(), end="")print(' also has', type(bytearray(b'bytearrays')))
and Python 3.4.1 also has <class 'bytearray'>
'note that we cannot add a string' + b'bytes for data'
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-13-d3e8942ccf81> in <module>()----> 1 'note that we cannot add a string' + b'bytes for data'TypeError: Can't convert 'bytes' object to str implicitly
xrange
O uso de xrange()
é muito popular em Python 2.x para a criação de um objecto iterável, por exemplo num for-loop ou list/set-dictionary-comprehension.
O comportamento era bastante semelhante ao de um gerador (ou seja “avaliação preguiçosa”), mas aqui o x-iterável não é esgotável – ou seja, poderia iterar infinitamente sobre ele.
Graças à sua “avaliação preguiçosa”, a vantagem do regular range()
é que xrange()
é geralmente mais rápido se tiver de iterar sobre ele apenas uma vez (por exemplo, num for-loop). No entanto, ao contrário das iterações 1 vez, não é recomendado se repetir a iteração várias vezes, uma vez que a geração acontece sempre a partir do zero!
Em Python 3, o range()
foi implementado como o xrange()
função para que uma função dedicada xrange()
já não exista (xrange()
eleva um NameError
em Python 3).
import timeitn = 10000def test_range(n): return for i in range(n): passdef test_xrange(n): for i in xrange(n): pass
Python 2
print 'Python', python_version()print '\ntiming range()'%timeit test_range(n)print '\n\ntiming xrange()'%timeit test_xrange(n)
Python 2.7.6timing range()1000 loops, best of 3: 433 µs per looptiming xrange()1000 loops, best of 3: 350 µs per loop
Python 3
print('Python', python_version())print('\ntiming range()')%timeit test_range(n)
Python 3.4.1timing range()1000 loops, best of 3: 520 µs per loop
/div>
print(xrange(10))
---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-5-5d8f9b79ea70> in <module>()----> 1 print(xrange(10))NameError: name 'xrange' is not defined
O método __contém__ para objectos de gama em Python 3
Outra coisa que vale a pena mencionar é que range
tem um método “novo” __contains__
em Python 3.x (graças a Yuchen Ying, que assinalou este facto). O método __contains__
pode acelerar “look-ups” em Python 3.x range
significativamente para os tipos inteiro e booleano.
x = 10000000
def val_in_range(x, val): return val in range(x)
def val_in_xrange(x, val): return val in xrange(x)
print('Python', python_version())assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_range(x, x/2)%timeit val_in_range(x, x//2)
Python 3.4.11 loops, best of 3: 742 ms per loop1000000 loops, best of 3: 1.19 µs per loop
Com base no timeit
resultados acima, vê-se que a execução do “olhar para cima” foi cerca de 60.000 mais rápida quando era de um tipo inteiro e não de um flutuador. No entanto, desde Python 2.x’s range
ou xrange
não tem um método __contains__
, a “velocidade de procura” não seria muito diferente para números inteiros ou flutuadores:
print 'Python', python_version()assert(val_in_xrange(x, x/2.0) == True)assert(val_in_xrange(x, x/2) == True)assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_xrange(x, x/2.0)%timeit val_in_xrange(x, x/2)%timeit val_in_range(x, x/2.0)%timeit val_in_range(x, x/2)
Python 2.7.71 loops, best of 3: 285 ms per loop1 loops, best of 3: 179 ms per loop1 loops, best of 3: 658 ms per loop1 loops, best of 3: 556 ms per loop
Below as “provas” de que o método __contain__
não foi adicionado ao Python 2.x ainda:
print('Python', python_version())range.__contains__
Python 3.4.1<slot wrapper '__contains__' of 'range' objects>
print 'Python', python_version()range.__contains__
Python 2.7.7---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-7-05327350dafb> in <module>() 1 print 'Python', python_version()----> 2 range.__contains__AttributeError: 'builtin_function_or_method' object has no attribute '__contains__'
/div>
print 'Python', python_version()xrange.__contains__
Python 2.7.7---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-8-7d1a71bfee8e> in <module>() 1 print 'Python', python_version()----> 2 xrange.__contains__AttributeError: type object 'xrange' has no attribute '__contains__'
Nota sobre as diferenças de velocidade em Python 2 e 3
algumas pessoas apontaram a diferença de velocidade entre Python 3’s range()
e Python2’s xrange()
. Uma vez que são implementadas da mesma forma, seria de esperar a mesma velocidade. No entanto, a diferença aqui advém apenas do facto de que Python 3 geralmente tende a correr mais devagar do que Python 2.
def test_while(): i = 0 while i < 20000: i += 1 return
print('Python', python_version())%timeit test_while()
Python 3.4.1100 loops, best of 3: 2.68 ms per loop
print 'Python', python_version()%timeit test_while()
Python 2.7.61000 loops, best of 3: 1.72 ms per loop
Aumentar excepções
Onde Python 2 aceita ambas as notações, a sintaxe “velha” e “nova”, Python 3 engasga (e levanta um SyntaxError
por sua vez) se não encerrarmos o argumento de excepção entre parênteses:
Python 2
print 'Python', python_version()
>div>>
Python 2.7.6
raise IOError, "file error"
---------------------------------------------------------------------------IOError Traceback (most recent call last)<ipython-input-8-25f049caebb0> in <module>()----> 1 raise IOError, "file error"IOError: file error
raise IOError("file error")
---------------------------------------------------------------------------IOError Traceback (most recent call last)<ipython-input-9-6f1c43f525b2> in <module>()----> 1 raise IOError("file error")IOError: file error
Python 3
print('Python', python_version())
Python 3.4.1
/div>
raise IOError, "file error"
File "<ipython-input-10-25f049caebb0>", line 1 raise IOError, "file error" ^SyntaxError: invalid syntax
A forma adequada de levantar uma excepção em Python 3:
print('Python', python_version())raise IOError("file error")
Excepções de manuseamento
Também o manuseamento de excepções mudou ligeiramente em Python 3. Em Python 3 temos de usar a palavra-chave “as
” agora
Python 2
print 'Python', python_version()try: let_us_cause_a_NameErrorexcept NameError, err: print err, '--> our error message'
Python 2.7.6name 'let_us_cause_a_NameError' is not defined --> our error message
Python 3
print('Python', python_version())try: let_us_cause_a_NameErrorexcept NameError as err: print(err, '--> our error message')
Python 3.4.1name 'let_us_cause_a_NameError' is not defined --> our error message
Desde next()
.next()
) é uma função (método) tão vulgarmente utilizada, esta é outra mudança de sintaxe (ou melhor, mudança na implementação) que vale a pena mencionar: onde se pode usar tanto a função como a sintaxe do método em Python 2.7.5, o next()
função é tudo o que permanece em Python 3 (chamando o .next()
método levanta um AttributeError
).
Python 2
print 'Python', python_version()my_generator = (letter for letter in 'abcdefg')next(my_generator)my_generator.next()
>div>>
Python 2.7.6'b'
Python 3
print('Python', python_version())my_generator = (letter for letter in 'abcdefg')next(my_generator)
Python 3.4.1'a'
my_generator.next()
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-14-125f388bb61b> in <module>()----> 1 my_generator.next()AttributeError: 'generator' object has no attribute 'next'
Para…variáveis de loop e o espaço de nomes global
Notícias boas são: Em Python 3.x for-loop variables don’t leak into the global namespace anymore!
Isto volta a uma mudança que foi feita em Python 3.x e é descrita em What’s New In Python 3.0 da seguinte forma:
“List comprehensions no longer support the syntactic form . Utilizar
em vez disso. Note também que as compreensões da lista têm semântica diferente: estão mais próximas do açúcar sintáctico para uma expressão do gerador dentro de um
list()
construtor, e em particular as variáveis de controlo do laço já não são vazadas para o âmbito circundante.”
Python 2
print 'Python', python_version()i = 1print 'before: i =', iprint 'comprehension: ', print 'after: i =', i
Python 2.7.6before: i = 1comprehension: after: i = 4
Python 3
print('Python', python_version())i = 1print('before: i =', i)print('comprehension:', )print('after: i =', i)
Python 3.4.1before: i = 1comprehension: after: i = 1
Comparar tipos não ordenáveis
Outra mudança agradável em Python 3 é que um TypeError
é levantado como aviso se tentarmos comparar tipos não ordenáveis.
Python 2
print 'Python', python_version()print " > 'foo' = ", > 'foo'print "(1, 2) > 'foo' = ", (1, 2) > 'foo'print " > (1, 2) = ", > (1, 2)
Python 2.7.6 > 'foo' = False(1, 2) > 'foo' = True > (1, 2) = False
>h4>Python 3
print('Python', python_version())print(" > 'foo' = ", > 'foo')print("(1, 2) > 'foo' = ", (1, 2) > 'foo')print(" > (1, 2) = ", > (1, 2))
Python 3.4.1---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-16-a9031729f4a0> in <module>() 1 print('Python', python_version())----> 2 print(" > 'foo' = ", > 'foo') 3 print("(1, 2) > 'foo' = ", (1, 2) > 'foo') 4 print(" > (1, 2) = ", > (1, 2))TypeError: unorderable types: list() > str()
Desfazer as entradas do utilizador via input()
Felizmente, a função input()
foi fixada em Python 3 para que armazene sempre as entradas do utilizador como str
objectos. A fim de evitar o comportamento perigoso em Python 2 para ler em outros tipos que não strings
, temos de usar raw_input()
em vez disso.
Python 2
Python 2.7.6 em darwinType "ajuda", "copyright", "créditos" ou "licença" para mais informações.>>> my_input = input('digite um número: ')digite um número: 123>>> type(my_input)<type 'int'>>>> my_input = raw_input('inserir um número: ')introduza um número: 123>>> type(my_input)<type str'>
Python 3
Python 3.4.1 sobre darwinType "ajuda", "copyright", "créditos" ou "licença" para mais informações.>>> my_input = input('digite um número: ')digite um número: 123>>> type(my_input)<classe 'str'>
Retornar objectos iteráveis em vez de listas
Como já vimos na secção xrange
, algumas funções e métodos devolvem agora objectos iteráveis em Python 3 – em vez de listas em Python 2.
Desde que nós normalmente iteramos sobre aqueles apenas uma vez de qualquer forma, penso que esta mudança faz muito sentido para salvar a memória. Contudo, também é possível – em contraste com os geradores – iterar sobre aqueles várias vezes, se necessário, só não é tão eficiente.
E para os casos em que precisamos realmente da função list
-objectos, podemos simplesmente converter o objecto iterável em list
através da função list()
.
Python 2
print 'Python', python_version()print range(3)print type(range(3))
Python 2.7.6<type 'list'>
Python 3
print('Python', python_version())print(range(3))print(type(range(3)))print(list(range(3)))
Python 3.4.1range(0, 3)<class 'range'>
algumas funções e métodos mais comummente utilizados que já não devolvem listas em Python 3:
-
zip()
-
map()
-
filter()
-
dicionário’s
.keys()
método -
dicionário’s
.values()
método -
dicionários
.items()
método
Arredondamento do Banqueiro
Python 3 adoptou a forma agora padrão de arredondamento de decimais quando resulta num empate (.5) nos últimos dígitos significativos. Agora, em Python 3, as casas decimais são arredondadas para o número par mais próximo. Embora seja um inconveniente para a portabilidade do código, é supostamente uma melhor forma de arredondamento em comparação com o arredondamento para cima, uma vez que evita o enviesamento para números grandes. Para mais informações, ver os excelentes artigos e parágrafos da Wikipedia:
- https://en.wikipedia.org/wiki/Rounding#Round_half_to_even
- https://en.wikipedia.org/wiki/IEEE_floating_point#Roundings_to_nearest
Python 2
print 'Python', python_version()
Python 2.7.12
round(15.5)
16.0
round(16.5)
17.0
Python 3
print('Python', python_version())
Python 3.5.1
round(15.5)
16
round(16.5)
16
Mais artigos sobre Python 2 e Python 3
Aqui está uma lista de alguns bons artigos sobre Python 2 e 3 que eu recomendaria como seguimento…para cima.
/ Porting to Python 3
-
Devo usar Python 2 ou Python 3 para a minha actividade de desenvolvimento?
-
O que há de novo em Python 3.0
-
Porting to Python 3
-
Porting Python 2 Code to Python 3
-
Como manter Python 3 avançando
/ Pro e anti Python 3
-
10 características fantásticas de Python que não se pode usar porque se recusa a actualizar para Python 3
-
p>Tudo o que não queria saber sobre Unicode em Python 3
-
Python 3 está a matar Python
-
Python 3 está bem
Python 3 pode reanimar Python