Вопрос, чтобы я понимал, стоит ли адаптировать контент под определенные системы.
Какой ОС вы в основном пользуетесь для разработки на Python?
Какой ОС вы в основном пользуетесь для разработки на Python?
Anonymous Poll
52%
Windows
13%
macOS
33%
Linux
2%
Другая
Недавно узнал, в цикле for/in после for может стоять не только имя переменной, но и любое выражение, которому можно присвоить что-либо: элемент списка/словаря или атрибут класса.
Пример – таблица чисел Фибоначчи, позволняет узнать по числу Фибоначчи его номер:
На каждой итерации
По мне, это не то, чтобы супер-полезная возможность, потому что мало людей, кто этим пользуется, и такой код сложновато осознать без привычки. А вы знали?
Пример – таблица чисел Фибоначчи, позволняет узнать по числу Фибоначчи его номер:
fib = {}
a, b = 1, 1
for fib[a] in range(1, 100):
a, b = a + b, a
print(fib[13]) # это №6 число Фиб.
print(fib[433494437]) # это №42 число Фиб.
print(fib[10]) # KeyError - 10 - это не число Фиб.На каждой итерации
fib[a] будет присвоено число из range(1, 100). Но на каждой итерации будет свое a – новое число Фибоначчи:fib[1] = 1
fib[2] = 1 + 1 = 2
fib[3] = 2 + 1 = 3По мне, это не то, чтобы супер-полезная возможность, потому что мало людей, кто этим пользуется, и такой код сложновато осознать без привычки. А вы знали?
Forwarded from PyWay – гуру Python 🐉
❌ Деструктор __del__
(часто спрашивают на собеседованиях)
Этот магический метод позволяет определить поведение экземпляра пользовательского типа при готовности интерпретатора уничтожить его.
Многие думают, что
📎 Примеры. Определим такой класс, где будем следить за вызовом его метода __del__:
❗️ Не гарантируется, что метод будет вызван для объектов, всё ещё существующих на момент выхода интерпретатора.
❗️ Если метод определён в базовом классе, то потомок должен вызывать его явно, чтобы удаление части экземпляра, реализуемой базовым классом произошло без ошибок.
❗️ Ссылка на объект может остаться при броске исключения в sys.exc_traceback (исправляется путем
❗️ До Python 3.4 сборщик мусора не мог разорвать циклические ссылки с объектами, у которых определен __del__.
❗️ Не стоит путать __del__ и __delete__, __delete__ используется напрямую крайне редко, и нужен он для объектов-дескрипторов.
(часто спрашивают на собеседованиях)
Этот магический метод позволяет определить поведение экземпляра пользовательского типа при готовности интерпретатора уничтожить его.
Многие думают, что
del x вызывает метод x.__del__. Это неправда. Python использует механизм подсчета ссылок, и del x – лишь один из способов уменьшить количество ссылок на 1.📎 Примеры. Определим такой класс, где будем следить за вызовом его метода __del__:
class Bazooka:Важные нюансы:
def __del__(self):
print('Bazooka.__del__()')
>>> b = Bazooka() # тут мы привяжем новый объект Bazooka() к имени переменной b (1 ссылка)
>>> del b # тут мы удаляем имя b, объект отвязывется, ссылок - 0, вызывается деструктор.
Bazooka.__del__()
>>> b = Bazooka()
>>> b = None # имя b не удалено, но объект будет отвязан от него и деструктор вызовется
Bazooka.__del__()
>>> b = Bazooka()
>>> b2 = b # объект привязан и к b, и к b2 (ссылок - 2)
>>> del b # удаляем первый, ссылок - 1, деструктор не вызван
>>> del b2 # удаляем второй, ссылок - 0, деструктор вызывается
Bazooka.__del__()
❗️ Не гарантируется, что метод будет вызван для объектов, всё ещё существующих на момент выхода интерпретатора.
❗️ Если метод определён в базовом классе, то потомок должен вызывать его явно, чтобы удаление части экземпляра, реализуемой базовым классом произошло без ошибок.
❗️ Ссылка на объект может остаться при броске исключения в sys.exc_traceback (исправляется путем
sys.last_traceback = None)❗️ До Python 3.4 сборщик мусора не мог разорвать циклические ссылки с объектами, у которых определен __del__.
❗️ Не стоит путать __del__ и __delete__, __delete__ используется напрямую крайне редко, и нужен он для объектов-дескрипторов.
Если нужно формировать пары из двух списков (или итераторов), пригодится встроенная функция
Из примера видно, что
Если нужно брать по максимуму до конца самого длинного из списков, то пригодится функция
Кстати, функции
Еще обе функции возвращают итератор, поэтому для наглядности я применяю функцию
zip:>>> x = [1, 2, 3, 4, 5]
>>> y = ['one', 'two', 'three']
>>> list(zip(x, y))
[(1, 'one'), (2, 'two'), (3, 'three')]Из примера видно, что
zip останавливается, как только в одном списков закончились значения. А в списке x остались бесхозные числа 4 и 5.Если нужно брать по максимуму до конца самого длинного из списков, то пригодится функция
zip_longest из стандартного модуля itertools. Если в одном из списков кончились значения, то zip_longest будет ставить на их место None, и закончит работу только тогда, когда каждый из списков будет исчерпан.>>> import itertools
>>> list(itertools.zip_longest(x, y))
[(1, 'one'), (2, 'two'), (3, 'three'), (4, None), (5, None)]
Кстати, функции
zip и zip_longest могут принимать не только два аргумента, а произвольное число входных аргументов, т.е. можно делать из трех списков тройки, из четырех – четверки и так далее.Еще обе функции возвращают итератор, поэтому для наглядности я применяю функцию
list, чтобы извлечь все значения итератора в список. Конечно, можно извлекать пары по одной в ленивом режиме функцией next:>>> it = itertools.zip_longest(x, y)
>>> next(it)
(1, 'one')Final
В современных ООП языках есть способы, как запретить создание подклассов какого-то класса. Например, в Java и Swift для этого есть ключевое слово
Мы можем добавить схожее поведение и в Python с помощью метаклассов. Напомню, что метакласс – это класс класса, т.е. тип (класс) – это экземпляр метакласса. В момент объявления подкласса
Можно оформить в виде декоратора класса, чтобы писать так:
Справедливости ради, хочу сказать, что в Python 3.8 появился декоратор
А вот зато утилита mypy, которая проверяет типы, выдаст ошибку:
В современных ООП языках есть способы, как запретить создание подклассов какого-то класса. Например, в Java и Swift для этого есть ключевое слово
final. Мы можем добавить схожее поведение и в Python с помощью метаклассов. Напомню, что метакласс – это класс класса, т.е. тип (класс) – это экземпляр метакласса. В момент объявления подкласса
B для класса A, вызывается метод new метакласса A. В этом методе мы проверим, есть ли среди базовых классов (bases) хоть один, чьим метаклассом является Final, если да – бросим исключение, сигнализирующее, что нельзя создать подкласс. Если среди базовых классов нет таких, то вызовем стандартный super().__new__. Вот так выглядит код метакласса:# метакласс наследуется от Type
class Final(type):
def __new__(mcls, name, bases, attrs):
for base in bases:
# является ли тип класса подклассом Final
if issubclass(type(base), Final):
# тогда - ошибка! нельзя содзать подкласс Final
raise TypeError(f'{name} is final!')
# иначе - обычное поведение
return super().__new__(mcls, name, bases, attrs)
Как пользоваться:
# тут отработает Final.__new__ для A - успешно
class FinalA(metaclass=Final):
...
# тут отработает Final.__new__ для B - с ошибкой!
class B(FinalA):
...Можно оформить в виде декоратора класса, чтобы писать так:
@final
class A:
...
Справедливости ради, хочу сказать, что в Python 3.8 появился декоратор
final! Но, он относится только к подсказкам типов (type hinting), и объявление подкласса от final класса не даст никаких ошибок!from typing import final
@final
class A:
...
# никаких ошибок
class B(A):
...А вот зато утилита mypy, которая проверяет типы, выдаст ошибку:
➜ 2 mypy final38.py
final38.py:8: error: Cannot inherit from final class "A"
Found 1 error in 1 file (checked 1 source file)#Задача
Новая рубрика – задачка на программирование. Сегодня для разгона – простая. Напишите функцию
Присылайте свои варианты решения в наш чатик!
Новая рубрика – задачка на программирование. Сегодня для разгона – простая. Напишите функцию
comprime(*numbers), которая принимает произвольное количество аргументов – натуральных чисел, и проверяет, являются ли все эти числа взаимно простыми, то есть не имеют общих делителей, кроме 1.>>> coprime(13, 20)
True
>>> coprime(13, 26)
False
>>> coprime(2, 3, 5, 7, 11)
TrueПрисылайте свои варианты решения в наш чатик!
Расскажите про любой шаблон проектирования на ваш выбор.
Случалось слышать такое на собеседованиях? Большинство людей в этот момент начинают рассказывать про синглтон (одиночку). Потому что он... простой? Да, вообще-то не очень. Попробуйте сходу вспомнить, как там реализовать его через метакласс. Да и часто ли приходится? Скорее всего вы пользуетесь уже готовым кодом для синглтона. Его даже называют "анти-паттерном", потому что он часто маскирует плохой дизайн кода, вызывает проблемы при тестировании и нарушает принцип единственной отвественности класса (и порождает себя, и делает какую-то работу). А еще, он может вызывать проблемы с многопоточностью или "многопроцессностью" в случае с Python. Поэтому хвастать знанием синглотона – не лучшая стратегия на собеседовании...
Ага! Стратегия! Это именно тот шаблон, который действительно подойдет для рассказа, потому что он простой и реально часто применяется на практике, даже если вы порой сами это не осознаете.
Стратегия – поведенческий шаблон, призванный для обеспечения взаимозаменяемости разных алгоритмов или вариаций алгоритма с одинаковыми интерфейсами. Стратегии – и есть эти варианты. В зависимости от условий (контекст) код выбирает подходящий алгоритм.
Реализация этого шаблона может быть не только объектная, но и функциональная. С нее и начнем:
Стратегия выбирается пользователем, а функция
В объектном варианте:
Мы обеспечили горячую заменя алгоритмов для класса
Здесь мы создаем общий интерфейс стратегий
Надеюсь, было полезно. Если хотите еще больше подробностей, то читайте 1, 2, 3.
Случалось слышать такое на собеседованиях? Большинство людей в этот момент начинают рассказывать про синглтон (одиночку). Потому что он... простой? Да, вообще-то не очень. Попробуйте сходу вспомнить, как там реализовать его через метакласс. Да и часто ли приходится? Скорее всего вы пользуетесь уже готовым кодом для синглтона. Его даже называют "анти-паттерном", потому что он часто маскирует плохой дизайн кода, вызывает проблемы при тестировании и нарушает принцип единственной отвественности класса (и порождает себя, и делает какую-то работу). А еще, он может вызывать проблемы с многопоточностью или "многопроцессностью" в случае с Python. Поэтому хвастать знанием синглотона – не лучшая стратегия на собеседовании...
Ага! Стратегия! Это именно тот шаблон, который действительно подойдет для рассказа, потому что он простой и реально часто применяется на практике, даже если вы порой сами это не осознаете.
Стратегия – поведенческий шаблон, призванный для обеспечения взаимозаменяемости разных алгоритмов или вариаций алгоритма с одинаковыми интерфейсами. Стратегии – и есть эти варианты. В зависимости от условий (контекст) код выбирает подходящий алгоритм.
Реализация этого шаблона может быть не только объектная, но и функциональная. С нее и начнем:
# стратегия печатать на экран
def console_writer(info):
print(info)
# стратегия выводить в файл
def file_writer(info):
with open('log.txt', 'a') as file:
file.write(info + '\n')
def client(writer):
writer('Hello world!')
writer('Good bye!')
# пользователь выбирает стратегию
if input('Write to file? [Y/N]') == 'Y':
client(writer=file_writer)
else:
client(writer=console_writer)Стратегия выбирается пользователем, а функция
client даже не знает, какой вариант алгоритма ей дадут. Она знает лишь то, что writer(info) – это некая функция, принимающая строку (это и есть общий интерфейс для всех стратегий). Таким образом, мы делегируем работу стратегиям, скрывая детали реализации каждой из них.В объектном варианте:
class Adder:
def do_work(self, x, y):
return x + y
class Multiplicator:
def do_work(self, x, y):
return x * y
class Calculator:
def set_strategy(self, strategy):
self.strategy = strategy
def calculate(self, x, y):
print('Result is', self.strategy.do_work(x, y))
calc = Calculator()
calc.set_strategy(Adder())
calc.calculate(10, 20)
calc.set_strategy(Multiplicator())
calc.calculate(10, 20)Мы обеспечили горячую заменя алгоритмов для класса
Calculator. Для простоты, здесь я не применял наследование (спасибо динамической природе Python), но в серьезных проектах, вам следовало бы написать что-то подобное:from abc import ABC, abstractmethod
class BaseStrategy(ABC):
@abstractmethod
def do_work(self, x, y):
pass
class Adder(BaseStrategy):
def do_work(self, x, y):
return x + y
class Multiplicator(BaseStrategy):
def do_work(self, x, y):
return x * y
class Calculator:
def set_strategy(self, strategy: BaseStrategy):
self.strategy = strategy
def calculate(self, x, y):
print('Result is', self.strategy.do_work(x, y))Здесь мы создаем общий интерфейс стратегий
BaseStrategy – как абстрактный класс ABC. Далее в каждой стратегии реализуем этот интерфейс.Надеюсь, было полезно. Если хотите еще больше подробностей, то читайте 1, 2, 3.
Как отправить Bitcoin на Python?
1. Установим библиотеку bit:
2. Загрузим приватный ключ из WIF:
3. Отправим монеты:
Очень просто и удобно! Заинтересованы? Хотите узнать больше, о том, как работать с транзакциями Bitcoin на Python? Читайте мою новую заметку!
1. Установим библиотеку bit:
pip install bit2. Загрузим приватный ключ из WIF:
from bit import Key
my_key = Key('L3Bc5K68nfDzaW4n4ag7eERKGw6WvsvTmqvirzn1wut7uL3sg76o')3. Отправим монеты:
my_key.send([
('1HB5XMLmzFVj2ALj6mfBsbаfRoD4miY36v', 0.0024, 'btc'),
], message='За кофе')Очень просто и удобно! Заинтересованы? Хотите узнать больше, о том, как работать с транзакциями Bitcoin на Python? Читайте мою новую заметку!
tirinox.ru
Отправить Bitcoin средствами Python
Чтобы создать биткоин транзакцию в наше время не нужно прилагать много усилий. Есть специальные доверенные онлайн сервисы, которые отправят вашу транзакцию в сеть бесплатно (без учета комиссии сети) и безопасно. Вам даже не нужно устанавливать ноду биткоина…
Вы удивитесь, когда увидите эти расчеты! А еще вы немного научитесь работать с данными, делать простые предсказания и строить графики на Python.
tirinox.ru
Коронавирус: предсказание на Python
Страшный вирус из Китая ежедневно наращивает свои позиции. Давайте побудем немного британскими учеными и попытаемся спрогнозировать Судный День, когда вся планета будет заражена. Нам понадобятся библиотеки: pandas – для загрузки данных matplotlib – для построения…
Лямбда или оператор?
Допустим у нас есть список напитков, где каждый элемент – кортеж (название, цена):
Хотим отсортировать их по цене, тогда нужно в функцию
Способ 2 –
Если хотите побольше узнать, как пользоваться
Какой бы способ вы предпочли?
Допустим у нас есть список напитков, где каждый элемент – кортеж (название, цена):
drinks = [
('Juice', 100),
('Beer', 200),
('Soda', 50),
('Cocktail', 400),
('Water', 20)
]
Хотим отсортировать их по цене, тогда нужно в функцию
sorted передать параметр key – функцию, которая достанет из кортежа элемент с индексом 1 – цену. Можно поступить разными способами. Способ 1 – lambda:>>> sorted(drinks, key=lambda d: d[1])
[('Water', 20), ('Soda', 50), ('Juice', 100), ('Beer', 200), ('Cocktail', 400)]Способ 2 –
operator.itemgetter:>>> from operator import itemgetter
>>> sorted(drinks, key=itemgetter(1))
[('Water', 20), ('Soda', 50), ('Juice', 100), ('Beer', 200), ('Cocktail', 400)]Если хотите побольше узнать, как пользоваться
key, то приглашаю прочитать новую заметку. Еще там есть про сортировку по нескольким признакам и про сравнение производительности разных способов задания key.Какой бы способ вы предпочли?
tirinox.ru
Ключ сортировки key
Методы sort, sorted могут принимать именованный аргумент key. Он должен быть функцией (или чем-то другим вызываемым – callable) с одним аргументом. Смысл key в том, что он вызывается ровно один раз для каждого из элементов списка (итератора и т.п.), которой…
При разборе вложенных структур из словарей и списков (например, конфигов), удобно пользоваться блоком
Ловим
Пример:
Альтернативно, вы можете сразу обновлять записи словаря (если они не найдены) методом
Может быть переписан как:
Заметьте, что повторный вызов с другим
Красивого всем кода!
try-except.Ловим
IndexError, если индекс отсутствует в списке, и KeyError, если ключ отсутствует в словаре. Однако, лучше ловить LookupError, который является предком обоих исключений:>>> issubclass(KeyError, LookupError)
True
>>> issubclass(IndexError, LookupError)
TrueПример:
config = {}
try:
admin = config['db'][0]['admins']['list'][0]
except LookupError:
admin = 'all'Альтернативно, вы можете сразу обновлять записи словаря (если они не найдены) методом
dict.setdefault(key, default). Этот метод проверяет, есть ли ключ в словаре, если его нет, то в словарь добавляется значение по умолчанию, и оно же возвращается. А если ключ был в словаре, то вернется значение по этому ключу. Поэтому такой неуклюжий код:if 'workers' not in config:
config['workers'] = 8
workers = config['workers']Может быть переписан как:
workers = config.setdefault('workers', 8) Заметьте, что повторный вызов с другим
default не поменяет уже записанное в первый раз значение:>>> d = {}
>>> d.setdefault('foo', 10)
10
>>> d.setdefault('foo', 20)
10Красивого всем кода!
Помните, недавно рассказывал про библиотеку bit? Она славится быстрыми алгоритмами для генерации ключей. Мне пришла идея, что можно воспользоваться этим, чтобы нагенерить красивых Bitcoin адресов, начинающихся или заканчивающихся с заданного слова. Например такого:
1PyWaytDDQMSsEDSpBHgfPrEUJJg8NiC9w
Так как заранее мы не можем знать, какие символы в адресе, и где они будут, то приходится делать большой перебор и проверять каждый адрес:
Вот код перебора:
Сразу предупреждаю, что слова длиннее 5 букв ищет очень долго (сам дождался только 5-символьного). Как только адрес найден, не забудьте сохранить приватный ключ, если хотите им пользоваться.
В заметке даю дополнительную информацию по теме и советы, как ускорить поиск.
1PyWaytDDQMSsEDSpBHgfPrEUJJg8NiC9w
Так как заранее мы не можем знать, какие символы в адресе, и где они будут, то приходится делать большой перебор и проверять каждый адрес:
PATTERN = 'PyWay'
def predicate(addr: str):
# первый символ – ID сети, пропустим его
return addr[1:].startswith(PATTERN)Вот код перебора:
from bit import Key
while True:
k = Key() # новый случайны ключ
if predicate(k.segwit_address):
print(f'{k.segwit_address} with WIF private key {k.to_wif()}')
breakСразу предупреждаю, что слова длиннее 5 букв ищет очень долго (сам дождался только 5-символьного). Как только адрес найден, не забудьте сохранить приватный ключ, если хотите им пользоваться.
В заметке даю дополнительную информацию по теме и советы, как ускорить поиск.
tirinox.ru
Майним красивый Bitcoin адрес на Python
Сегодня покажу, как найти (намайнить) себе красивый адрес Bitcoin кошелька. Красивый адрес, значит, что его первые несколько символов будут заданым нами словом. Я буду использовать библиотеку bit, если вы с ней еще не знакомы, прочтите эту статью. Здесь нам…
Показываем уведомления на рабочем столе
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
import os
def notify_macos(title, text):
os.system("""
osascript -e 'display notification "{}" with title "{}"'
""".format(text, title))notify_macos("Поздравляю", "Ген супер-человека найден!")На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
import subprocess as s
def notify_linux(message, title):
subprocess.Popen(['notify-send', title, message])
return
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
# pip install win10toast
from win10toast import ToastNotifier
toaster = ToastNotifier()
toaster.show_toast("Заголовок",
"Текст",
duration=5)
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
# pip install plyer
from plyer import notification
notification.notify(
title='Заголовок',
message='Сообщение',
app_icon=None, # e.g. 'C:\\icon_32x32.ico'
timeout=5, # секунд
)
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
Счетчик itertools.count
Если вам нужно считать неизвестное заранее количество шагов цикла
Можно написать более лаконично, делегировав функциональность по счету к
Если вам нужно считать неизвестное заранее количество шагов цикла
while, то в место кода вида:attempt = 1
while True:
...
attempt += 1Можно написать более лаконично, делегировав функциональность по счету к
count:from itertools import count
for attempt in count(1):
...
count(start=0, step=1) – бесконечный итератор, который выдает возрастрающую последовательность чисел. По умолчанию счет начинается с 0 с шагом 1: 0, 1, 2, 3, 4, ... Но можно и настроить: первый аргумент – начальное значение, второй – шаг. Таким образом, count(2, 3) выдаст 2, 5, 8, 11, ...О наследовании атрибутов
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Видим, что у класса Barak и Clara значение стало 30, а
Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Предок класса Clara – класс Barak. Как только мы написали
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
class Abram:
foo = 10
class Barak(Abram):
pass
class Clara(Barak):
pass
print(Abram.foo, Barak.foo, Clara.foo) # 10 10 10Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Abram.foo = 20
print(Abram.foo, Barak.foo, Clara.foo) # 20 20 20
Barak.foo = 30
print(Abram.foo, Barak.foo, Clara.foo) # 20 30 30
Abram.foo = 40
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 30Видим, что у класса Barak и Clara значение стало 30, а
Abram.foo живет своей жизнью после Barak.foo = 30 и не перестало влиять на прочие классы.Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Clara.foo? Есть ли атрибут foo у Clara? Вообще говоря, его нет, ведь мы ни разу не присваивали ничего к Clara.foo:>>> 'foo' in Clara.__dict__
False
Предок класса Clara – класс Barak. Как только мы написали
Barak.foo = 30 в классе Barak появился свой собственный foo:>>> Barak.foo = 20
>>> 'foo' in Barak.__dict__
True
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Clara.foo = 50, то у каждого из классов будет свой foo.Clara.foo = 50
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 50
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Как узнать имя переменной?
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
Тестируем:
Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
def find_names(obj):
import inspect
# currentframe - текущий контекст выполнения, т.е. эта же функция
# а f_back - фрейм код, который ее вызвал
parent_frame = inspect.currentframe().f_back
# соберем все глобальные и локальные переменные вызывающего кода
# это словарь имя переменной: ее значение
search = {**parent_frame.f_globals, **parent_frame.f_locals}
for name, v in search.items():
# если переменная ЯВЛЯЕТСЯ искомым объектом вернем ее имя
if v is obj:
yield nameТестируем:
class A: ...
x = A()
y = x
print(list(find_names(x))) # ['x', 'y']Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
a = None
print(list(find_names(a)))
# ['__doc__', '__package__', '__spec__', '__cached__', 'a']Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
def make_dict(*args):
return {next(find_names(_arg)): _arg for _arg in args}
a, b, c = 10, 20, 30
d = make_dict(a, b, c)
print(d) # {'a': 10, 'b': 20, 'c': 30}Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
NumPy-бродкастинг
Можно ли сложить NumPy-массивы совершенно разных форм?
Оказывается, да! Не будет никаких ошибок, а форма результата будет
Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
Можно ли сложить NumPy-массивы совершенно разных форм?
import numpy as np
a = np.ones((8, 1, 6, 1))
b = np.ones((7, 1, 5))
(a + b).shape # ?Оказывается, да! Не будет никаких ошибок, а форма результата будет
(8, 7, 6, 5). Интересно, как это получается? Дело в том, что здесь работает механизм бродкастинга (broadcasting), когда недостающие размеры расширяются путем "копирования" данных. А когда формы массивов выровнены, происходит простое поэлементное сложение.Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
A (4d массив): 8 x 1 x 6 x 1
B (3d массив): 7 x 1 x 5
Результат (4d массив): 8 x 7 x 6 x 5Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
tirinox.ru
NumPy-бродкастинг
Эта тема не очень освещена на русском языке, но является весьма важной по паре причин: бродкастинг упрощает жизнь, и порой он же ее усложняет. Давайте разберемся что это, и как оно работает? Бродкастинг (broadcasting) – автоматическое расширение размерности…
Чтобы сохранять и загружать данные на уровне отдельных байтов пригодится модуль struct.
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
И распаковки:
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
>>> import struct
>>> struct.pack('>hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
И распаковки:
>>> struct.unpack('>hhl', _)
(1, 2, 3)
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
tirinox.ru
Пакуем байты на Python: struct
Кто сказал, что нельзя делать низкоуровневые вещи на Python? Конечно, можно. Давайте научимся упаковывать данные из Python в байты и распаковывать их обратно. Встроенный модуль struct как раз создан для этих целей. В низкоуровневом деле важны детали, а именно…
Задачка. Имеется такой код, где мы делаем 5 записей в словарь:
d = {}
d[float('nan')] = 1
d[float('nan')] = 2
d[1.0] = 'float'
d[1] = 'int'
d[True] = 'bool'
print(len(d))🌷Всех дам поздравляю с Международным женским днем! 🌷
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]