PyWay – гуру Python 🐉
974 subscribers
22 photos
1 video
2 files
153 links
Ваш путь в глубины Python. Узнай все секреты и фишки у нас! Если хотите сотрудничать – пишите @account1242 (условия @pyway_ads)
Download Telegram
f-строки
📝 В Python существуют целых 5 стандартных способов форматировать строки (+, %, Template, str.format, f-строки).

f-строки появились в Python 3.6 и являются наиболее современным и гибким способом форматирования строк (еще этот способ называют интерполяцией строк). Они позволяют использовать значения любых переменных из окружения строки, а также даже выполнять некоторый код.

Синтаксически мы просто добавляем букву f (или F) перед открывающией кавычкой строки. Внутри строки в фигурных скобках мы можем писать почти любые выражения на Python, использовать переменные и функции; результат этого выражения будет будет подставлен на место фигурных скобок.

📎 Примеры:

>>> x, y = 5, 1/3

>>> f'x = {x} and y = {y}'
'x = 5 and y = 0.3333333333333333'

>>> f'x = {x} and y = {y:.5}; so x + y = {(x + y):.5}'
'x = 5 and y = 0.33333; so x + y = 5.3333'

>>> f'y = {round(y, 2)}'
'y = 0.33'


f-строки – это не только модно и удобно, но и быстро. Тесты показывают, что они на четверть быстрее str.format.

Я нашел для вас статью, где вы увидите больше примеров f-строк 👈
[📕 Библиотеки ] Pympler (pip install pympler)
Эта библиотка поможет вам профилировать использование памяти в программах на Python. Наоболее часто она используется для нахождения реального размера объектов в байтах.

📎 Примеры:

>>> from pympler.asizeof import asizeof
>>> asizeof(10)
32
>>> asizeof("Hello world")
64
>>> asizeof({})
240
>>> asizeof({"foo":"bar"})
352
>>> class Baz: ...
...
>>> asizeof(Baz())
168

В отличие от системной sys.getsizeof, asizeof – считает размер сложных объектов рекурсивно.

https://pythonhosted.org/Pympler/
Дизассемблирование Python (dis)

🚗 Программа Python выболняется на виртуальной машине. Во время интерпретации высокоуровненые команды превращаются в байт-код (элементарные команды для виртуальной машины). С модулем dis мы можем узнать какой именно байт-код был сгенерирован. Это часто нужно для глубокой оптимизации кода.

📎 Примеры:

>>> import dis

Можно дизассмблировать код из строки:

>>> dis.dis("print(1)")
1 0 LOAD_NAME 0 (print)
2 LOAD_CONST 0 (1)
4 CALL_FUNCTION 1
6 RETURN_VALUE


Или из функции:

>>> def foo(x, y): return x + 2 * y
...
>>> dis.dis(foo)
1 0 LOAD_FAST 0 (x)
2 LOAD_CONST 1 (2)
4 LOAD_FAST 1 (y)
6 BINARY_MULTIPLY
8 BINARY_ADD
10 RETURN_VALUE


Также туда можно передать модуль, класс, генератор и еще много что. Начиная с Python 3.7 можно указать именованный параметр depth, который включает рекурсивное дизассемблирование.

👉Документация на dis

P.S. Все вышеперечисленное относится к реализации CPython, в других реализациях, вероятно, будут отличия.
Django (/ˈdʒæŋɡoʊ/ джанго) — бесплатный и свободный фреймворк для веб-приложений, написанный на Python. Веб-фреймворк Django используется в таких крупных и известных сайтах, как Instagram, Disqus, Mozilla, The Washington Times, Pinterest, YouTube, Google и других.

Предлагаю вам небольшую подборку статей и видеоуроков по Django.

📌 Очень обширная документация по Django на русском

📌 Видео-курс по Django (Гоша Дударь)

📌 Что нового в версии Django 2.0

📌 Запуск приложения Django внутри Docker

📌 Серия статей про интернет-магазин на Django (Дикий Григорий)

📌 Видео уроки по REST API на Django

📌 Какие типичные ошибки не нужно совершать в проектах на Django

📌 Отправка Web-push из Django
Деструктор __del__
(часто спрашивают на собеседованиях)

Этот магический метод позволяет определить поведение экземпляра пользовательского типа при готовности интерпретатора уничтожить его.

Многие думают, что 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__ используется напрямую крайне редко, и нужен он для объектов-дескрипторов.
🎈🌟 Ура! Нас уже более 200 человек! 🌟🎈

Если у вас возникают вопросы, связанные с программированием на языке Python, то скорее добавляйтесь в эти классные чаты:

💬 @ru_python_beginners - для новичков

💬 @ru_python - для профессионалов

👨‍👩‍👧‍👦 Живое общение в среде единомышленников способствует вашему скорейшему профессиональному росту!
🍩 Пока вчера ехал в поезде написал для вас игру "Крестики-нолики" на Python.
Используется Flask, поэтому играть нужно в браузере.
Искусственной интеллект решил пока отключить, потому что он не может составить конкуренции человеку. Играют в одном браузере двое людей по очереди.
В коде можно настроить размер поля и длину линии для победы: строка 265 return Game(size=6, to_win=4)

👉 Скачать исходник
Так это выглядит 😁
[#новичкам]

⚡️ is - сравнивает ссылки на объекты (идентификаторы), а == сравнивает значения объектов.

📎 Пример: одно и тоже значение может храниться в разных объектах!

>>> x = 10000
>>> y = 10000
>>> x == y
True
>>> x is y
False

Интересно, почему так?

https://telegra.ph/Ne-putajte-is-i-11-25
🔡 Транспонирование матриц

Допустим есть матрица (двумерный список) размера 2x3:

>>> matrix = [[1, 2, 3], [4, 5, 6]]

Как в одну строку кода можно поменять местами строки и столбцы (научно: транспонировать матрицу)?

>>> list(zip(*matrix))
[(1, 4), (2, 5), (3, 6)]


Объяснение. Звездочка перед значением аргумента функции разворачивает список в список аргументов. Пример:

>>> print(*matrix, sep=', ')
[1, 2, 3], [4, 5, 6]


В списке matrix было 2 элемента, и вызов print стал аналогичен:

>>> print(matrix[0], matrix[1], sep=', ')
[1, 2, 3], [4, 5, 6]


Теперь zip. Она берет на вход последовательности (одну, две, больше...) и вовращает список из кортежей вида:

[ (элем0_из_первой_посл, элем0_из_второй_посл, ...),
(элем1_из_первой_посл, элем1_из_второй_посл, ...),
... ]


У нас будет:

[ (matrix[0][0] = 1, matrix[1][0] = 4),
(matrix[1][0] = 2, matrix[1][1] = 5),
(matrix[2][0] = 3, matrix[2][1] = 6) ]

Но нам нужен не список кортежей, а список списков – резонно возразите вы. Что ж! Применим к каждому элементу результата ф-цию list, она превратит его в список:

>>> list(map(list, zip(*matrix)))
[[1, 4], [2, 5], [3, 6]]


Это и есть ответ. Кстати, размер матрицы стал 3x2.
А потом добавьте, что вы бы не страдали велосипедо-строением для транспонирования матриц и применили бы numpy:

>>> matrix = numpy.array([[1, 2, 3], [4, 5, 6]])
>>> matrix.T
array([[1, 4],
[2, 5],
[3, 6]])
Singleton (Одиночка) — порождающий шаблон проектирования, гарантирующий, что в однопроцессном приложении будет единственный экземпляр некоторого класса, и предоставляющий глобальную точку доступа к этому экземпляру.

📎 Реализация синглтона через декоратор класса:

def singleton(cls):
# храним все разные синглтоны с одном словаре (класс -> экземпляр)
instances = {}
def getinstance():
# если класса нет среди ключей нашего словаря - создадим экземпляр
if cls not in instances:
instances[cls] = cls()
# вернем ссылку на него
return instances[cls]
return getinstance


Вот так мы помечаем, что класс MySingleton – синглтон:

@singleton
class MySingleton:
def __init__(self):
self.x = 10
print("__init__")


📎 Пример (проверяем единственность экземляра):

>>> x1 = MySingleton()
init
>>> x2 = MySingleton()
>>> x1 is x2
True
>>> x1.x = 100
>>> x2.x
100

init было вызвано единажды
• Обе переменные указывают на один экземпляр
• При изменении полей в одном экземпляре, они меняются и во втором.

Плохо то, что MySingleton здесь – это функция (результат работы декоратора), а не класс: вы не можете вызывать класс-методы у нее. Эта проблема решается использованием метаклассов.

# обратите внимание, метакласс наследован от type
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]

Прим
енение (Python 3):

class MySingleton(metaclass=Singleton):
def __init__(self):
self.x = 10
print("__init__")

⚠️ Не злоупотребляйте синглтонами, они осложняют тестирование кода.
Бесплатные курсы по Python

Онлайн курсы, по моему мнению, являются одним из самых эффективных способов изучения языков программирования и IT технологий. На это есть причины. Онлайн курсы – это уже давно не только набор видеолекций. Это тесная связь между теорией, практикой и общением. Вы смотрите видео, получаете небольшую порцию нового материала, затем вам сразу предлагается ответить на вопросы по этому материалу и решить задачи. Если у вас что-то не получается, вы всегда можете обсудить это с другими слушателями курса и преподавателями в чате под уроком. Лично меня всегда поражало, сколько уникальных и красивых решений для банальных задач можно узнать, просматривая варианты ответов от других людей. Кроме того тема программирования настолько обширна, что не стоит ограничивать себя одним курсом. Каждый из них содержит в себе уникальные блоки знаний: где-то матикатика, где-то веб-сервисы, где-то утилиты ОС и т. д.

1️⃣ [Stepik] Программирование на Python

2️⃣ [Stepik] Python: основы и применение

3️⃣ [Hexlet] Введение в Python

4️⃣ [Intuit] Язык программирования Python

5️⃣ [Coursera] Математика и Python для анализа данных

На Coursera вообще много курсов (бесплатных и платных, для начинающих и продвинутых).

Еще есть онлайн сервис по изучению Python, где также код заданий можно писать и выполнять прямо в браузере. http://pythontutor.ru/
Измерение времени выполнения кода

Часто на форумах и чатах возникают горячие споры о том, какой же вариант кода из нескольких выполняется быстрее. К счастью, в Python есть модуль timeit, который позволяет быстро замерить и сравнить производительность кода.

📎 Пример: определим, какой вариант кода быстрее:

>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.23387694358825684
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.20793890953063965
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.2012779712677002

Оказалось, что третий.

Если в тестируемом кусочке кода вам потребуется обратиться к переменным или модулям из глобальной зоны видимости, то удобно воспользоваться параметром globals и присвоить его результаты функции globals().

>>> import math
>>> my_const = 6.28
>>> timeit.timeit('math.cos(my_const)', globals=globals())
0.12635547306854278

Можно также передавать в timeit имя функции (без параметров):

>>> import timeit
>>> def foo(): "-".join(map(str, range(1000)))
...
>>> timeit.timeit(foo, number=1000)

📎 timeit можно вызвать из терминала:

python -m timeit -s "from math import sqrt" -n 10000 "x = sqrt(25)"

После ключа -s идет строка инициализации; она выполнится единожды. Ключ -n установит число итераций теста (рекомендуется не меньше 1000).

⚠️ Помните, что результаты тестов могут отличаться в зависимости от вашего компьютера, ОС, версии Python, фаз луны и много еще чего. Также советуем вам не увлекаться чрезмерной оптимизацией во вред читаемости кода.

Желаем вам продуктивного программирования!
🤓 Любопытство и dir

dir – это встроенная функция Python. Она позволяет нам заглянуть внутрь объекта (или модуля) и узнать, какие он имеет атрибуты (методы, поля и т.п.)
dir возвращает список строк – имен атрибутов.

dir будет очень полезна и новичкам, и профессионалам. Недавно к нам в руки попал проприетарный модуль на C++ для Python без документации. Пользуясь dir мы узнали, как называются интересующие нас методы и поля классов.

📎 dir без аргументов вернет список объектов, доступных в текущем модуле. Сюда попадут объявленные переменные, функции, классы, импортированные модули.

>>> import math
>>> x = 8
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math', 'x']


📎 dir с аргументом-модулем выведет нам перечень экспортированных модулем функций и классов.

>>> dir(math)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']


Для экземпляров классов dir пытается сначала вызвать магический метод dir у объекта; если этот метод неопределен, то она смотрит в dict. Даже если нет dict, dir выведет известные ему атрибуты типа.

А еще я тут подготовил функцию, которая рекурсивно печатает dir объекта или модуля.

def recudir(obj, max_depth=2, _d=0):
for name in dir(obj):
if not name.startswith('__'):
attr = getattr(obj, name)
print(' - ' * _d, f'\033[92m{name}\033[0m', f'[{type(attr)}]');
if _d < max_depth:
recudir(attr, max_depth, _d + 1)
🗜 Сохрание и загрузка объектов со сжатием на лету

Кто сталкивался с сериализацией на языках типа C++ знают, какая это может быть боль, когда вам нужно тщательно записать каждое поле каждого класса, соблюдая типы и думая о платформо-независимости. Конечно, есть библиотеки, но они лишь облечгают страдания.

К счастью, в Python нам доступны встроенные механизмы сериализации и десериализации, например – pickle.

Для примера возьмем такой словарик:

x = { "arr": list(range(100000)), "str": "hello" * 10000 }

"Замаринуем" его (получится объект типа bytes):
import pickle
d = pickle.dumps(x)
print(len(d)) # 418910

Восставновление:
y = pickle.loads(d)
print(y == x) # True

Если надо записать данные в файл, делается это просто:
with open('1.pkl', 'wb') as f:
pickle.dump(x, f)

И чтение:
with open('1.pkl', 'rb') as f: 
y = pickle.load(f)
print(y == x) # True

Можно применить компрессию с помощью gzip (тоже встроенный модуль Python). Все очень просто: импортируем модуль и заменяем вызовы open на gzip.open:

import gzip
with gzip.open('1.pkl.gz', 'wb') as f:
pickle.dump(x, f)

И чтение:
with gzip.open('1.pkl.gz', 'rb') as f: 
y = pickle.load(f)

Узнаем размер файла после сжатия:
import os
print(os.path.getsize('1.pkl.gz')) # 191791

В данном случае выигрыш более чем в 2 раза. Однако, на сжатие и расжатие данных требуется определенное время.

💣 Как всегда есть ложка дегтя в этой бочке меда. Pickle может содержать не только данные, но и код. Дело в том, что нельзя бездумно загружать пиклы, которые поступили к вам из ненадежных источников (например, по сети). Например:

pickle.loads(bytes("cos\nsystem\n(S'ls ~'\ntR.", 'latin-1'))

Выполнит системную команду ls ~ прямо во время загрузки! А вдруг вам по сети придет патч Бармина?

Люди пишут целые модули, для анализа pickle, например picklemagic.

💁‍♂️ Совет: используйте pickle с умом. Его удобно использовать для MVP, в научных исследованих и т.п. Остерегайтесь pickle в продакшене.
Наконец, кроме pickle для сериализации в Python есть json и менее популярный marshal, а также уйма сторонних решений.
💊 Инкапсулация и сокрытие

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

В Python этот вопрос решается на уровне соглашений. То есть программисты договариваются, что переменные, классы, атрибуты, имена которых начинаются с подчеркивания, считаются приватными и защищенными. На уровне синтаксиса не запрещено их читать или записывать из-вне.

Однако есть некоторые нюансы. Если хотите узнать о них и о том, как работают двойное и одинарное подчеркивания перед именем, то читайте эту заметку.

P. S. Некоторые статью я выношу на сайт, потому что 1) они объемные 2) в Телеграм двойное подчеркивание ломает форматирование во всем посте.
🖨 Все о print

print – одна из первый функций, с которой знакомятся новички, изучающие Python.

>>> print("Hello world!")
Hello world!


Однако, print умеет больше, чем просто печатать через пробел. Взглянем на сигнатуру:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Именованные параметры управляют поведением функции.

Во-первых, обратим внимание на параметр sep – это строка-разделитель, она будет вставлена между каждым из неименованных параметров переданным в print (по умолчанию – одиночный пробел).

>>> print(1, 2, 3, 4, sep=" and ")
1 and 2 and 3 and 4


Если передать sep='\n', то каждый параметр будет выведен с новой строки.

Во-вторых, параметр end – будет выведен после печати последнего аргумента. По умолчанию, перевод строки. Например, иногда требуется печатать в одну строку: тогда передим end='':

>>> print("Same", end=''); print("Line")
SameLine


Параметр file указывает файл или поток, в который будет выводится информация, по умолчанию, это стандартный вывод sys.stdout. Можно печатать в файл:

>>> f = open('1.txt', 'w')
>>> print("hello", file=f)
>>> f.close()


Параметр flush=True заставляет систему немедленно сбросить содержимое буфера в поток вывода. Изредка данные застревают в буфере, и этим мы их проталкиваем. Например, при end='', "1" появится только через 5 секунд сразу с "2".

>>> print('1', end=''); time.sleep(5); print('2')

Исправим это:

>>> print('1', end='', flush=True); time.sleep(5); print('2')

Наконец, не забудем, что бывает удобно печатать коллекции, передав их в print со звездочкой.

>>> arr = ["Apple", "pear", "orange"]
>>> print(*arr, sep=", ")
Apple, pear, orange
⭐️ Звезды Python

Звездочка
(этот символ называется «астериск») – один из самых многоликих операторов в Python. Судите сами:

🌟 Умножение
🌟 Возведение в степень
🌟 Размножение списков, кортежей и строк
🌟 Получение позиционных и именованных аргументов функций
🌟 Передача аргументов в функцию списком или словарем
🌟 Принуждение к явному именованию аргументов при вызове
🌟 Склеивание списков, кортежей и обновление словарей
🌟 Распаковка сложных структур и итераблов в присваивании

Я подготовил для вас объемный материал, который объясняет каждую из этих возможностей языка Python. Там много примеров. Даже опытные разработчики Python не всегда знают все эти фишки! А, может, я и сам что-то упустил?
🎄С Новым 2019 годом! 🎆 Наступающим или наступившим! 🥂

🍾 Пусть сбудутся все мечты и желания! Крепкого здоровья и благосостояния! Успехов вам в профессиональной деятельности и личной жизни! 🎁🎇

И компьютер пусть сегодня тоже отдохнет! Встречайтесь, общайтесь и веселитесь! 🎉

P.S. Сделал для вас консольную ёлочку 🎄
🐍 Реализации Python

Существует несколько реализаций языка Python. Вот основные из них:

👉 CPython – (не путать с Cython, актуальные версии 2.7.15 и 3.7.0) — наиболее распространённая, де-факто эталонная реализация языка программирования Python. CPython является интерпретатором байт-кода, написан на C. До недавнего времени разработкой руководил создатель Python Гвидо ван Россум.

👉 PyPy – актуальная верси 5.8.0 от 9 июня 2017 – Python, написанный на Python (на самом деле там все чуть сложнее). Имеет JIT-компиляцию. Совместим с версиями CPython 2.7.13 и 3.5.3. PyPy в тестах часто обходит CPython по скорости. Также в PyPy решается проблема GIL.

👉 Cython – 0.28.5 от 3 августа 2018 – не совсем Python. Код Cython преобразуется в С/С++ код для последующей компиляции и впоследствии может использоваться как расширение стандартного Python или как независимое приложение со встроенной библиотекой выполнения Cython.

👉 Stackless Python – 3.6.6 от 12 сентября 2018 – версия интерпретатора языка программирования Python, названная так из-за отказа от использования стандартного стека вызовов языка С в пользу собственного стека. Наиболее впечатляющей особенностью Stackless являются микропотоки.

👉 IronPython – 2.7.8 от 16 февраля 2018 – одна из основных реализаций языка Python, предназначенная для платформы Microsoft .NET или Mono. Полностью написан на C#, и является транслятором компилирующего типа.

👉 Micro Python – 1.9.4 от 11 мая 2018 – эффективной реализация Python 3 для встроенных систем с малым объёмом оперативной памяти. Micro Python поддерживает почти весь синтаксис Python 3.4. Умещается в 80 килобайт, базовая REPL-среда требует всего 2 килобайта ОЗУ.

👉 Jython - 2.7.0 от 29 апреля 2015 – реализация Python на Java. Говорят, что его используют, например, чтобы писать плагины для Jira.