__future__ Python

Содержание
Введение
Примеры
Type Annotations
Аннотация типа в classvariable
Без "" никак
man
Исходный код
Похожие статьи

Введение

Если вы просто изучаете Python 3 __future__ вам скорее всего не нужен.

Он используется для совместимости давно устаревшего Python 2 с современным Python 3 кодом и наоборот. Также для совместимости некоторых старых 3.X версий с новыми. В общем для работы с legacy и с возможностями, которые по каким-то причинам не могут попасть в ядро языка.

Импортировать из __future__ нужно в самом начале скрипта сразу за docstring если она есть.

python-future - это недостающий уровень совместимости между Python 2 и Python 3. Это позволяет вам использовать единую чистую кодовую базу, совместимую с Python 3.x, для поддержки как Python 2, так и Python 3 с минимальными затратами.

Он предоставляет будущие и прошлые пакеты с обратными портами и прямыми портами функций из Python 3 и 2. Он также поставляется с futurize и pasteurize, настраиваемыми скриптами на основе 2to3, которые помогут вам легко конвертировать код Py2 или Py3 для поддержки Python 2 и 3 в единой чистой кодовой базе в стиле Py3, модуль за модулем.

Известными проектами, использующими python-future для совместимости с Python 2/3, являются Mezzanine и ObsPy.

Описание модуля можно изучить здесь

Примеры

division

Рассмотрим деление в Python 3

python3

Python 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> 2 / 3 0.6666666666666666

В Python 2 деление по умолчанию целочисленное, но с помощью __future__ можно импортировать division и тогда деление заработает как в третьем Python

python2

Python 2.7.5 (default, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> 2 / 3 0 >>> from __future__ import division >>> 2 / 3 0.6666666666666666

unicode_literals

python2

>>> type("") <type 'str'> >>> from __future__ import unicode_literals >>> type("") <type 'unicode'>

Type Annotations

Про classmethod можно прочитать здесь . Если не хотите усложнять можете не писать @classmethod вообще - поведение аннотаций не изменится.

Рассмотрим класс C и classmethod make()

Если запустить скрипт ошибки не будет

# t.py class C: @classmethod def make(cls): return cls()

python3 t.py

Добавим typehint (аннотацию) в которой используем переменную.

Появится ошибка , так как переменная не определена.

# t.py class C: @classmethod def make(cls) -> C: return cls()

python3 t.py

Traceback (most recent call last): File "t.py", line 3, in <module> class C: File "t.py", line 5, in C def make(cls) -> C: NameError: name 'C' is not defined

Ошибки не будет, например, если вместо переменной C использовать в аннотации строку "C", но это не то, что нам нужно.

# t.py class C: @classmethod def make(cls) -> "C": return cls()

python3 t.py

Попробуем использовать __future__

# t.py from __future__ import annotations class C: @classmethod def make(cls) -> C: return cls()

python3 t.py

Ошибки нет, всё работает.

Планировалось , что с версии 3.10 не нужно будет писать from __future__ import annotations. Но я уже давно пользуюсь версией 3.12 и по-прежнему приходится так писать.

В PEP 563 можно ознакомиться с мнением сообщества о перспективах аннотаций типов и связанных с этим соображений.

Аннотация типа в classvariable

Если использовать переменную класса как коллекцию экземпляров этого класса - при создании аннотации типа возникнет необходимость в annotations из __future__

Рассмотрим пример из статьи про super()

class Rectangle: all_rectangles: list[Rectangle] = [] def __init__(self, length: float, width: float) -> None: self.length = length self.width = width Rectangle.all_rectangles.append(self)

Traceback (most recent call last): File "C:\Users\andrei\shapes.py", line 1, in <module> class Rectangle: File "C:\Users\andrei\shapes.py", line 2, in Rectangle all_rectangles: list[Rectangle] = [] ^^^^^^^^^ NameError: name 'Rectangle' is not defined

Можно сделать Rectangle строкой, но мне не нравится этот способ, поэтому импортируем annotations

from __future__ import annotations class Rectangle: all_rectangles: list[Rectangle] = [] def __init__(self, length: float, width: float) -> None: self.length = length self.width = width Rectangle.all_rectangles.append(self) def area(self) -> float: return self.length * self.width r1 = Rectangle(3, 2) print(r1.area()) print(f"Rectangle count: {len(Rectangle.all_rectangles)}")

6
Rectangle count: 1

Без "" никак

Рассмотрим ситуацию, которая мне не нравится, но пока не понимаю можно ли её обойти:

Случай когда импорт annotations не избавляет от необходимости указывать тип в виде строки.

Если создать отдельный класс под составную аннотацию типа - допустим список, но только объектов кастомного класса, начинается путаница с порядком объявления, и только помещение типа в кавычки спасает от неразберихи

from __future__ import annotations class ContactList(list["Contact"]): pass class Contact: all_contacts = ContactList() def __init__(self, name: str, email: str) -> None: self.name = name self.email = email Contact.all_contacts.append(self) c1 = Contact("Malaga Guide", "spain@heihei.ru") c2 = Contact("Python Teacher", "mentors@devhops.ru") print(Contact.all_contacts)

Если бы отдельного класса ContactList не было, можно было бы написать

all_contacts: list[Contact] = []

Но так как используется all_contacts = ContactList() приходится в аннотации типа брать Contact в кавычки

class ContactList(list["Contact"]): …

Если этого не сделать получим NameError

Traceback (most recent call last): File "C:\Users\Andrei\future_and_string.py", line 4, in <module> class ContactList(list[Contact]): ^^^^^^^ NameError: name 'Contact' is not defined

Если поменять классы местами получим

Traceback (most recent call last): File "C:\Users\Andre\future_and_string.py", line 4, in <module> class Contact: File "C:\Users\Andrei\future_and_string.py", line 5, in Contact all_contacts = ContactList() ^^^^^^^^^^^ NameError: name 'ContactList' is not defined

Если вы знаете как обойти это не используя кавычки - пишите в чат

Может быть между написанием этой статьи и моментом, когда вы это читаете что-то изменилось в Python.

РЕКЛАМА от Яндекса. Может быть недоступна в вашем регионе

Конец рекламы. Если там пусто считайте это рекламой моей телеги

barry_as_FLUFL

python2

Python 2.7.5 (default, Jun 28 2022, 15:30:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> >>> 0 <> 0 False >>> 0 <> 1 True

В Python 3 такой оператор не предусмотрен

python3

Python 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> >>> >>> 0 <> 0 File "<stdin>", line 1 0 <> 0 ^ SyntaxError: invalid syntax >>> from __future__ import barry_as_FLUFL >>> >>> 0 <> 0 False >>> 0 <> 1 True

man

python -m pydoc __future__

Help on module __future__: NAME __future__ - Record of phased-in incompatible language changes. MODULE REFERENCE https://docs.python.org/3.8/library/__future__ The following documentation is automatically generated from the Python source files. It may be incomplete, incorrect or include features that are considered implementation detail and may vary between Python implementations. When in doubt, consult the module reference at the location listed above. DESCRIPTION Each line is of the form: FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease "," CompilerFlag ")" where, normally, OptionalRelease < MandatoryRelease, and both are 5-tuples of the same form as sys.version_info: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int PY_MICRO_VERSION, # the 0; an int PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string PY_RELEASE_SERIAL # the 3; an int ) OptionalRelease records the first release in which from __future__ import FeatureName was accepted. In the case of MandatoryReleases that have not yet occurred, MandatoryRelease predicts the release in which the feature will become part of the language. Else MandatoryRelease records when the feature became part of the language; in releases at or after that, modules no longer need from __future__ import FeatureName to use the feature in question, but may continue to use such imports. MandatoryRelease may also be None, meaning that a planned feature got dropped. Instances of class _Feature have two corresponding methods, .getOptionalRelease() and .getMandatoryRelease(). CompilerFlag is the (bitfield) flag that should be passed in the fourth argument to the builtin function compile() to enable the feature in dynamically compiled code. This flag is stored in the .compiler_flag attribute on _Future instances. These values must match the appropriate #defines of CO_xxx flags in Include/compile.h. No feature line is ever to be deleted from this file. DATA __all__ = ['all_feature_names', 'nested_scopes', 'generators', 'divisi… absolute_import = _Feature((2, 5, 0, 'alpha', 1), (3, 0, 0, 'alpha', 0… all_feature_names = ['nested_scopes', 'generators', 'division', 'absol… annotations = _Feature((3, 7, 0, 'beta', 1), (3, 10, 0, 'alpha', 0), 1… barry_as_FLUFL = _Feature((3, 1, 0, 'alpha', 2), (4, 0, 0, 'alpha', 0)… division = _Feature((2, 2, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 1310… generator_stop = _Feature((3, 5, 0, 'beta', 1), (3, 7, 0, 'alpha', 0),… generators = _Feature((2, 2, 0, 'alpha', 1), (2, 3, 0, 'final', 0), 0) nested_scopes = _Feature((2, 1, 0, 'beta', 1), (2, 2, 0, 'alpha', 0), … print_function = _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0)… unicode_literals = _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', … with_statement = _Feature((2, 5, 0, 'alpha', 1), (2, 6, 0, 'alpha', 0)… FILE /usr/lib/python3.8/__future__.py

Исходный код

Изучить код модуля можно выполнив

vi /usr/lib/python3.8/__future__.py

"""Record of phased-in incompatible language changes. Each line is of the form: FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease "," CompilerFlag ")" where, normally, OptionalRelease < MandatoryRelease, and both are 5-tuples of the same form as sys.version_info: (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int PY_MINOR_VERSION, # the 1; an int PY_MICRO_VERSION, # the 0; an int PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string PY_RELEASE_SERIAL # the 3; an int ) OptionalRelease records the first release in which from __future__ import FeatureName was accepted. In the case of MandatoryReleases that have not yet occurred, MandatoryRelease predicts the release in which the feature will become part of the language. Else MandatoryRelease records when the feature became part of the language; in releases at or after that, modules no longer need from __future__ import FeatureName to use the feature in question, but may continue to use such imports. MandatoryRelease may also be None, meaning that a planned feature got dropped. Instances of class _Feature have two corresponding methods, .getOptionalRelease() and .getMandatoryRelease(). CompilerFlag is the (bitfield) flag that should be passed in the fourth argument to the builtin function compile() to enable the feature in dynamically compiled code. This flag is stored in the .compiler_flag attribute on _Future instances. These values must match the appropriate #defines of CO_xxx flags in Include/compile.h. No feature line is ever to be deleted from this file. """ all_feature_names = [ "nested_scopes", "generators", "division", "absolute_import", "with_statement", "print_function", "unicode_literals", "barry_as_FLUFL", "generator_stop", "annotations", ] __all__ = ["all_feature_names"] + all_feature_names # The CO_xxx symbols are defined here under the same names defined in # code.h and used by compile.h, so that an editor search will find them here. # However, they're not exported in __all__, because they don't really belong to # this module. CO_NESTED = 0x0010 # nested_scopes CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000) CO_FUTURE_DIVISION = 0x20000 # division CO_FUTURE_ABSOLUTE_IMPORT = 0x40000 # perform absolute imports by default CO_FUTURE_WITH_STATEMENT = 0x80000 # with statement CO_FUTURE_PRINT_FUNCTION = 0x100000 # print function CO_FUTURE_UNICODE_LITERALS = 0x200000 # unicode string literals CO_FUTURE_BARRY_AS_BDFL = 0x400000 CO_FUTURE_GENERATOR_STOP = 0x800000 # StopIteration becomes RuntimeError in generators CO_FUTURE_ANNOTATIONS = 0x1000000 # annotations become strings at runtime class _Feature: def __init__(self, optionalRelease, mandatoryRelease, compiler_flag): self.optional = optionalRelease self.mandatory = mandatoryRelease self.compiler_flag = compiler_flag def getOptionalRelease(self): """Return first release in which this feature was recognized. This is a 5-tuple, of the same form as sys.version_info. """ return self.optional def getMandatoryRelease(self): """Return release in which this feature will become mandatory. This is a 5-tuple, of the same form as sys.version_info, or, if the feature was dropped, is None. """ return self.mandatory def __repr__(self): return "_Feature" + repr((self.optional, self.mandatory, self.compiler_flag)) nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "alpha", 0), CO_NESTED) generators = _Feature((2, 2, 0, "alpha", 1), (2, 3, 0, "final", 0), CO_GENERATOR_ALLOWED) division = _Feature((2, 2, 0, "alpha", 2), (3, 0, 0, "alpha", 0), CO_FUTURE_DIVISION) absolute_import = _Feature((2, 5, 0, "alpha", 1), (3, 0, 0, "alpha", 0), CO_FUTURE_ABSOLUTE_IMPORT) with_statement = _Feature((2, 5, 0, "alpha", 1), (2, 6, 0, "alpha", 0), CO_FUTURE_WITH_STATEMENT) print_function = _Feature((2, 6, 0, "alpha", 2), (3, 0, 0, "alpha", 0), CO_FUTURE_PRINT_FUNCTION) unicode_literals = _Feature((2, 6, 0, "alpha", 2), (3, 0, 0, "alpha", 0), CO_FUTURE_UNICODE_LITERALS) barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2), (4, 0, 0, "alpha", 0), CO_FUTURE_BARRY_AS_BDFL) generator_stop = _Feature((3, 5, 0, "beta", 1), (3, 7, 0, "alpha", 0), CO_FUTURE_GENERATOR_STOP) annotations = _Feature((3, 7, 0, "beta", 1), (3, 10, 0, "alpha", 0), CO_FUTURE_ANNOTATIONS)

Похожие статьи
future
Type Hints
Списки []
list comprehension: Абстракция списка
Python
if, elif, else
Циклы
Абстракция множеств и словарей

Поиск по сайту

Подпишитесь на Telegram канал @aofeed чтобы следить за выходом новых статей и обновлением старых

Перейти на канал

@aofeed

Задать вопрос в Телеграм-группе

@aofeedchat

Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящую по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: