As diferenças chave entre Python 2.7.x e Python 3.x com exemplos

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 3 xrange

    • Python 2
    • Python 3
    • O __contains__ método para range objectos em Python 3
      • Nota sobre as diferenças de velocidade em Python 2 e 3
  • Levantamento de excepções
    • Python 2
    • Python 3
  • Excepções de manuseamento
    • Python 2
    • Python 3
  • Python 2
  • Python 3
  • Python 3

  • For-variáveis de loop e o espaço de nomes global
    • Python 2
    • Python 3
  • Comparar tipos não ordenáveis
    • Python 2
    • Python 3
  • Parsing user inputs via input()
    • Python 2
    • Python 3
  • Devolver objectos iteráveis em vez de listas
    • Python 2
    • Python 3
  • Arredondamento de banqueiros
    • Python 2
    • Python 3
  • Mais artigos sobre Python 2 e 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:

    >

    >th>feature>th>optional inth>mandatory in>th>effect
    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

    (Fonte: (https://docs.python.org/2/library/__future__.html#module-__future
    div>>div>>

    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
    div id=”9936883015″>
     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

    div>

    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) strings, e 2 classes de bytes: byte e bytearrays.

    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__
    div>>

    Python 3.4.1<slot wrapper '__contains__' of 'range' objects>
    div>

    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")
    div>>div id=”ba858f07″>

    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

    div>

    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()
    div>

    ---------------------------------------------------------------------------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 pode reanimar Python

    • Python 3 está bem

    Deixe uma resposta

    O seu endereço de email não será publicado. Campos obrigatórios marcados com *