Size: a a a

PyWay – гуру Python 🐉

2019 January 03
PyWay – гуру Python 🐉
🐍 Реализации 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.
источник
2019 January 04
PyWay – гуру Python 🐉
🧐 А вы знали?

Если функция принимает единственный аргумент, то можно в нее передать генераторное выражение без скобок:

>>> sum(x * x for x in range(5))
30

Тоже самое, что и:

>>> sum((x * x for x in range(5)))
30


Но вне вызова функции генератор недопустимо использовать без скобок – это синтаксическая ошибка:

>>> g = x * x for x in range(5)
 File "<stdin>", line 1
   g = x * x for x in range(5)
               ^
SyntaxError: invalid syntax
источник
2019 January 06
PyWay – гуру Python 🐉
🎎 Операции над множествами

Множество – неупорядоченная коллекция из уникальных (неповторяющихся) элементов.

Для множеств определены выразительные математические операторы.
Рассмотрим два множества:

>>> A = {1, 2, 3, 4, 5}
>>> B = {4, 5, 6, 7, 8}


Их объединение:

>>> A | B
{1, 2, 3, 4, 5, 6, 7, 8}

Пересечение:

>>> A & B
{4, 5}

Обычная разность множеств:

>>> A - B
{1, 2, 3}


Симмертичная разность:

>>> A ^ B
{1, 2, 3, 6, 7, 8}

Проверка включения подмножества в множество:

>>> {1, 2, 5} < A
True
>>> B > {6, 7}
True


Хотите знать больше о множествах? Тогда читайте новую статью. Там есть картинки! А еще там рассказывается немного о замороженных множествах.
источник
2019 January 13
PyWay – гуру Python 🐉
В чем разница между итератором и генератором
(вопрос с собеседований)

Итератор – более общая концепция, чем генератор.

Итератор – это интерфейс доступа к элементам коллекций и потоков данных. Он требует реализации единственного метода – «дай мне следующий элемент».

~~~~~~~

Генератор – это итератор, но не наоборот. Не любой итератор является генератором.

Есть два способа получить генератор:
1. Генераторное выражение
2. Генераторные функции (функции c yield)

Генератор в отличие от простого итератора позволяет передавать данные внутрь себя, а также возбуждать внутри себя исключения с помощью специальных методов.

Более подробное описание и примеры кода ищите в моей новой заметке.
источник
2019 January 16
PyWay – гуру Python 🐉
⛓ Цепочки сравнений

Распространенная ситуация: проверка того, что переменная находится в заданных пределах. Можно было бы использовать логический оператор and:

 if x >= 5 and x < 20:

Однако Python предоставляет нам синтаксическое удобство, которое выглядит более "математичным". Такая запись и короче, и понятнее:

 if 5 <= x < 20:

В качестве операторов сравнения в цепочках могут быть любые из списка в любых сочетаниях:

 "<", "==", ">=", "<=", "!=", "is" ["not"], ["not"] "in"

Т.е. запись вида a < b > c вполне законна, хоть и трудна для понимания.

Формально, если мы имеем N операций OP1...OPN и N + 1 выражений (a, b ... y, z), то запись вида:
 OP1 b OP2 c ... y OPN z 

Это эквивалентно записи:
 OP1 b and b OP2 c and ... and y OPN z

📎 Примеры:
x = 5
print(1 < x < 10)
print(x < 10 < x*10 < 100)
print(10 > x <= 9)
print(5 == x > 4)

a, b, c, d, e, f = 0, 5, 12, 0, 15, 15
print(a <= b < c > d is not e is f)
источник
2019 January 19
PyWay – гуру Python 🐉
​​📈 Построение графиков и диаграмм

Одно из самых распространённых применений Python – научные исследования. Диапазон научных дисциплин, в которых может быть полезен Python просто огромен: машинное обучение, статистика, биоинформатика, финансы, социальные науки, моделирование физических процессов и так далее. Одним из мощнейших средств научных средств – являются графики.

Де-факто стандартом в мире построения графиков на Python является библиотека Matplotlib. Она имеет обширный функционал и не очень тривиальный интерфейс.

А что бы во всем этом разобраться, можно изучить этот замечательный учебник на русском языке. Автор: Шабанов П.А.
источник
2019 January 22
PyWay – гуру Python 🐉
[📕 Библиотеки ] urllib, urllib2, urllib3, ... ?

Оказывается, что существует несколько библиотек для выполения HTTP запросов на Python. Это может запутать тех, кто впервые начинает работать с этими функциями. Давайте разберемся.

Жил-был встроенный модуль urllib в Python 2.x. Вышел Python 3 и эту библиотеку разбили на модули urllib.request, urllib.error, urllib.parse. А для ветки Python 2 ее переимевали в urllib2. При этом urllib (без цифр) есть и Python 3, и в Python 2. Итого:

👉 urllib - встроенная библиотека для открытия URL ссылок (преимущественно HTTP запросов).
а) Python 2: не используйте, используйте urllib2 (До версии 2.7.9 urlopen в urllib не проверяет HTTPS сертификаты!)
б) Python 3: можно пользоваться, но неудобная.

👉 urllib2 - это не вторая версия urllib, а версия urllib для Python 2!

👉 urllib3 - это не третья версия urllib, это вообще строронняя библиотека (pip install urllib3). Отличается потокобезопасностью, пулами соединений, поддержкой сжатия, прокси и прочими фишками. Сделана поверх socket.

👉 httplib - это голый HTTP клиент для Python 2. Переименована в http.client в Python 3. Более "низкоуровневый" модуль, чем urllib. Например, если urllib умеет обрабатывать редиректы, то при работе с httplib вам придется реализовать эту логику самостоятельно.

👉 httplib2 - это сторонний HTTP клиент (pip install httplib2). Что еще один?!

А рекомендуется (даже в официальной документации Python) использовать библиотеку requests:

👉 requests - это сторонняя библотека для выполнения HTTP запросов (pip install requests). По общему мнению она обладает наиболее простым и элегантным интерфейсом. При этом она наделена мощным набором возможностей. Кстати, requests сделана поверх urllib3. Документация.
источник
2019 January 29
PyWay – гуру Python 🐉
​​🗃 Известно множество алгоритмов сортировки. Мы припомним сортировку пузырьком, вставками, слияниями, быструю сортировку, сортировку выбором и другие.

Однако, если нас спросят про сортировку, которая гарантированно выполняется за линейное время?
Есть такая! Это, конечно, же поразрядная сортировка (radix sort). Она стара как наш IT мир (1887 год), поразрядной сортировкой сортировали еще перфокарты со времен первых компьютеров.

Если есть линейная сортировка, то зачем нам все остальные алгоритмы?

Дело в том, что поразрядная сортировка предназначена для данных, которые можно поделить на "разряды", содержащие сравнимые значения. Исходно алгоритм предназначен для сортировки целых чисел, записанных цифрами. Эту сортировку также несложно приспособить для строк (т.к. каждый символ строки можно представить числом).

Смысл поразрядной сортировки таков: сначала мы раскладываем все данные в кучки по одному крайнему разряду, затем группируем их обратно в большой массив. Затем раскладываем в кучки по следующему разряду (не нарушая порядок по предыдущему разряду, конечно) и снова группируем. И так до конца.

Поразрядная сортировка выполняется за время O(nk) и требует O(k) дополнительной памяти, где n - число элементов, k - число разрядов.

Конечно же, мы прилагаем вариант реализации поразрядной сортировки и скрипт для тестирования ее производительности.
источник
2019 February 07
PyWay – гуру Python 🐉
[📕 #Библиотеки ] boltons
#Библиотеки ] boltons
Это обширная коллекция утилитарных классов и функций, которых, по мнению авторов, не хватает в стандартной библиотеке Python.
Вы удивитесь, когда найдете столько знакомых вещей, которые вы пишите сами каждый раз в вашем файлике "utils.py"utils.py".

Модуль содержит дополнительные структуры данных, такие как OrderedMultiDict, IndexedSet, BList, namedlist и Table.
Также там есть целая куча функций для работы со строками, например: camel2under, html2text, bytes2human, args2sh и прочие.
Шикарный набор функций для работы с итераторами: chunked, pairwise, windowed, unique и другие.
Еще есть средства для кэширования, для расширенной работы с файлами, сокетами. Кое-что из математики и статистики.
Некоторые из функций дополняют или улучшают поведение их аналогов из стандартной библиотеки.

Установка:
pip install boltons

Исходный код:
https://github.com/mahmoud/boltons

Документация:
https://boltons.readthedocs.io/en/latest/index.html
источник
2019 February 09
PyWay – гуру Python 🐉
​​🔢 Приоритет операций  #новичкам  

В языках программирования и в математике вычисление выражений производится в определенном порядке. Порядок этот задается приоритетом операторов и скобками. Со школы мы знаем, что умножение имеет более высокий приоритет, чем сложение, поэтому в пределах одних скобок сначала будет выполнено умножение, а затем только сложение:

 2 * 2 + 2 = 6

Посмотрите таблицу приоритета операций в языке Python. Сверху таблицы самые приоритетные операции, снизу – операции с низким приоритетом. Как видно, скобки самые главные. Скобки решают все.

Если в одном выражении идут операторы одинакового приоритета, то вычисления выполняются слева направо. Исключение составляет оператор **. Он право-ассоциативный. Т.е. в цепочке из двух таких операторов сначала выполнится правый, а потом левый:

 >>> 3 ** 4 ** 2
43046721
>>> 3 ** (4 ** 2)
43046721
>>> (3 ** 4) ** 2
6561

Приоритет not больше, чем у and. Приоритет and больше, чем у or.

 a or b and c   ===   (not a) or (b and c)

Правила хорошего тона: не составляйте очень сложных выражений и логических выражений; разбивайте их на части. Даже если вы прекрасно знаете приоритеты операций, то программист, читающий ваш код после вас, может знать их плохо; поэтому НЕ пренебрегайте скобками.
источник
2019 February 16
PyWay – гуру Python 🐉
@ Оператор умножения матриц

А вы знали, что помимо обыденных операторов +, -, *, / и прочих, есть еще операторы @ и @=? Нет, это не про декораторы. Задуманы эти операторы были для умножения матриц и появились в версии Python 3.5. Однако встроенного типа "матрица" в Python нет, и ни один из встроенных типов эти операторы не реализует. Поэтому, быть может, о нем и не рассказывают на курсах.

Однако оператор @ рекомендуется для умножения матриц в библиотеке numpy:

>>> import numpy as np
>>> a = np.array( [ [1, 2], [-2, 3] ] )
>>> b = np.array( [ [3, 0], [1, -3] ] )
>>> a @ b
array([[ 5, -6],
      [-3, -9]])
>>> np.matmul(a, b)
array([[ 5, -6],
      [-3, -9]])

⚠️ Обратите внимание, что это именно np.matmul, а не np.dot!

Также вы можете написать реализацию операторов @ и @= для своих классов. Для этого вам понадобятся магические методы matmul, imatmul, rmatmul с подчеркиваниями. Telegram опять рубит двойные подчеркивания, поэтому смотрите пример по ссылке:

Вот пример.
источник
2019 February 17
PyWay – гуру Python 🐉
​​🔐 Храним секреты правильно

Наверное, каждый когда-то писал в своем коде:

DB_HOST = 'localhost'
DB_USER = 'root'
DB_PASSWORD = 'l33thAxor666'

Это небезопасно и неудобно. Можно утащить доступы прямо из кода с машины или из репозитория. Можно хранить секретные данные в отдельных файлах конфигурации, передавать через переменные среды, но зачем это, если у современных ОС уже есть встроенные защищенные хранилища.

Для хранения секретов и паролей придет на помощь библиотека keyring.

В зависимости от ОС и среды она использует:
• macOS Keychain
• Freedesktop Secret Service
• KDE4 & KDE5 KWallet
• Windows Credential Locker
• и другие бэкенды...

Мы храним в скрипте или конфиге только название системы и логин (можете использовать произвольные):

>>> import keyring
>>> keyring.set_password("my_system", "my_username", "password")
>>> keyring.get_password("my_system", "my_username")
'password'


Другие пользователи системы не смогут прочитать эти данные. Но от вашего имени можно получить доступ к ним даже из терминала:

$ keyring set my_system my_username
Password for 'my_username' in 'my_system':
$ keyring get my_system my_username
qwerty


Считать пароль безопасно с клавиатуры можно с помощью модуля getpass (он строен в Python). Вводимые символы не будут видны на экране:

>>> import getpass
>>> password = getpass.getpass(prompt="Enter super password:")
Enter super password:
>>> password
'qwerty'
источник
2019 February 18
PyWay – гуру Python 🐉
👀 global и nonlocal

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

def foo():
   print('x is', x)
x = 5
foo()  # напечает x is 5

Однако если в функции есть присваиваниие x после использования переменной x, то возникнет ошибка:

def foo():
   print('x is', x)
   x = 10
x = 5
foo()  # UnboundLocalError: local variable 'x' referenced before assignment

Обатите внимание, что присваивание бывает в следующих ситуациях:
x = ...
x += ..., x -= ... и т.п.
for x in ...:
with ... as x:

Чтобы избежать ошибки, мы должны явно указать перед использованием x, что она относится к глобальной области видимости:

def foo():
   global x  # <-- тут
   print('x is', x)
   x = 10
   print('x is now', x)
x = 5
foo()  # ошибок не будет


Подобная проблема возникает и для вложенных функций, когда во внутренней функции мы хотим поймать в замыкание переменную из внушней функции, чтобы далее присвоить ей другое значение. Вот пример – функция, создающее увеличивающийся на 1 счечтик:

def make_inc():  # внешняя ф-ция
   total = 0     # счетчик
   def helper():  # внутр. ф-ция
       total += 1  # тут присваивание переменной
       return total
   return helper  
f = make_inc()
print(f())  # UnboundLocalError: local variable 'total' referenced before assignment


Тут нужно другое ключевое слово – nonlocal, которое укажет, что нужно искать переменную во внешней области видимости. Такой пример будет работать, как задумано:

def make_inc():
   total = 0
   def helper():
       nonlocal total  # <- тут
       total += 1
       return total
   return helper
f = make_inc()
print(f())

Почему мы редко видим global и nonlocal?
nonlocal – специфичная вещь, обычно вместо нее создают класс.
global потакает плохим практикам программирования. Менять глобальные переменные внутри функций – плохая практика.

📎 Пример. Нет ошибок выполнения, но есть логическая ошибка! После первого вызова foo() мы испортили глобальную переменную x, она стала 1 (последним значением в цикле). Надо было просто называть переменные разными именами, и global не понадобится!

def foo():
   global x
   print('x is', x)
   for x in range(2):
       ...
x = 5
foo()  # x is 5
foo()  # x is 1 (испортили из-за for)
источник
2019 February 19
PyWay – гуру Python 🐉
​​🗓 Календарь

Когда под рукой нет календаря, но есть Python:

import calendar; calendar.TextCalendar().pryear(2019)

Или из командной строки:

python -c 'import calendar; calendar.TextCalendar().pryear(2019)'

Хотите по-русски (если вдруг еще не)?

import locale
locale.setlocale(locale.LC_ALL, 'ru_RU')
import calendar
calendar.TextCalendar().pryear(2019)

А еще можно узнать, високосный ли год:

>>> calendar.isleap(2019)
False
>>> calendar.isleap(2020)
True

Или какой сегодня день недели?

>>> calendar.day_name[calendar.weekday(2019, 2, 19)]
'вторник'

Больше функций календаря ищите в документации к модулю calendar.
источник
2019 March 06
PyWay – гуру Python 🐉
🎲 Великий random

Генераторы псевдослучайных чисел бывают обычными и криптографически безопасными.
Обычные основаны на алгоритме "Вихрь Мерсенна". К ним относятся:

• Модуль random, кроме random.SystemRandom
• Модуль numpy.random

Они быстрые и воспроизводимые. Поэтому они хорошо подходят для статистических исследований, симуляций, игр, графики и т.п.

Криптографически безопасные генераторы:

• Функция os.urandom
• Класс random.SystemRandom
• Функция uuid.uuid4
• Модуль secrets

Такие генераторы берут случайность из системных шумов, времен различных событий, действий пользователей и аппаратного источника при наличии последнего. Они медленные, но отлично подходят для генерации секретов, паролей, токенов и т.п.

Предлагаю вам к чтению обзор основных генераторов случайных чисел. В статье есть много разных примеров и рецептов. Есть также бенчмарк ГСЧ против КБГСЧ, который наглядно показывает превосходство по скорости обычных алгоритмов.
источник
2019 March 07
PyWay – гуру Python 🐉
📗 Что такое PEP?

PEP (Python Enhancement Proposal) – предложение по развитию языка Python. Иными словами, это дизайн-документ, описывающий потенциальные фичи, дающий рекомендации по использованию языка или документирующий уже принятые проектные решения.

Список всех PEP на английском.

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

Еще один важный PEP – PEP-257 (рус.), рассказывающий про документирование кода путем docstring.

Интересен также PEP-3099 (англ.): "Что не поменяется в Python 3.x"

Всех их не перечислить, их сотни. Для практикующих программистов PEP на ряду с документацией являются мощными источниками достоверных знаний по Python.
источник
2019 March 09
PyWay – гуру Python 🐉
🔀 Встроенная сортировка

В Python сортировка производится встроенной функцией sorted. Первым аргументом она принимает итерируемый объект. Это может быть список, кортеж, генератор, итератор и т.п. Возвращает отсортированный список.

>>> sorted([4, 2, 3, 1, 0])
[0, 1, 2, 3, 4]

>>> sorted(x * x for x in range(-5, 6))
[0, 1, 1, 4, 4, 9, 9, 16, 16, 25, 25]


Можно сортировать в обратном порядке:

>>> sorted([4, 2, 3, 1, 0], reverse=True)
[4, 3, 2, 1, 0]

Если сортируемые элементы – списки, словари или объекты, то воспользуемся параметром key. Мы передаем в key нечто вызываемое (имя функции, lambda и т.п), и при сортировки элементы сравниваются по результату вызова key на элементе. Результатом key должно быть число, строка или что-то другое сравнимое между собой.

📎 Пример. Сортировка списка строк по длине строки:

>>> sorted(["foo", "bazooka", "", "game"], key=len)
['', 'foo', 'game', 'bazooka']


📎 Пример. Сортировка списка кортежей по 0 или 1 элементу каждого.

>>> people = [("Bill", "Gates"), ("Tim", "Cook"), ("Donald", "Trump")]

>>> sorted(people, key=lambda t: t[0])
[('Bill', 'Gates'), ('Donald', 'Trump'), ('Tim', 'Cook')]

>>> sorted(people, key=lambda t: t[1])
[('Tim', 'Cook'), ('Bill', 'Gates'), ('Donald', 'Trump')]


Для этой же цели удобно использовать функцию operator.itemgetter:

>>> import operator
>>> sorted(people, key=operator.itemgetter(0))
[('Bill', 'Gates'), ('Donald', 'Trump'), ('Tim', 'Cook')]

Еще полезные функции из operator:
attrgetter(name) – для получение значения атрибута объекта с именем name
methodcaller(name[, args...]) – для получения результата вызова метода name у объекта. Опционально с аргументами args.
Вот пример кода с attrgetter и methodcaller.

Для списков (list) определен метод sort(), который модифицирует исходный список, выстраивая элемента по порядку.

>>> arr = [3, 4, 1, 2, 5, 6, 0]
>>> arr.sort()
>>> arr
[0, 1, 2, 3, 4, 5, 6]


Сортировка в Python – устойчива. Это значит, что порядок элементов с одинаковыми ключами будет сохранен в сортированной последовательности. Пример.

Внутри Python использует Timsort – гибридный алгоритм сортировки, сочетающий сортировку вставками и сортировку слиянием. Смысл в том, что в реальном мире часто встречаются частично отсортированные данные, на которых Timsort работает ощутимо быстрее прочих алгоритмов сортировки. Сложность по времени: O(n log n) в худшем случае и O(n) – в лучшем.

⚠️ CPython: не пытайтесь модифицировать сортируемый список во время сортировки. Эффект непредсказуем.
источник
2019 March 22
PyWay – гуру Python 🐉
∞ Ограничение по глубине рекурсии

Рекурсия заключается в вызове функцией самой себя. Рекурсия использует стек, чтобы сохранять адреса возвратов из функций и локальные переменные. Размер стека обычно не очень велик: от десятков килобайт до нескольких мегабайт, так как в реальном мире стек используется не так глубоко, и резервировать большие участки памяти под стек для каждого потока кажется неоптимальным решением.

В алгоритмах, применяющих рекурсию, глубина вызовов заранее неизвестна и зависит от входных данных. Для примера возьмем реализацию факториала через рекурсию:

def fac(n):
   return 1 if (n < 1) else n * fac(n-1)

>>> fac(1000)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 2, in fac
 File "<stdin>", line 2, in fac
 File "<stdin>", line 2, in fac
 [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded in comparison


Упс! Мы не смогли вычислить 1000!, так как уперлись ограницение по рекурсии. В Python это обычно 1000 вызовов. Узнать можно так:
>>> import sys
>>> sys.getrecursionlimit()
1000


Можно и изменить это ограничение:
>>> sys.setrecursionlimit(50000)
>>> fac(1000)
40238726007709...


Однако, таким образом мы берем на себя отвественность за переполнение стека Си. Python может просто крашнуться:
>>> fac(40000)
Segmentation fault: 11


Сразу скажу, что это не самое удачное решение проблемы! Стек плохо поддается контролю. Размер стека при setrecursionlimit не меняется, а меняется только планка, на которой Python начинает паниковать. Прочие минусы:
• Стек маленький, на порядки меньше доступной RAM.
• Мы плохо можем влиять на его размер
• Стек уже может быть заполнен вызыващим кодом

Хорошее решение: переписать рекурсивный алгоритм в итеративный. На примере факториала:

def fac(n):
   num = 1
   while n >= 1:
       num = num * n
       n -= 1
   return num


Иногда приходится эмулировать стек вручную, выделяя память под список в куче. В куче мы можем выделить гораздо более крупный кусок памяти, чем на стеке.
📎 Пример. Обход дерева в глубину:

def deep_walk(graph: dict, fn: callable, root=0):
   stack = [root]
   visited = set()
   while stack:
       vertex = stack.pop()
       if vertex not in visited:
           fn(vertex)
           visited.add(vertex)
           for child in graph[vertex]:
               stack.append(child)

➖ Менее математично, сложнее читать
➖ Выделение динамической памяти медленее, чем стек
➕ Нет ограничений системного стека
➕ В ручном стеке мы храним только нужный минимальный контекст, а не все локальные переменные
источник
2019 March 28
PyWay – гуру Python 🐉
Скачивание файлов Python 3

Самый простой способ:

import urllib.request
urllib.request.urlretrieve('https://erugame.ru/img/icon.png', '1.png')

Чем плох? Вроде как не поддерживает keep-alive, т.е. он каждый раз открывает сокет, скачивает и закрывает. Будет работать небыстро, если нужно качать множество файлов подряд.

Модуль requests (pip install requests) поддерживает keep-alive:

import requests
p = requests.get('https://erugame.ru/img/icon.png')
with open('2.png', 'wb') as out:
   out.write(p.content)

Или поумнее (проверит код возврата и запишет с оригинальным именем):

import requests, shutil, os
url = 'https://erugame.ru/img/icon.png'
filename = os.path.basename(url)
r = requests.get(url, stream=True)
if r.status_code == 200:
   with open(filename, 'wb') as f:
       r.raw.decode_content = True
       shutil.copyfileobj(r.raw, f)

С помощью модуля wget (pip install wget) тоже легко. wget нарисует нам еще и полосу загрузки:

import wget, os
s='https://erugame.ru/img/icon.png'
filename = wget.download(s)
os.rename(filename, '3.png')

Есть вариант для бруталов через сокеты. Не поддерживает ничего (ни keep-alive, ни https и т.п.) Но говорят, что если надо скачать большой файл по HTTP, то работает быстро. Заодно дает немного понять, как устроен HTTP. Вот исходник.

Еще есть билиотека pycurl (интерфейс к великой libcurl). Очень мощная штука, но мне не очень нравится, потому что использовать ее субъективно неудобно. Даже пример у меня не завелся сходу.

По мне, так метод с requests – самый лучший.
источник
2019 March 29
PyWay – гуру Python 🐉
🖇 Секреты аннотаций

В Python 3 можно добавлять аннотации к параметрам функций и к возвращаемому значению. Очевидное применение: подсказывать IDE правильные типы. Например:

def add_int_to_str(x: int, s: str = '') -> str:
   return str(x) + s

Кстати, Python не будет ругаться, если вы передадите не тот тип! И вот почему. Оказывается, что аннотацией не обязательно вообще должен быть тип, ей может быть вообще любое выражение: число, строка, имя класса, вызов функции и еще много чего:

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
   pass


Во время объявления функции все эти выражения будут просто вычислены и записаны в поле  annotations  – это словарь, где ключи – имена переменных, а возвращаемое значение имеет ключ 'return':

>>> foo.__annotations__
{'a': 'x', 'b': 11, 'c': <class 'list'>, 'return': 9}

Это свойство языка может найти кучу креативных применений, хотя на практике мы редко его задействуем, помимо обозначения типов.
источник