Python Заметки
2.28K subscribers
60 photos
2 videos
2 files
215 links
Интересные заметки и обучающие материалы по Python

Контакт: @paulwinex

⚠️ Рекламу на канале не делаю!⚠️

Хештеги для поиска:
#tricks
#libs
#pep
#basic
#regex
#qt
#django
#2to3
#source
#offtop
Download Telegram
Знаете ли вы про "магические" методы классов ˍˍgetattributeˍˍ() и ˍˍgetattrˍˍ()?

ˍˍ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
>>> print(example.var1)
1
>>> print(example.var3)
AttributeError

>>> print(dir(example)))
['var1', 'var2']

#tricks #pep
Вторая по частоте future-функция, которую я использовал, это абсолютный импорт

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

или относительный импорт, но с указанием пути относительно текущего модуля main

from . import string

Еще одной неоднозначностью меньше 😎

Подробней про импорты здесь:
https://docs.python.org/3/tutorial/modules.html

#2to3 #pep #basic
Ранее я уже упоминал о другой фишке из ˍˍfutureˍˍ , это оператор деления.

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