Серия «Не Ван Россум»

1

40. Как использовать глобальные переменные? Это хорошая идея?

port = 443

def change_port():

‧‧‧‧global port

‧‧‧‧port = 8080


change_port()

Хорошая ли это идея? Автор вопроса пытается вывести нас на шаблонный ответ, что конечно же, это идея плохая (он прав). Вся концепция ООП крутится вокруг иерархии, "кто на ком стоял" и "кому что можно, а что нельзя". Однако существуют случаи, когда проще использовать глобальную переменную, особенно в программе, которую ты пишешь сам от начала до конца.

Они и сами по смыслу являются глобальными, некими общими для всей программы сущностями. Например, при написании программ с GUI на QT у нас имеется одна сущность - окно программы, QMainWindow. Мы можем все эти вещи для работы сделать свойствами написанного нами класса, назовем его MyGUI. Отлично, gui = MyGUI() и теперь инстанс этого класса все равно будет использоваться глобально отовсюду, потому что как у нас было одно QMainWindow, так и осталось.

Хорошая ли это идея? В абстракции - нет, фу-фу-фу, нам нужна иерархия, инкапсуляция и вот это вот всё.

А на практике может случиться, что тебе приходится делать именно вот так и никак иначе. На паттерн "синглтон" вроде бы никто не ругается - есть сценарии, когда он нужен. И с глобальными переменными то же самое. Их следует избегать во всех возможных случаях, а в невозможных - картинно закатить глаза, и написать "global".

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

#сериал101, #40

Показать полностью
1

39. Опишите принцип работы сборщика мусора в Python

В Python имеется встроенный механизм управления памятью, реализующий сборщик мусора (garbage collector ).

Сборщик мусора периодически запускается и подсчитывает ссылки на объекты.

Если ссылок нет, память можно освобождать. Это просто и эффективно, но есть один недостаток - определеление циклических ссылок. Для этого существует дополнительный сборщик, generational garbage collection, который следит за объектами с циклическими ссылками.

В Python встроен модуль gc, благодаря которому можно осуществить управление или слежение за сборкой мусора. (https://docs.python.org/3/library/gc.html)

Дополнительно упомяну каверзный вопрос: что делать, чтобы избежать циклических ссылок в своём коде? Правильный ответ - писать нормальный код. Ожидаемый ответ - использовать модуль weakref (https://docs.python.org/3/library/weakref.html#module-weakre...)

p.s. Количество ссылок на ваш объект можно узнать так:

import sys

sys.getrefcount(some_object)

#сериал101, #39

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

Показать полностью

38. Как сделать копию объекта? Как сделать глубокую копию объекта?

(прошу прощения, пост #37 задвоился из-за непонятной задержки Pikabu Publish Bot - пытаюсь это исправить!)

Типа копий бывает два: обычная-неглубокая (shallow) и глубокая (deep).

Разница между мелким и глубоким копированием актуальна только для составных объектов (объектов, содержащих другие объекты, такие как списки или экземпляры классов).:

- Неглубокая копия создает новый составной объект, а затем (насколько это возможно) вставляет в него ссылки на объекты, найденные в оригинале.

- Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.

Ответ:

from copy import copy, deepcopy

a = [1,2,3,4,5,6]

my_copy = copy(a)

my_deep_copy = deepcopy(a)

>>> id(a)

140384823640320

>>> id(my_copy)

140384823640448

>>> id(my_deep_copy)

140384823572544


#сериал101, #38

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

Показать полностью

#37 Как сделать python-скрипт исполняемым в различных операционных системах?

(вторая часть)

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

Вариант номер 1: А давайте напишем dockerfile, соберем docker-контейнер, и тогда скрипт можно будет запускать под разными операционнами системами, включая Windows. Рабочий вариант, при условии, что наша программа - это некий web-based сервис и весь его интерфейс реализован в виде web-странички, либо не имеет даже его, а выполняет какую-нибудь сетевую функцию или является хранилищем. Всё, что ему необходимо иметь, он носит с собой и значительно изолирован от операцонной системы пользователя, что может быть для разных задач как плюсом, так и минусом.

Вариант номер 2: А давайте соберем исполняемый файл для целевой операционной системы. Используем PyInstaller, утилиту для этих целей. Она создаст исполняемый файл или папку с файлами, содержащими нужные модули. В случае упаковки в один файл - да-да, я говорю "упаковки" - по сути будет создан самораспаковывающийся архив, создающий при запуске нужное окружение и исполняющий байт-код нашей программы. Это будет полноценная программа, с доступом к файловой системе, портам, графическому интерфейсу. Можно открывать диалоговые окна и грабить коро.... Эм, нет, только окна.

Минусы - иногда PyInstaller может упаковать слишком много ненужного, иногда не включить нужный модуль, и самое главное - в любом случае это будет байткод.

Вариант номер 2+: А давайте используем Nuitka. Транспилируем Python-код в C, и потом соберем его при помощи cmake как программу, написанную на C.

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

По умолчанию я стараюсь использовать PyInstaller из-за лучшей поддержки и минимума головной боли. Если, конечно, задача собрать программу в исполняемый файл у меня имеется.


Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

#сериал101, #37

Показать полностью

Думаю, не самым последним занятием в программировании является отдых и перезагрузка

Думаю, не самым последним занятием в программировании является отдых и перезагрузка. Можно медитировать или слушать музыку, смотреть кино или гулять по парку. Всячески разрушать стереотип "программисты - это скучные люди из мира математики". Я вот, например, не люблю математику, а люблю творчество.

p.s. Да-да, я знаю, это Пикабу, сейчас вы мне тут накомментируете. =)
Поэтому сразу говорю: работа неоконченная - раз, и я не художник - два.

#мысли

Думаю, не самым последним занятием в программировании является отдых и перезагрузка

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

37 Как сделать python-скрипт исполняемым в различных операционных системах

#37 Как сделать python-скрипт исполняемым в различных операционных системах?

Я буду рассматривать этот вопрос в двух разных плоскостях:

1. "Как сделать python-скрипт мультиплатформенным, то есть, работающим и под Windows, и под Linux?"
2. "Как сделать python-скрипт портируемым, то есть переносимым с машины на машину."

В чём разница?

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

Например, правильно выбрать pathlib для работы с путями файловой системы, вместо определения, какие же слэши для путей (os.sep) нам нужны - прямые или обратные.

Не знаю, как сейчас, но psutil долгое время была доступна только для *nix-like систем, потому что работает с встроенным в *nix-системы инструментарием, о чём говорит даже само название: ps - это встроенная команда, доступная например, в Linux, но никак не в Windows.

То есть, мы изначально пишем программу, модуль, функцию, класс с учетом того, что операционная система может отличаться от той, что имеется у разработчика. Соответственно, и тестируем написанный код под разными системами. Для этого можно использовать виртуальное окружение, например, VirtualBox справится с этой задачей.

(это была первая часть).

#сериал101, #37

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

Показать полностью

Сериал-101 возвращается

Сериал-101 возвращается.

Очень хочу проскочить скучные вопросы, но имею привычку быть последовательным.
Я и так отвлекал вас, как мог, картинками. Можно сказать, прокрастинировал.


#34 Для чего используется ключевое слово yield?

yield - это как return, только для генератора.

#35 Чем отличаются __iter__ и __next__?

Как мы уже разбирали выше, __iter__ - это магический метод, возвращающий сам итератор, а __next__ - это метод перебора по нему.

#36 Что такое контекстный менеджер?

Когда мы пишем что-то вроде:


with DatabaseConnection() as dbconn:
‧‧‧‧...



происходит вот что:

- создается объект DatabaseConnection
- вызывается магический метод __enter__
- возвращаемое значение присваивается переменной dbconn
- после выражения with вызывается метод __exit__


class DatabaseConnection(object):
‧‧‧‧def __enter__(self):
‧‧‧‧‧‧‧‧# Здесь нужно создать соединение с БД
‧‧‧‧‧‧‧‧# и вернуть его через return
‧‧‧‧‧‧‧‧...
‧‧‧‧‧‧‧‧return self.dbconn

‧‧‧‧def __exit__(self, exc_type, exc_val, exc_tb):
‧‧‧‧# Здесь нужно закрыть базу
‧‧‧‧self.dbconn.close()
‧‧‧‧...



Пример, конечно, тот ещё. Открытие-закрытие базы на каждую единичную транзакцию убьёт производительность решения чуть более, чем полностью. Но это всего лишь пример.

Контекстному менеджеру with посвящен PEP 343 (https://peps.python.org/pep-0343/)

#сериал101, #34, #35, #36

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

Показать полностью

Что такое генератор и чем отличается от итератора

Что такое генератор и чем отличается от итератора?

Можно сказать, что генератор является частным случаем итератора: он так же имеет методы __next__ и __iter__. Каждый генератор является итератором, но не наоборот.

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

Пример генератора:


def fibonacci():
‧‧‧‧prev, cur = 0, 1
‧‧‧‧while True:
‧‧‧‧‧‧‧‧yield prev
‧‧‧‧‧‧‧‧prev, cur = cur, prev + cur


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


for i in fibonacci():
‧‧‧‧print(i)
‧‧‧‧if i > 100:
‧‧‧‧‧‧‧‧break


#сериал101 , #33

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.

Показать полностью
Отличная работа, все прочитано!