По возможности используйте специальные (магические) методы
Специальные методы позволяют вашему коду быть более выразительным и "питонячим". Этот простой пример на скриншоте покажет вам огромную выгоду от реализации двух специальных методов:
Теперь, как и для любой стандартной коллекции вы можете вызвать функцию
Код на Github
#std
Специальные методы позволяют вашему коду быть более выразительным и "питонячим". Этот простой пример на скриншоте покажет вам огромную выгоду от реализации двух специальных методов:
__getitem__
и __len__
.Теперь, как и для любой стандартной коллекции вы можете вызвать функцию
len()
, которая вернет количество карт:>>> deck = Deck()А что, если мы хотим получить последнюю карту? Для этого у нас реализован
>>> len(deck)
36
__getitem__
:>>>deck[-1]Получить случайную карту в колоде? Не проблема:
Card(rank='Т', suit='бубны')
>>>import randomКак видим - использовать специальные методы очень даже выгодно. Как минимум, это открывает вам богатства взаимодействия с стандартной библиотекой и предоставит простой и понятный интерфейс взаимодействия с классом - нет нужды, например, писать метод для получения случайного элемента в массиве.
>>>random.choice(deck)
Card(rank='8', suit='трефы')
Код на Github
#std
Тут спрашивают, почему для определения Card использовался "именованный кортеж" -
Сами кортежи представляют собой неизменяемую структуру данных, которая поддерживает складывание в него произвольных объектов. Проще говоря, это такая коробочка в которую мы можем один раз что-то положить и потом достать по мере необходимости:
Доставать рубашку и ранг карты по индексам - не комильфо, код может быстро превратиться в кашу. А вот если бы мы могли сделать
Каждый объект, который сохранен в именованном кортеже может быть доступен через уникальный идентификатор:
- Нужно повысить читабельность кода
- Нужен иммутабельный контейнер
- Нужен контейнер которые хешируется и быстро работает
...используйте namedtuple!
#std
namedtuple
из модуля collections
, а не класс/словарь или что-то другое.Сами кортежи представляют собой неизменяемую структуру данных, которая поддерживает складывание в него произвольных объектов. Проще говоря, это такая коробочка в которую мы можем один раз что-то положить и потом достать по мере необходимости:
>>>some_tuple = ("kiriharu", 1, len)Мы же наш Card не изменяем, правда?
>>>some_tuple
('kiriharu', 1, <built-in function len>)
>>>some_tuple[1]
1
>>>some_tuple[1] = "hello"
TypeError: 'tuple' object does not support item assignment
Доставать рубашку и ранг карты по индексам - не комильфо, код может быстро превратиться в кашу. А вот если бы мы могли сделать
Card.rank
(вместо Card[0]
) - было бы отлично. Это же нам и позволяет сделать namedtuple
.Каждый объект, который сохранен в именованном кортеже может быть доступен через уникальный идентификатор:
>>>Card = collections.namedtuple('Card', ['rank', 'suit'])По итогу, если вам...
>>>card = Card(6, "пики")
>>>c.suit
'пики'
- Нужно повысить читабельность кода
- Нужен иммутабельный контейнер
- Нужен контейнер которые хешируется и быстро работает
...используйте namedtuple!
#std
Последовательность - это такая коллекция, значения в которой имеют определенный порядок. Последовательность предоставляет индексированный доступ к элементам. Докажем это на примере обычного типа данных - строки:
Последовательности бывают:
- Контейнерные - это такие последовательности, в которых можно хранить элементы разных типов. К ним относят
- Плоские - в них можно хранить только элемент 1 типа. Примерами являются
- Мутабельные - содержимое таких последовательностей можно изменять. К ним относятся
- Иммутабельные - содержимое таких последовательностей изменять нельзя. К таким относятся
#std
>>> name = "kiriharu"Символы в строке хранятся упорядоченно. Так же мы можем получить букву 'i' по индексу 1.
>>> name[1]
'i'
Последовательности бывают:
- Контейнерные - это такие последовательности, в которых можно хранить элементы разных типов. К ним относят
list
, tuple
и deque
из модуля collections
.- Плоские - в них можно хранить только элемент 1 типа. Примерами являются
str
, bytes
, bytearray
и array
из модуля array
.- Мутабельные - содержимое таких последовательностей можно изменять. К ним относятся
list
, bytearray
, array
из модуля array
, deque
из модуля collections
.- Иммутабельные - содержимое таких последовательностей изменять нельзя. К таким относятся
tuple
, str
, bytes
.#std
Множества, в отличии от последовательностей неупорядоченные, элементы в нём уникальны. Поговорим про изменяемые множества.
Допустим, я хочу сделать изменяемое множество из моих братишек-разработчиков (привет!):
Это можно использовать для того, чтобы убрать повторяющиеся элементы в списке:
#std
Допустим, я хочу сделать изменяемое множество из моих братишек-разработчиков (привет!):
>>> bros = {"cmd410", "reygasai", "mo_rjindael"}Добавим ещё одного братишку:
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai'}
>>> bros.add("hkc")Попытаемся добавить 'cmd410' ещё раз в множество:
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai', 'hkc'}
>>> bros.add("cmd410")Множество не изменилось, потому что 'cmd410' уже в нём есть. Элементы в множестве уникальны.
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai', 'hkc'}
Это можно использовать для того, чтобы убрать повторяющиеся элементы в списке:
>>> repeated = [1, 1, 2, 3, 4, 1, 2, 3, 4, 4]Множество неупорядоченно. Например, мы не можем взять нулевого по индексу братишку из него:
>>> set(repeated)
{1, 2, 3, 4}
>>> bros[0]А какие ещё операции над множествами вы знаете? Пишите в комментарии 😏!
TypeError: 'set' object is not subscriptable.
#std
Собираюсь сделать пост по сбору датасета при помощи нескольких инструментов, на примере. Как делать?
Anonymous Poll
56%
Сделай на каждый инструмент пост с кратким обзором и ролью. Код на Github, с разделением по веткам.
41%
Сделай одну большую статью, где опиши все инструменты.
3%
Свой вариант в комменты.
Использование распаковки для исключения лишних элементов
Допустим, вам необходимо распаковать N элементов из итерируемого объекта (список, кортеж), исключив при этом лишние элементы. Выражение со звёздочкой поможет это сделать.
Первая функция в примере исключит первые 2 элемента, а остальные вернет в качестве результата:
Код на GitHub
#std
Допустим, вам необходимо распаковать N элементов из итерируемого объекта (список, кортеж), исключив при этом лишние элементы. Выражение со звёздочкой поможет это сделать.
Первая функция в примере исключит первые 2 элемента, а остальные вернет в качестве результата:
>>>record = ('kiriharu', 'me@kiriha.ru', '8-800-555-35-35', '1337-1337')Второй пример показывает, что распаковку можно использовать даже в середине присваивания. Функция отбросит первый и последний элемент в списке, а остальное запишет в grades:
>>>get_phones(record)
['8-800-555-35-35', '1337-1337']
>>>grades = ('kiriharu', 1, 1, 1, 1, 'A')Выражение со звездочкой можно использовать как угодно - можно наоборот отбросить всё то, что попадает в него, а остальное вернуть. Попробуйте сами написать такую функцию :)
>>>get_grades(grades)
[1, 1, 1, 1]
Код на GitHub
#std
Несколько методов для эмуляции числовых типов
В питоне есть магические методы, которые позволяют складывать или умножать между собой объекты. Рассмотрим их.
Например, мы можем сделать класс для представления двухмерных векторов, которые могут складываться между собой создавая новый вектор или умножать вектор на скаляр.
#std
В питоне есть магические методы, которые позволяют складывать или умножать между собой объекты. Рассмотрим их.
Например, мы можем сделать класс для представления двухмерных векторов, которые могут складываться между собой создавая новый вектор или умножать вектор на скаляр.
>>> v1 = Vector2D(1, 1)
>>> v2 = Vector2D(5, 6)
>>> v1 + v2
Vector(6, 7)
>>> v1 * 3
Vector(3, 3)
GitHub#std
Коробка с питоном
Несколько методов для эмуляции числовых типов В питоне есть магические методы, которые позволяют складывать или умножать между собой объекты. Рассмотрим их. Например, мы можем сделать класс для представления двухмерных векторов, которые могут складываться…
Возвращайте NotImplemented для неподдерживаемых бинарных операций с вашим типом
В комментариях к предыдущему посту возник вопрос, что если вместо целочисленного scalar к нам придет float или какой-то другой тип?
Естественно, код в посте выше будет работать с ошибками, поэтому явно было бы выбросить исключение, но оказывается что так делать не нужно!
Оказывается, в Python есть следующий механизм: если метод представляющий бинарную операцию (
GitHub | Объяснение "на пальцах"
#std
В комментариях к предыдущему посту возник вопрос, что если вместо целочисленного scalar к нам придет float или какой-то другой тип?
Естественно, код в посте выше будет работать с ошибками, поэтому явно было бы выбросить исключение, но оказывается что так делать не нужно!
Оказывается, в Python есть следующий механизм: если метод представляющий бинарную операцию (
__add__
, __mul__
и т.д.) возвращает NotImplemented
, то Python попытается произвести отраженную операцию (для x.__mul__(1)
вызовет 1.__rmul__(x)
, например) или другие операции, в зависимости от оператора. Как только все возможные методы вернут NotImplemented
он сам возбудит исключение на месте вызова метода в вашем коде, а не в коде класса:>>> v1 = Vector2D(1, 2)Списки магических методов и рекомендации по их реализации можно найти в разделе Data model
>>> v1 * 1.1
TypeError: unsupported operand type(s) for *: 'Vector2D' and 'float'
GitHub | Объяснение "на пальцах"
#std
💫 Небольшой новостной пост
Ранее, разработчик FastAPI - Sebastian 'tiangolo' Ramirez говорил о интеграции pydantic (библиотека для валидации и де/сериализации данных на основе аннотаций типов) и sqlalchemy (одна из самых популярных ORM для взаимодействия с реляционными базами данных). И кажется, это свершилось.
На свет появился репозиторий sqlmodel. Считаю, что эта солянка с FastAPI совсем скоро станет стандартом и возможно, мы увидим что-то настолько крутое и мощное, чем в своё время стал Flask.
#новости
Ранее, разработчик FastAPI - Sebastian 'tiangolo' Ramirez говорил о интеграции pydantic (библиотека для валидации и де/сериализации данных на основе аннотаций типов) и sqlalchemy (одна из самых популярных ORM для взаимодействия с реляционными базами данных). И кажется, это свершилось.
На свет появился репозиторий sqlmodel. Считаю, что эта солянка с FastAPI совсем скоро станет стандартом и возможно, мы увидим что-то настолько крутое и мощное, чем в своё время стал Flask.
#новости
adict - небольшая библиотека, которая позволяет обращаться со словарем так, как будто мы взаимодействуем с экземпляром класса. Библиотека предоставляет доступ к ключам словаря как доступ к атрибутам объекта.
GitHub | PyPi
#библиотека
GitHub | PyPi
#библиотека
Как работает bool()?
Python может принимать любой объект в булевом контексте. Чтобы определить, является ли выражение истинным или ложным, применяется функция
По умолчанию, объект попытается вызвать метод
Резюмируя, получается такая цепочка:
Python может принимать любой объект в булевом контексте. Чтобы определить, является ли выражение истинным или ложным, применяется функция
bool(x)
, которая должна вернуть булево значение (True
или False
).По умолчанию, объект попытается вызвать метод
__bool__
, который должен вернуть булево значение. Если реализованного метода нет, то Python попытается вызвать __len__
, который должен вернуть 0 или значение больше ноля - при ноле результатом будет False
, соответственно при значении больше ноля - True
. Если ни один метод не реализован, то автоматически вернется True
.Резюмируя, получается такая цепочка:
__bool__
→ __len__
→ True
#stdНемного фактов про str() и repr()
-
-
- Если метод
А что вы можете сказать про
#std
-
repr()
вызывает метод __repr__
объекта, а метод str()
, собственно __str__
.-
repr()
вызывается интерактивной оболочкой, при попытке вывести объект.- Если метод
__str__
в объекте не определен, то вызывается __repr__
. А что вы можете сказать про
str()
и repr()
? Пишите ниже, в комментарии 👇#std
Коробка с питоном
Немного фактов про str() и repr() - repr() вызывает метод __repr__ объекта, а метод str(), собственно __str__. - repr() вызывается интерактивной оболочкой, при попытке вывести объект. - Если метод __str__ в объекте не определен, то вызывается __repr__. …
Когда использовать __str__ или __repr__?
Оба магических метода используются для получения строкового представления объекта. Но как их лучше использовать - можно увидеть на картинке.
Таким образом имеем, что
#std
Оба магических метода используются для получения строкового представления объекта. Но как их лучше использовать - можно увидеть на картинке.
Таким образом имеем, что
__repr__
должен использоваться для предоставлении информации об объекте разработчику, а __str__
должен быть читаемым и использоваться для представления информации пользователю.#std