Python Language
Несовместимость, перемещающаяся с Python 2 на Python 3
Поиск…
Вступление
В отличие от большинства языков, 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
- это утверждение:
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()
- это функция с аргументами ключевого слова для общего использования:
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 есть два варианта строки: те из байтов с типом ( 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 тип 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)
Также возможно префикс строковых литералов с префиксом 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é'
Хотя тип bytes
существует как в Python 2, так и в 3, тип unicode
существует только в Python 2. Чтобы использовать неявные строки Unicode Python 3 в Python 2, добавьте следующее в начало файла кода:
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
Другое важное различие заключается в том, что индексирование байтов в 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 это просто:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
В Python 3.x пример становится немного сложнее:
>>> 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
:
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
:
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
Преимущество использования специального типа последовательности вместо списка состоит в том, что интерпретатору не нужно выделять память для списка и заполнять его:
# 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
:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Совместимость
Чтобы поддерживать совместимость между версиями Python 2.x и Python 3.x, вы можете использовать builtins
модуль из future
внешнего пакета для достижения как совместимости с переходом, так и обратной совместимости :
#forward-compatible
from builtins import range
for i in range(10**8):
pass
#backward-compatible
from past.builtins import xrange
for i in xrange(10**8):
pass
range
в future
библиотеке поддерживает нарезку, index
и count
во всех версиях Python, как и встроенный метод на Python 3.2+.
Распаковка итераций
В 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.5 . Теперь в одном выражении можно иметь несколько операций распаковки:
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
Также можно распаковать итерируемый аргумент функции:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 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 удаляет распаковку в функции. Следовательно, в 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
строк:
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 также добавляет цепочку исключений , в которой вы можете указать, что причиной этого исключения является другое исключение. Например
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; исходное исключение и его трассировка будут потеряны, если в исключающем блоке будет создано другое исключение. Следующий код может использоваться для совместимости:
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")
Чтобы «забыть» ранее заброшенное исключение, используйте 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
на самом итераторе:
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
функции с итератором в качестве аргумента.
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
Этот код переносится в разных версиях от версии 2.6 до последних версий.
Сравнение различных типов
Можно сравнить объекты разных типов. Результаты являются произвольными, но непротиворечивыми. Они упорядочены так, что 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)]
Исключение возникает при сравнении разных (нечисловых) типов:
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
,
user_input = raw_input()
В то время как в Python 3 пользовательский ввод принимается с использованием функции input
.
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. Таким образом, вы можете изменить утверждения
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
к формам
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
является полностью необязательным:
class X: pass
class Y(object): pass
Оба этих класса теперь содержат object
в своем mro
(порядок разрешения метода):
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
В классах Python 2.x
по умолчанию используются классы старого стиля; они не неявно наследуют от object
. Это заставляет семантику классов различаться в зависимости от того, если мы явно добавляем object
в качестве базового class
:
class X: pass
class Y(object): pass
В этом случае, если мы попытаемся напечатать __mro__
of Y
, __mro__
аналогичный вывод, как в случае с Python 3.x
:
>>> 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)
.
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
>>> 1 <> 2
File "<stdin>", line 1
1 <> 2
^
SyntaxError: invalid syntax
>>> `foo`
File "<stdin>", line 1
`foo`
^
SyntaxError: invalid syntax
кодирование / декодирование в hex больше недоступно
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
"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, которые поддерживают использование функций сравнения.
Исключенные переменные в понимании списка
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'
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.
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
>>> 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:
>>> 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:
>>> 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 () возвращают итераторы вместо последовательностей
В 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 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. Например:
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()
вернет четное целое число (например , округление банкиров ). Например:
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
round(4.8)
# 5.0
Начиная с Python 3.0, если второй аргумент (число цифр) опущен, он возвращает int
.
round(4.8)
# 5
Верно, ложно и нет
В Python 2, True
, False
и None
есть встроенные константы. Это означает, что можно переназначить их.
True, False = False, True
True # False
False # True
Вы не можете сделать это с помощью None
с Python 2.4.
None = None # SyntaxError: cannot assign to None
В Python 3, True
, False
и None
теперь используются ключевые слова.
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
Возвращаемое значение при записи в файл-объект
В Python 2 запись непосредственно в дескриптор файла возвращает None
:
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
В Python 3 запись в дескриптор возвращает количество символов, записанных при записи текста, и количество байтов, записанных при написании байтов:
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:
>>> 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
.
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
Класс Boolean Value
В 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, __bool__
используется вместо __nonzero__
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False