Поиск…


Вступление

В отличие от большинства языков, Python поддерживает две основные версии. С 2008 года, когда был выпущен Python 3, многие сделали переход, в то время как многие из них этого не сделали. Чтобы понять оба варианта, в этом разделе рассматриваются важные различия между Python 2 и Python 3.

замечания

В настоящее время существуют две поддерживаемые версии Python: 2.7 (Python 2) и 3.6 (Python 3). Кроме того, версии 3.3 и 3.4 получают обновления безопасности в исходном формате.

Python 2.7 совместим с предыдущими версиями Python и может запускать код Python из версий 1.x и 2.x Python без изменений. Он широко доступен с обширной коллекцией пакетов. Он также считается устаревшим разработчиком CPython и получает только защиту и исправление ошибок. Разработчики CPython намерены отказаться от этой версии языка в 2020 году .

Согласно Python Enhancement Proposal 373 , запланированные будущие выпуски Python 2 после 25 июня 2016 года не будут исправлены, но исправления ошибок и обновления безопасности будут поддерживаться до 2020 года. (В нем не указано, какой точной датой в 2020 году станет дата заката Python 2.)

Python 3 намеренно нарушил совместимость в обратном направлении, чтобы решить проблемы, с которыми языковые разработчики сталкивались с ядром языка. Python 3 получает новые разработки и новые функции. Это версия языка, которую разработчики языка намерены продвигать вперед.

За время между первоначальным выпуском Python 3.0 и текущей версией некоторые функции Python 3 были перенесены в Python 2.6, а другие части Python 3 были расширены, чтобы иметь синтаксис, совместимый с Python 2. Поэтому можно писать Python, который будет работать как на Python 2, так и на Python 3, используя будущие импорты и специальные модули (например, шесть ).

Будущий импорт должен быть в начале вашего модуля:

from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')

Для получения дополнительной информации о модуле __future__ см. Соответствующую страницу в документации Python .

Инструмент 2to3 - это программа Python, которая преобразует код Python 2.x в код Python 3.x, см. Также документацию Python .

В пакете 6 предусмотрены утилиты для совместимости с Python 2/3:

  • унифицированный доступ к переименованным библиотекам
  • переменные для типов string / unicode
  • функции для метода, который был удален или был переименован

Ссылка на различия между Python 2 и Python 3 приведена здесь .

Операция печати и функции печати

В Python 2 print - это утверждение:

Python 2.x 2.7
print "Hello World"
print                         # print a newline
print "No newline",           # add trailing comma to remove newline 
print >>sys.stderr, "Error"   # print to stderr
print("hello")                # print "hello", since ("hello") == "hello"
print()                       # print an empty tuple "()"
print 1, 2, 3                 # print space-separated arguments: "1 2 3"
print(1, 2, 3)                # print tuple "(1, 2, 3)"

В Python 3 функция print() - это функция с аргументами ключевого слова для общего использования:

Python 3.x 3.0
print "Hello World"              # SyntaxError
print("Hello World")
print()                          # print a newline (must use parentheses)
print("No newline", end="")      # end specifies what to append (defaults to newline)
print("Error", file=sys.stderr)  # file specifies the output buffer
print("Comma", "separated", "output", sep=",")  # sep specifies the separator
print("A", "B", "C", sep="")     # null string for sep: prints as ABC
print("Flush this", flush=True)  # flush the output buffer, added in Python 3.3
print(1, 2, 3)                   # print space-separated arguments: "1 2 3"
print((1, 2, 3))                 # print tuple "(1, 2, 3)"

Функция печати имеет следующие параметры:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

sep - это то, что отделяет объекты, которые вы передаете, для печати. Например:

print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar

end - это то, что следует за завершением инструкции print. Например:

print('foo', 'bar', end='!') # out: foo bar!

Повторная печать после завершающего оператора печати, не относящегося к новой строке, будет напечатана в той же строке:

print('foo', end='~')
print('bar')
# out: foo~bar

Примечание. Для будущей совместимости функция print также доступна в Python 2.6; однако его нельзя использовать, если разбор инструкции print не отключен

from __future__ import print_function

Эта функция имеет тот же формат, что и Python 3, за исключением того, что ему не хватает параметра flush .

См. PEP 3105 для обоснования.

Строки: байты против Unicode

Python 2.x 2.7

В Python 2 есть два варианта строки: те из байтов с типом ( str ) и те, что сделаны из текста с типом ( unicode ).

В Python 2 объект типа str всегда является байтовой последовательностью, но обычно используется как для текстовых, так и для двоичных данных.

Строковый литерал интерпретируется как байтовая строка.

s = 'Cafe'    # type(s) == str

Есть два исключения: вы можете явно определить литерал Unicode (text) , префиксного литерала с помощью u :

s = u'Café'   # type(s) == unicode
b = 'Lorem ipsum'  # type(b) == str

Кроме того, вы можете указать, что строковые литералы всего модуля должны создавать литералы Unicode (text):

from __future__ import unicode_literals

s = 'Café'   # type(s) == unicode
b = 'Lorem ipsum'  # type(b) == unicode

Чтобы проверить, является ли ваша переменная строкой (либо Unicode, либо байтовая строка), вы можете использовать:

isinstance(s, basestring)
Python 3.x 3.0

В Python 3 тип str - это текстовый тип Unicode.

s = 'Cafe'           # type(s) == str
s = 'Café'           # type(s) == str (note the accented trailing e)

Кроме того, Python 3 добавил объект bytes , подходящий для двоичных «blobs» или записи в независимые от кодирования файлы. Чтобы создать объект байтов, вы можете префикс b в строковый литерал или вызвать метод encode строки:

# Or, if you really need a byte string:
s = b'Cafe'          # type(s) == bytes
s = 'Café'.encode()  # type(s) == bytes

Чтобы проверить, является ли значение строкой, используйте:

isinstance(s, str)
Python 3.x 3.3

Также возможно префикс строковых литералов с префиксом u чтобы упростить совместимость между базами данных Python 2 и Python 3. Поскольку в Python 3 все строки по умолчанию Unicode, добавление строкового литерала с u имеет никакого эффекта:

u'Cafe' == 'Cafe'

Python 2 в сырце Unicode строки префикс ur не поддерживаются, однако:

>>> ur'Café'
  File "<stdin>", line 1
    ur'Café'
           ^
SyntaxError: invalid syntax

Обратите внимание, что вы должны encode объект Python 3 text ( str ), чтобы преобразовать его в представление bytes этого текста. Кодировка по умолчанию этого метода - UTF-8 .

Вы можете использовать decode чтобы задать объект bytes для текста Unicode, который он представляет:

>>> b.decode()
'Café'
Python 2.x 2.6

Хотя тип bytes существует как в Python 2, так и в 3, тип unicode существует только в Python 2. Чтобы использовать неявные строки Unicode Python 3 в Python 2, добавьте следующее в начало файла кода:

from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
Python 3.x 3.0

Другое важное различие заключается в том, что индексирование байтов в Python 3 приводит к выводу int так:

b"abc"[0] == 97

В то время как разрезание в размере одного результата приводит к объекту длиной 1 байт:

b"abc"[0:1] == b"a"

Кроме того, Python 3 исправляет некоторые необычные действия с помощью unicode, т. Е. Обратные байтовые строки в Python 2. Например, разрешена следующая проблема :

# -*- coding: utf8 -*-
print("Hi, my name is Łukasz Langa.")
print(u"Hi, my name is Łukasz Langa."[::-1])
print("Hi, my name is Łukasz Langa."[::-1])

# Output in Python 2
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsaku�� si eman ym ,iH

# Output in Python 3
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsakuŁ si eman ym ,iH

Целостный отдел

Стандартный символ разделения ( / ) работает по-разному в Python 3 и Python 2 при применении к целым числам.

При делении целого на другое целое число в Python 3 операция деления x / y представляет собой истинное деление (использует метод __truediv__ ) и производит результат с плавающей запятой. Между тем, та же операция в Python 2 представляет собой классическое разделение, которое округляет результат до отрицательной бесконечности (также известный как слово ).

Например:

Код Выход Python 2 Выход Python 3
3 / 2 1 1,5
2 / 3 0 0,6666666666666666
-3 / 2 -2 -1,5

Поведение округления к нулю было устарело в Python 2.2 , но осталось в Python 2.7 для обратной совместимости и было удалено в Python 3.

Примечание. Чтобы получить результат с плавающей точкой в Python 2 (без округления по полу), мы можем указать один из операндов с десятичной точкой. Вышеприведенный пример 2/3 который дает 0 в Python 2, должен использоваться как 2 / 3.0 или 2.0 / 3 или 2.0/3.0 для получения 0.6666666666666666

Код Выход Python 2 Выход Python 3
3.0 / 2.0 1,5 1,5
2 / 3.0 0,6666666666666666 0,6666666666666666
-3.0 / 2 -1,5 -1,5

Существует также оператор деления пола ( // ), который работает одинаково в обеих версиях: он округляется до ближайшего целого. (хотя float возвращается при использовании с float). В обеих версиях оператор // сопоставляется с __floordiv__ .

Код Выход Python 2 Выход Python 3
3 // 2 1 1
2 // 3 0 0
-3 // 2 -2 -2
3.0 // 2.0 1,0 1,0
2.0 // 3 0.0 0.0
-3 // 2.0 -2,0 -2,0

В явном виде можно обеспечить прямое разделение или разделение полов с использованием собственных функций в модуле operator :

from operator import truediv, floordiv
assert truediv(10, 8) == 1.25            # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1              # equivalent to `//`

Хотя ясное и ясное, использование операторских функций для каждого деления может быть утомительным. Частое изменение поведения оператора / часто бывает предпочтительным. Общей практикой является устранение типичного поведения деления путем добавления from __future__ import division в качестве первого оператора в каждом модуле:

# needs to be the first statement in a module
from __future__ import division
Код Выход Python 2 Выход Python 3
3 / 2 1,5 1,5
2 / 3 0,6666666666666666 0,6666666666666666
-3 / 2 -1,5 -1,5

from __future__ import division гарантирует, что оператор / представляет истинное деление и только внутри модулей, которые содержат импорт __future__ , поэтому нет никаких веских причин не включать его во все новые модули.

Примечание . Некоторые другие языки программирования используют округление до нуля (усечение), а не округление до отрицательной бесконечности, как это делает Python (т.е. на этих языках -3 / 2 == -1 ). Такое поведение может вызвать путаницу при переносе или сравнении кода.


Примечание по операндам float . В качестве альтернативы from __future__ import division можно использовать обычный символ разделения / и гарантировать, что хотя бы один из операндов является float: 3 / 2.0 == 1.5 . Однако это можно считать плохой практикой. Слишком просто написать average = sum(items) / len(items) и забыть использовать один из аргументов для float. Более того, такие случаи могут часто уклоняться от уведомления во время тестирования, например, если вы тестируете массив, содержащий float s, но получаете массив int s в процессе производства. Кроме того, если тот же код используется в Python 3, программы, ожидающие, что 3/2 3 / 2 == 1 будет True, будут работать неправильно.

См. PEP 238 для более подробного обоснования того, почему оператор разделения был изменен в Python 3 и почему следует избегать разделения в старом стиле.


См. Раздел « Простая математика» для получения дополнительной информации о разделении.

Сокращение больше не является встроенным

В Python 2 reduce доступно либо как встроенная функция, либо из пакета functools (начиная с версии 2.6), тогда как в Python 3 reduce доступно только из functools . Однако синтаксис reduce как в Python2, так и в Python3 одинаковый и reduce(function_to_reduce, list_to_reduce) .

В качестве примера рассмотрим сокращение списка до одного значения путем деления каждого из соседних чисел. Здесь мы используем функцию truediv из библиотеки operator .

В Python 2.x это просто:

Python 2.x 2.3
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333

В Python 3.x пример становится немного сложнее:

Python 3.x 3.0
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333

Мы также можем использовать from functools import reduce чтобы избежать reduce вызова с помощью имени пространства имен.

Различия между диапазонами и функциями xrange

В Python 2 функция range возвращает список, тогда как xrange создает специальный объект xrange , который является неизменной последовательностью, которая, в отличие от других встроенных типов последовательностей, не поддерживает срез и не имеет ни методов index ни count :

Python 2.x 2.3
print(range(1, 10))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(isinstance(range(1, 10), list))
# Out: True

print(xrange(1, 10))
# Out: xrange(1, 10)

print(isinstance(xrange(1, 10), xrange))
# Out: True

В Python 3 xrange был расширен до последовательности range , что теперь создает объект range . Нет типа xrange :

Python 3.x 3.0
print(range(1, 10))
# Out: range(1, 10)

print(isinstance(range(1, 10), range))
# Out: True

# print(xrange(1, 10))
# The output will be:
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#NameError: name 'xrange' is not defined

Кроме того, поскольку Python 3.2, range также поддерживает нарезку, index и count :

print(range(1, 10)[3:7])
# Out: range(3, 7)
print(range(1, 10).count(5))
# Out: 1
print(range(1, 10).index(7))
# Out: 6

Преимущество использования специального типа последовательности вместо списка состоит в том, что интерпретатору не нужно выделять память для списка и заполнять его:

Python 2.x 2.3
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# MemoryError

print(xrange(100000000000000000))
# Out: xrange(100000000000000000)

Поскольку последнее поведение обычно желательно, первое было удалено в Python 3. Если вы все еще хотите иметь список в Python 3, вы можете просто использовать конструктор list() для объекта range :

Python 3.x 3.0
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Совместимость

Чтобы поддерживать совместимость между версиями Python 2.x и Python 3.x, вы можете использовать builtins модуль из future внешнего пакета для достижения как совместимости с переходом, так и обратной совместимости :

Python 2.x 2.0
#forward-compatible
from builtins import range

for i in range(10**8):
    pass
Python 3.x 3.0
#backward-compatible
from past.builtins import xrange

for i in xrange(10**8):
    pass

range в future библиотеке поддерживает нарезку, index и count во всех версиях Python, как и встроенный метод на Python 3.2+.

Распаковка итераций

Python 3.x 3.0

В Python 3 вы можете распаковать итерацию, не зная точного количества элементов в ней и даже иметь переменную, удерживающую конец итерабельного. Для этого вы предоставляете переменную, которая может собирать список значений. Это делается путем размещения звездочки перед именем. Например, распаковка list :

first, second, *tail, last = [1, 2, 3, 4, 5]
print(first)
# Out: 1
print(second)
# Out: 2
print(tail)
# Out: [3, 4]
print(last)
# Out: 5

Примечание . При использовании синтаксиса *variable variable всегда будет списком, даже если исходный тип не был списком. Он может содержать ноль или более элементов в зависимости от количества элементов в исходном списке.

first, second, *tail, last = [1, 2, 3, 4]
print(tail)
# Out: [3]

first, second, *tail, last = [1, 2, 3]
print(tail)
# Out: []
print(last)
# Out: 3

Аналогично, распаковка str :

begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']

Пример распаковки date ; _ Используется в этом примере в качестве переменной (холостой мы заинтересованы только в year стоимости):

person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016

Стоит отметить, что, поскольку * ест переменное количество элементов, вы не можете иметь два * s для одного и того же итерабельного в задании - он не будет знать, сколько элементов входит в первую распаковку, и сколько во втором :

*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
Python 3.x 3.5

До сих пор мы обсуждали распаковку в заданиях. * и ** были расширены в Python 3.5 . Теперь в одном выражении можно иметь несколько операций распаковки:

{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
Python 2.x 2.0

Также можно распаковать итерируемый аргумент функции:

iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
Python 3.x 3.5

Распаковка словаря использует две соседние звезды ** ( PEP 448 ):

tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
 # Out: {'x': 1, 'y': 2, 'z': 3}

Это позволяет как переопределять старые значения, так и объединять словари.

dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3.x 3.0

Python 3 удаляет распаковку в функции. Следовательно, в Python 3 не работает следующее

# Works in Python 2, but syntax error in Python 3:
map(lambda (x, y): x + y, zip(range(5), range(5)))
# Same is true for non-lambdas:
def example((x, y)):
    pass

# Works in both Python 2 and Python 3:
map(lambda x: x[0] + x[1], zip(range(5), range(5)))
# And non-lambdas, too:
def working_example(x_y):
    x, y = x_y
    pass

См. PEP 3113 для подробного обоснования.

Поднятие и обработка исключений

Это синтаксис Python 2, обратите внимание на запятые , на raise и except строк:

Python 2.x 2.3
try:
    raise IOError, "input/output error"
except IOError, exc:
    print exc

В Python 3, , синтаксис отбрасывается и заменяется скобкой и в as ключевого слова:

try:
    raise IOError("input/output error")
except IOError as exc:
    print(exc)

Для обратной совместимости синтаксис Python 3 также доступен в Python 2.6, поэтому он должен использоваться для всего нового кода, который не должен быть совместим с предыдущими версиями.


Python 3.x 3.0

Python 3 также добавляет цепочку исключений , в которой вы можете указать, что причиной этого исключения является другое исключение. Например

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}') from e

Исключение, возникающее в инструкции except имеет тип DatabaseError , но исходное исключение помечено как атрибут __cause__ этого исключения. Когда отображается трассировка, исходное исключение также будет отображаться в traceback:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
FileNotFoundError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')

Если вы выбрали except блок без явной цепочки:

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}')

След

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
FileNotFoundError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Python 2.x 2.0

Ни один из них не поддерживается в Python 2.x; исходное исключение и его трассировка будут потеряны, если в исключающем блоке будет создано другое исключение. Следующий код может использоваться для совместимости:

import sys
import traceback

try:
    funcWithError()
except:
    sys_vers = getattr(sys, 'version_info', (0,))
    if sys_vers < (3, 0):
        traceback.print_exc()
    raise Exception("new exception")
Python 3.x 3.3

Чтобы «забыть» ранее заброшенное исключение, используйте raise from None

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}') from None

Теперь трассировка будет просто

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')

Или, чтобы сделать его совместимым с Python 2 и 3, вы можете использовать шесть пакетов следующим образом:

import six
try:
    file = open('database.db')
except FileNotFoundError as e:
    six.raise_from(DatabaseError('Cannot open {}'), None)

.next () для итераторов, переименованных

В Python 2 итератор может быть пройден с помощью метода, называемого next на самом итераторе:

Python 2.x 2.3
g = (i for i in range(0, 3))
g.next()  # Yields 0
g.next()  # Yields 1
g.next()  # Yields 2

В Python 3 метод .next был переименован в .__next__ , признав свою «магическую» роль, поэтому вызов .next повысит AttributeError . Правильный способ доступа к этой функциональности как в Python 2, так и в Python 3 - это вызов next функции с итератором в качестве аргумента.

Python 3.x 3.0
g = (i for i in range(0, 3))
next(g)  # Yields 0
next(g)  # Yields 1
next(g)  # Yields 2

Этот код переносится в разных версиях от версии 2.6 до последних версий.

Сравнение различных типов

Python 2.x 2.3

Можно сравнить объекты разных типов. Результаты являются произвольными, но непротиворечивыми. Они упорядочены так, что None меньше, чем что-либо еще, числовые типы меньше, чем нечисловые типы, а все остальное упорядочено лексикографически по типу. Таким образом, int меньше, чем str а tuple больше, чем list :

[1, 2] > 'foo'
# Out: False
(1, 2) > 'foo'
# Out: True
[1, 2] > (1, 2)
# Out: False
100 < [1, 'x'] < 'xyz' < (1, 'x')
# Out: True

Первоначально это было сделано, поэтому список смешанных типов можно было отсортировать, и объекты будут сгруппированы по типу:

l = [7, 'x', (1, 2), [5, 6], 5, 8.0, 'y', 1.2, [7, 8], 'z']
sorted(l)
# Out: [1.2, 5, 7, 8.0, [5, 6], [7, 8], 'x', 'y', 'z', (1, 2)]
Python 3.x 3.0

Исключение возникает при сравнении разных (нечисловых) типов:

1 < 1.5
# Out: True

[1, 2] > 'foo'
# TypeError: unorderable types: list() > str()
(1, 2) > 'foo'
# TypeError: unorderable types: tuple() > str()
[1, 2] > (1, 2)
# TypeError: unorderable types: list() > tuple()

Чтобы отсортировать смешанные списки в Python 3 по типам и добиться совместимости между версиями, вы должны предоставить ключ к отсортированной функции:

>>> list = [1, 'hello', [3, 4], {'python': 2}, 'stackoverflow', 8, {'python': 3}, [5, 6]]
>>> sorted(list, key=str)
# Out: [1, 8, [3, 4], [5, 6], 'hello', 'stackoverflow', {'python': 2}, {'python': 3}]

Использование str в качестве key функции временно преобразует каждый элемент в строку только для целей сравнения. Затем он видит строковое представление, начиная с [ , ' , { или 0-9 и он может сортировать эти (и все следующие символы).

Вход пользователя

В Python 2 пользовательский ввод принимается с использованием функции raw_input ,

Python 2.x 2.3
user_input = raw_input()

В то время как в Python 3 пользовательский ввод принимается с использованием функции input .

Python 3.x 3.0
user_input = input()

В Python 2 input функция принимает вход и интерпретирует его. Хотя это может быть полезно, оно имеет несколько соображений безопасности и было удалено в Python 3. Для доступа к той же функциональности можно использовать eval(input()) .

Чтобы сохранить сценарий переносимым по двум версиям, вы можете поместить код ниже в верхней части своего сценария Python:

try:
    input = raw_input
except NameError:
    pass

Изменения в словаре

В Python 3 многие из методов словаря отличаются поведением от Python 2, и многие также были удалены: has_key , iter* и view* исчезли. Вместо d.has_key(key) , который давно устарел, теперь нужно использовать key in d .

В Python 2 словарные keys методов, values и items возвращают списки. В Python 3 вместо этого они возвращают объекты вида ; объекты представления не являются итераторами, и они отличаются от них двумя способами, а именно:

  • они имеют размер (на них можно использовать функцию len )
  • они могут повторяться много раз

Кроме того, как итераторы, изменения в словаре отражаются в объектах представления.

Python 2.7 поддерживает эти методы с Python 3; они доступны как viewkeys , viewvalues и viewitems . Чтобы преобразовать код Python 2 в код Python 3, соответствующие формы:

  • d.keys() , d.values() и d.items() Python 2 должны быть изменены в list(d.keys()) , list(d.values()) и list(d.items())
  • d.iterkeys() , d.itervalues() и d.iteritems() должны быть изменены на iter(d.keys()) или даже лучше, iter(d) ; iter(d.values()) и iter(d.items()) соответственно
  • и, наконец, методы Python 2.7 вызовы d.viewkeys() , d.viewvalues() и d.viewitems() могут быть заменены на d.keys() , d.values() и d.items() .

Портирование кода Python 2, который выполняет итерации по словарным клавишам, значениям или элементам при их мутации, иногда бывает сложным. Рассматривать:

d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
    if key.isalpha():
        del d[key]

Код выглядит так, как если бы он работал аналогично в Python 3, но там метод keys возвращает объект вида, а не список, и если словарь изменяет размер при повторении, код Python 3 будет сбой с RuntimeError: dictionary changed size during iteration . Разумеется, решение должно правильно записываться for key in list(d) .

Аналогично, объекты просмотра ведут себя иначе, чем итераторы: нельзя использовать next() для них, и нельзя возобновить итерацию; он вместо этого перезапустится; если код Python 2 передает возвращаемое значение d.iterkeys() , d.itervalues() или d.iteritems() в метод, который ожидает итератор вместо итерабельного , то это должно быть iter(d) , iter(d.values()) или iter(d.items()) в Python 3.

Оператор exec является функцией в Python 3

В Python 2 exec - это оператор со специальным синтаксисом: exec code [in globals[, locals]]. В Python 3 exec теперь есть функция: exec(code, [, globals[, locals]]) , а синтаксис Python 2 поднимет SyntaxError .

Поскольку print была изменена из оператора в функцию, был __future__ импорт __future__ . Тем не менее, нет from __future__ import exec_function , поскольку он не нужен: оператор exec в Python 2 также может использоваться с синтаксисом, который выглядит точно так же, как вызов функции exec в Python 3. Таким образом, вы можете изменить утверждения

Python 2.x 2.3
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars

к формам

Python 3.x 3.0
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)

и последние формы гарантированно работают одинаково как в Python 2, так и в Python 3.

Ошибка функции hasattr в Python 2

В Python 2, когда свойство hasattr ошибку, hasattr игнорирует это свойство, возвращая False .

class A(object):
    @property
    def get(self):
        raise IOError


class B(object):
    @property
    def get(self):
        return 'get in b'

a = A()
b = B()

print 'a hasattr get: ', hasattr(a, 'get')
# output False in Python 2 (fixed, True in Python 3)
print 'b hasattr get', hasattr(b, 'get')
# output True in Python 2 and Python 3

Эта ошибка исправлена ​​в Python3. Поэтому, если вы используете Python 2, используйте

try:
    a.get
except AttributeError:
    print("no get property!")

или вместо этого использовать getattr

p = getattr(a, "get", None)
if p is not None:
    print(p)
else:
    print("no get property!")

Переименованные модули

Несколько модулей в стандартной библиотеке были переименованы:

Старое название Новое имя
_winreg WinREG
ConfigParser ConfigParser
copy_reg copyreg
Очередь очередь
SocketServer SocketServer
_markupbase markupbase
магнезии reprlib
test.test_support test.support
Tkinter Tkinter
tkFileDialog tkinter.filedialog
urllib / urllib2 urllib, urllib.parse, urllib.error, urllib.response, urllib.request, urllib.robotparser

Некоторые модули даже были преобразованы из файлов в библиотеки. Возьмите tkinter и urllib сверху в качестве примера.

Совместимость

Поддерживая совместимость между версиями Python 2.x и 3.x, вы можете использовать future внешний пакет, чтобы включить импорт стандартных пакетов стандартного пакета с именами Python 3.x в версиях Python 2.x.

Октальные константы

В Python 2 восьмой литерал можно определить как

>>> 0755  # only Python 2

Чтобы обеспечить кросс-совместимость, используйте

0o755  # both Python 2 and Python 3

Все классы являются «классами нового стиля» в Python 3.

В Python 3.x все классы являются классами нового стиля ; при определении нового класса python неявно делает его наследуемым от object . Таким образом, указание object в определении class является полностью необязательным:

Python 3.x 3.0
class X: pass
class Y(object): pass

Оба этих класса теперь содержат object в своем mro (порядок разрешения метода):

Python 3.x 3.0
>>> X.__mro__
(__main__.X, object)

>>> Y.__mro__
(__main__.Y, object)

В классах Python 2.x по умолчанию используются классы старого стиля; они не неявно наследуют от object . Это заставляет семантику классов различаться в зависимости от того, если мы явно добавляем object в качестве базового class :

Python 2.x 2.3
class X: pass
class Y(object): pass

В этом случае, если мы попытаемся напечатать __mro__ of Y , __mro__ аналогичный вывод, как в случае с Python 3.x :

Python 2.x 2.3
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)

Это происходит потому, что мы явно наследовали Y от объекта при его определении: class Y(object): pass . Для класса X который не наследуется от объекта, атрибут __mro__ не существует, попытка доступа к нему приводит к __mro__ AttributeError .

Чтобы обеспечить совместимость между обеими версиями Python, классы могут быть определены с object в качестве базового класса:

class mycls(object):
    """I am fully compatible with Python 2/3"""

В качестве альтернативы, если переменная __metaclass__ задана для type в глобальной области видимости, все последующие классы в данном модуле являются неявно новыми, не требуя явно наследовать от object :

__metaclass__ = type

class mycls:
    """I am also fully compatible with Python 2/3"""

Удаленные операторы <> и ``, синонимичные с! = И repr ()

В Python 2 <> является синонимом для != ; Аналогично, `foo` является синонимом для repr(foo) .

Python 2.x 2.7
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
Python 3.x 3.0
>>> 1 <> 2
  File "<stdin>", line 1
    1 <> 2
       ^
SyntaxError: invalid syntax
>>> `foo`
  File "<stdin>", line 1
    `foo`
    ^
SyntaxError: invalid syntax

кодирование / декодирование в hex больше недоступно

Python 2.x 2.7
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
Python 3.x 3.0
"1deadbeef3".decode('hex')
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: 'str' object has no attribute 'decode'

b"1deadbeef3".decode('hex')
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs

'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs

b'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# AttributeError: 'bytes' object has no attribute 'encode'

Однако, как было предложено сообщением об ошибке, вы можете использовать модуль codecs для достижения того же результата:

import codecs
codecs.decode('1deadbeef4', 'hex')
# Out: b'\x1d\xea\xdb\xee\xf4'
codecs.encode(b'\x1d\xea\xdb\xee\xf4', 'hex')
# Out: b'1deadbeef4'

Обратите внимание, что codecs.encode возвращает объект bytes . Чтобы получить объект str просто decode в ASCII:

codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'

Функция cmp удалена в Python 3

В Python 3 была удалена встроенная функция cmp вместе со специальным методом __cmp__ .

Из документации:

Функция cmp() следует рассматривать как ушедшую, а специальный метод __cmp__() больше не поддерживается. Используйте __lt__() для сортировки __eq__() с __hash__() и другими богатыми сравнениями по мере необходимости. (Если вам действительно нужна функция cmp() , вы можете использовать выражение (a > b) - (a < b) как эквивалент для cmp(a, b) .)

Более того, все встроенные функции, которые принимают параметр cmp теперь принимают только параметр ключевого key слова.

В functools модуле есть также полезная функция cmp_to_key(func) , которая позволяет конвертировать из cmp функции -style к key -style функции:

Преобразуйте функцию сравнения старого стиля в ключевую функцию. Используется с инструментами, которые принимают ключевые функции (такие как sorted() , min() , max() , heapq.nlargest() , heapq.nsmallest() , itertools.groupby() ). Эта функция в основном используется в качестве инструмента перехода для программ, преобразованных из Python 2, которые поддерживают использование функций сравнения.

Исключенные переменные в понимании списка

Python 2.x 2.3
x = 'hello world!'
vowels = [x for x in 'AEIOU'] 

print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'   
Python 3.x 3.0
x = 'hello world!'
vowels = [x for x in 'AEIOU']

print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'hello world!'

Как видно из примера, в Python 2 значение x просочилось: оно замаскировало hello world! и распечатал U , так как это было последним значением x когда цикл закончился.

Тем не менее, в Python 3 x печатает первоначально определенный hello world! , так как локальная переменная из понимания списка не маскирует переменные из окружающей области.

Кроме того, ни одно из выражений генератора (доступно в Python начиная с версии 2.5), а также словарные или установочные представления (которые были переданы Python 2.7 из Python 3) в Python 2.

Обратите внимание, что в обоих Python 2 и Python 3 переменные будут просачиваться в окружающую область при использовании цикла for:

x = 'hello world!'
vowels = []
for x in 'AEIOU':
    vowels.append(x)
print(x)
# Out: 'U'

карта()

map() является встроенным, который полезен для применения функции к элементам итерации. В Python 2 map возвращает список. В Python 3 map возвращает объект карты , который является генератором.

# Python 2.X
>>> map(str, [1, 2, 3, 4, 5])
['1', '2', '3', '4', '5']
>>> type(_)
>>> <class 'list'>

# Python 3.X
>>> map(str, [1, 2, 3, 4, 5])
<map object at 0x*>
>>> type(_)
<class 'map'>

# We need to apply map again because we "consumed" the previous map....
>>> map(str, [1, 2, 3, 4, 5])
>>> list(_)
['1', '2', '3', '4', '5']

В Python 2 вы можете передать None чтобы служить функцией идентификации. Это больше не работает в Python 3.

Python 2.x 2.3
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
Python 3.x 3.0
>>> list(map(None, [0, 1, 2, 3, 0, 5]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

Более того, при передаче более одного итерабельного аргумента в Python 2, накладки map короче итераций с None (аналогично itertools.izip_longest ). В Python 3 итерация останавливается после кратчайшего повторения.

В Python 2:

Python 2.x 2.3
>>> map(None, [1, 2, 3], [1, 2], [1, 2, 3, 4, 5])
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]

В Python 3:

Python 3.x 3.0
>>> list(map(lambda x, y, z: (x, y, z), [1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2)]

# to obtain the same padding as in Python 2 use zip_longest from itertools
>>> import itertools
>>> list(itertools.zip_longest([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]

Примечание . Вместо map рассмотрите использование списков, совместимых с Python 2/3. Замена map(str, [1, 2, 3, 4, 5]) :

>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']

filter (), map () и zip () возвращают итераторы вместо последовательностей

Python 2.x 2.7

В filter Python 2, встроенные функции map и zip возвращают последовательность. map и zip всегда возвращают список, а с filter тип возврата зависит от типа заданного параметра:

>>> s = filter(lambda x: x.isalpha(), 'a1b2c3')
>>> s
'abc'
>>> s = map(lambda x: x * x, [0, 1, 2])
>>> s
[0, 1, 4]
>>> s = zip([0, 1, 2], [3, 4, 5])
>>> s
[(0, 3), (1, 4), (2, 5)]
Python 3.x 3.0

В Python 3 filter , map и zip обратный итератор вместо:

>>> it = filter(lambda x: x.isalpha(), 'a1b2c3')
>>> it
<filter object at 0x00000098A55C2518>
>>> ''.join(it)
'abc'
>>> it = map(lambda x: x * x, [0, 1, 2])
>>> it
<map object at 0x000000E0763C2D30>
>>> list(it)
[0, 1, 4]
>>> it = zip([0, 1, 2], [3, 4, 5])
>>> it
<zip object at 0x000000E0763C52C8>
>>> list(it)
[(0, 3), (1, 4), (2, 5)]

Поскольку Python 2 itertools.izip эквивалентен Python 3, zip izip был удален на Python 3.

Абсолютный / относительный импорт

В Python 3 PEP 404 изменяет способ работы импорта с Python 2. Имплицитный относительный импорт больше не разрешен в пакетах и from ... import * импорт разрешен только в модульном уровне кода.

Чтобы достичь поведения Python 3 в Python 2:

  • функция абсолютного импорта может быть включена с from __future__ import absolute_import
  • явный относительный импорт поощряется вместо имплицитного относительного импорта

Для пояснения в Python 2 модуль может импортировать содержимое другого модуля, расположенного в том же каталоге, что и ниже:

import foo

Обратите внимание, что местоположение foo неоднозначно из оператора импорта. Этот тип неявного относительного импорта, таким образом, обескуражен в пользу явного относительного импорта , который выглядит следующим образом:

from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
from ...package import bar
from ...sys import path

Точка . позволяет явное объявление местоположения модуля в дереве каталогов.


Подробнее о относительном импорте

Рассмотрим некоторый пользовательский пакет, называемый shapes . Структура каталогов выглядит следующим образом:

shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py

circle.py , square.py и triangle.py все import util.py в качестве модуля. Как они будут ссылаться на модуль на одном уровне?

 from . import util # use util.PI, util.sq(x), etc

ИЛИ ЖЕ

 from .util import * #use PI, sq(x), etc to call functions

. используется для относительного импорта на уровне одного уровня.

Теперь рассмотрим альтернативный макет модуля shapes :

shapes
├── __init__.py
|
├── circle
│   ├── __init__.py
│   └── circle.py
|
├── square
│   ├── __init__.py
│   └── square.py
|
├── triangle
│   ├── __init__.py
│   ├── triangle.py
|
└── util.py

Теперь, как эти 3 класса ссылаются на util.py?

 from .. import util # use util.PI, util.sq(x), etc

ИЛИ ЖЕ

 from ..util import * # use PI, sq(x), etc to call functions

The .. используется для относительного импорта родительского уровня. Добавить еще . s с количеством уровней между родительским и дочерним.

Файловый ввод-вывод

file больше не является встроенным именем в 3.x ( open still works).

Внутренние данные ввода-вывода файлов были перенесены в стандартный библиотечный модуль io , который также является новым домом для StringIO :

import io
assert io.open is open # the builtin is an alias
buffer = io.StringIO()
buffer.write('hello, ') # returns number of characters written
buffer.write('world!\n')
buffer.getvalue() # 'hello, world!\n'

Режим файла (text vs binary) теперь определяет тип данных, полученных при чтении файла (и типа, необходимого для записи):

with open('data.txt') as f:
    first_line = next(f)
    assert type(first_line) is str
with open('data.bin', 'rb') as f:
    first_kb = f.read(1024)
    assert type(first_kb) is bytes

Кодировка для текстовых файлов по умолчанию соответствует тому, что возвращается locale.getpreferredencoding(False) . Чтобы явно указать кодировку, используйте параметр ключевого слова для encoding :

with open('old_japanese_poetry.txt', 'shift_jis') as text:
    haiku = text.read()

Функция round () для циклического размыкания и возврата

раунд ()

В Python 2, используя round() для числа, равного близкому к двум целым числам, вернется один из самых удаленных от 0. Например:

Python 2.x 2.7
round(1.5)  # Out: 2.0
round(0.5)  # Out: 1.0
round(-0.5)  # Out: -1.0
round(-1.5)  # Out: -2.0

Однако в Python 3 round() вернет четное целое число (например , округление банкиров ). Например:

Python 3.x 3.0
round(1.5)  # Out: 2
round(0.5)  # Out: 0
round(-0.5)  # Out: 0
round(-1.5)  # Out: -2

Функция round () следует стратегии от половины до четного округления , которая будет округлять половинные числа до ближайшего четного целого числа (например, round(2.5) теперь возвращает 2, а не 3.0).

Согласно ссылке в Википедии , это также известно как беспристрастное округление , округленное округление , округление статистики , голландское округление , гауссово округление или нечетное округление .

Половина и округление - это часть стандарта IEEE 754, а также режим округления по умолчанию в Microsoft .NET.

Эта стратегия округления имеет тенденцию уменьшать общую ошибку округления. Так как в среднем количество округленных чисел совпадает с количеством округленных чисел, ошибки округления сокращаются. Другие методы округления вместо этого имеют тенденцию иметь отклонение вверх или вниз в средней ошибке.


круглый () тип возврата

Функция round() возвращает тип float в Python 2.7

Python 2.x 2.7
round(4.8)
# 5.0

Начиная с Python 3.0, если второй аргумент (число цифр) опущен, он возвращает int .

Python 3.x 3.0
round(4.8)
# 5

Верно, ложно и нет

В Python 2, True , False и None есть встроенные константы. Это означает, что можно переназначить их.

Python 2.x 2.0
True, False = False, True
True   # False
False  # True

Вы не можете сделать это с помощью None с Python 2.4.

Python 2.x 2.4
None = None  # SyntaxError: cannot assign to None

В Python 3, True , False и None теперь используются ключевые слова.

Python 3.x 3.0
True, False = False, True  # SyntaxError: can't assign to keyword

None = None  # SyntaxError: can't assign to keyword

Возвращаемое значение при записи в файл-объект

В Python 2 запись непосредственно в дескриптор файла возвращает None :

Python 2.x 2.3
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>

В Python 3 запись в дескриптор возвращает количество символов, записанных при записи текста, и количество байтов, записанных при написании байтов:

Python 3.x 3.0
import sys

char_count = sys.stdout.write('hello world 🐍\n')
# Out: hello world 🐍
char_count
# Out: 14

byte_count = sys.stdout.buffer.write(b'hello world \xf0\x9f\x90\x8d\n')
# Out: hello world 🐍
byte_count
# Out: 17

long vs. int

В Python 2 любое целое число, большее, чем C ssize_t , будет преобразовано в long тип данных, обозначенный суффиксом L в литерале. Например, в 32-битной сборке Python:

Python 2.x 2.7
>>> 2**31
2147483648L
>>> type(2**31)
<type 'long'>
>>> 2**30
1073741824
>>> type(2**30)
<type 'int'>
>>> 2**31 - 1  # 2**31 is long and long - int is long
2147483647L

Однако в Python 3 был удален long тип данных; независимо от того, насколько велика целое число, это будет int .

Python 3.x 3.0
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>

Класс Boolean Value

Python 2.x 2.7

В Python 2, если вы хотите самостоятельно определить логическое значение класса, вам необходимо реализовать метод __nonzero__ в вашем классе. Значение по умолчанию равно True.

class MyClass:
    def __nonzero__(self):
        return False

my_instance = MyClass()
print bool(MyClass)       # True
print bool(my_instance)   # False
Python 3.x 3.0

В Python 3, __bool__ используется вместо __nonzero__

class MyClass:
    def __bool__(self):
        return False

my_instance = MyClass()
print(bool(MyClass))       # True
print(bool(my_instance))   # False


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow