Знаете ли вы про "магические" методы классов ˍˍgetattributeˍˍ() и ˍˍgetattrˍˍ()?
ˍˍgetattributeˍˍ вызывается всякий раз когда идёт обращение к атрибуту объекта. Например метод или какая-то переменная.
ˍˍgetattrˍˍ вызывается когда атрибут не найден.
И вот тут-то начинается самое интересное. Вы можете написать алгоритм определения динамического атрибута. Вы получаете его имя и можете решить, что вернуть учитывая запрошенное имя. Например, можете сделать запрос в базу данных или просто вернуть значение по умолчанию.
Но пост на самом деле не об этом. Дело в том, что в Python 3.7 добавили возможность определять функцию ˍˍgetattrˍˍ() в модуле с аналогичной функциональностью! (PEP562)
То есть, создав внутри модуля функцию ˍˍgetattrˍˍ() мы определяем действие в случае запроса несуществующего атрибута модуля. Ровно так же как это делаем в классах. Тем самым можно динамически определять состав модуля.
А еще можно создать функцию ˍˍdirˍˍ(), определяющую поведение для стандартной функции dir().
Пример модуля:
ˍˍgetattributeˍˍ вызывается всякий раз когда идёт обращение к атрибуту объекта. Например метод или какая-то переменная.
ˍˍgetattrˍˍ вызывается когда атрибут не найден.
И вот тут-то начинается самое интересное. Вы можете написать алгоритм определения динамического атрибута. Вы получаете его имя и можете решить, что вернуть учитывая запрошенное имя. Например, можете сделать запрос в базу данных или просто вернуть значение по умолчанию.
Но пост на самом деле не об этом. Дело в том, что в Python 3.7 добавили возможность определять функцию ˍˍgetattrˍˍ() в модуле с аналогичной функциональностью! (PEP562)
То есть, создав внутри модуля функцию ˍˍgetattrˍˍ() мы определяем действие в случае запроса несуществующего атрибута модуля. Ровно так же как это делаем в классах. Тем самым можно динамически определять состав модуля.
А еще можно создать функцию ˍˍdirˍˍ(), определяющую поведение для стандартной функции dir().
Пример модуля:
# example.pyКак использовать модуль
my_variables = {'var1': 1, "var2": 2}
def __getattr__(name):
try:
return my_variables[name]
except KeyError:
raise AttributeError
def __dir__():
return list(my_variables.keys())
>>> import example#tricks #pep
>>> print(example.var1)
1
>>> print(example.var3)
AttributeError
>>> print(dir(example)))
['var1', 'var2']
Python Enhancement Proposals (PEPs)
PEP 562 – Module __getattr__ and __dir__ | peps.python.org
It is proposed to support __getattr__ and __dir__ function defined on modules to provide basic customization of module attribute access.
Вторая по частоте future-функция, которую я использовал, это абсолютный импорт
Изменения, которые вносит эта инъекция описаны в PEP328
Покажу простой пример.
Допустим, есть такой пакет:
1. модуль в моём пакете my_package.string
2. стандартный модуль string
И вот тут вступает в дело приоритет импортов. В Python2 порядок следующий: помимо иных источников, раньше ищется модуль внутри текущего пакета, а потом в стандартных библиотеках. Таким образом мы импортнём my_package.string.
Но в Python3 это поведение изменилось. Если мы указываем просто имя пакета, то ищется именно такой модуль, игнорируя имена в текущем пакете. Если мы хотим импортнуть именно подмодуль из нашего пакета то, мы должны теперь явно это указывать.
Подробней про импорты здесь:
https://docs.python.org/3/tutorial/modules.html
#2to3 #pep #basic
from __future__ import absolute_import
Что она делает? Изменения, которые вносит эта инъекция описаны в PEP328
Покажу простой пример.
Допустим, есть такой пакет:
/my_package
/__init__.py
/main.py
/string.py
Смотрим код в my_package/main.py# main.py
import string
Простой пример готов) Вопрос в том, какой модуль импортируется в данном случае? Есть два варианта:1. модуль в моём пакете my_package.string
2. стандартный модуль string
И вот тут вступает в дело приоритет импортов. В Python2 порядок следующий: помимо иных источников, раньше ищется модуль внутри текущего пакета, а потом в стандартных библиотеках. Таким образом мы импортнём my_package.string.
Но в Python3 это поведение изменилось. Если мы указываем просто имя пакета, то ищется именно такой модуль, игнорируя имена в текущем пакете. Если мы хотим импортнуть именно подмодуль из нашего пакета то, мы должны теперь явно это указывать.
from my_package import string
или относительный импорт, но с указанием пути относительно текущего модуля mainfrom . import string
Еще одной неоднозначностью меньше 😎Подробней про импорты здесь:
https://docs.python.org/3/tutorial/modules.html
#2to3 #pep #basic
Python Enhancement Proposals (PEPs)
PEP 328 – Imports: Multi-Line and Absolute/Relative | peps.python.org
The import statement has two problems:
Ранее я уже упоминал о другой фишке из ˍˍfutureˍˍ , это оператор деления.
Например:
Если нам требуется получить дробное значение при делении двух int то приходилось форсированно один из операндов конверировать в float.
То есть теперь деление int на int даёт float если результат не целое число.
В классах теперь доступны методы __floordiv__() и __truediv__() для определения поведения с этими операторами.
Данный переход описан в PEP238.
#pep #2to3 #basic
from __future__ import division
Суть проста. Раньше сложность типа данных результата поределялась типом самого сложного операнда.Например:
int/int => int
int/float => float
В первом случае оба операнда int, значит и результат будет int. Во втором float более сложный тип, поэтому результат будет float. Если нам требуется получить дробное значение при делении двух int то приходилось форсированно один из операндов конверировать в float.
12/float(5) => float
Но с новой "философией" это не требуется. В Python3 "floor division" заменили на "true division" а старый способ теперь работает через оператор "//". >>> 3/2
1.5
>>> 3//2
1То есть теперь деление int на int даёт float если результат не целое число.
В классах теперь доступны методы __floordiv__() и __truediv__() для определения поведения с этими операторами.
Данный переход описан в PEP238.
#pep #2to3 #basic
Telegram
Python Заметки
Если вы еще не начали переходить на Python3 то сейчас самое время!
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает…
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает…