Не Ван Россум
48 постов
48 постов
port = 443
def change_port():
‧‧‧‧global port
‧‧‧‧port = 8080
change_port()
Хорошая ли это идея? Автор вопроса пытается вывести нас на шаблонный ответ, что конечно же, это идея плохая (он прав). Вся концепция ООП крутится вокруг иерархии, "кто на ком стоял" и "кому что можно, а что нельзя". Однако существуют случаи, когда проще использовать глобальную переменную, особенно в программе, которую ты пишешь сам от начала до конца.
Они и сами по смыслу являются глобальными, некими общими для всей программы сущностями. Например, при написании программ с GUI на QT у нас имеется одна сущность - окно программы, QMainWindow. Мы можем все эти вещи для работы сделать свойствами написанного нами класса, назовем его MyGUI. Отлично, gui = MyGUI() и теперь инстанс этого класса все равно будет использоваться глобально отовсюду, потому что как у нас было одно QMainWindow, так и осталось.
Хорошая ли это идея? В абстракции - нет, фу-фу-фу, нам нужна иерархия, инкапсуляция и вот это вот всё.
А на практике может случиться, что тебе приходится делать именно вот так и никак иначе. На паттерн "синглтон" вроде бы никто не ругается - есть сценарии, когда он нужен. И с глобальными переменными то же самое. Их следует избегать во всех возможных случаях, а в невозможных - картинно закатить глаза, и написать "global".
Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.
#сериал101, #40
В 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" с описанием подводных камней, неочевидностей и загвоздок.
(прошу прощения, пост #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" с описанием подводных камней, неочевидностей и загвоздок.
(вторая часть)
У нас может быть мультиплатформенный или моноплатформенный скрипт/программа/утилита/что-угодно, и мы хотим его распространять среди пользователей, не знающих, что такое 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-скрипт исполняемым в различных операционных системах?
Я буду рассматривать этот вопрос в двух разных плоскостях:
1. "Как сделать python-скрипт мультиплатформенным, то есть, работающим и под Windows, и под Linux?"
2. "Как сделать python-скрипт портируемым, то есть переносимым с машины на машину."
В чём разница?
В первом случае мы добиваемся того, чтобы один и тот же скрипт работал с одинаковым результатом в разных операционных системах, а значит, используем библиотеки, одинаково хорошо поддерживаемые обеими операционными системами, либо ищем варианты для альтернативной реализации функционала, либо даже урезаем функционал. Особенно это касается работы с файловой системой и библиотеками (относительно) низкоуровневой работы с операционной системой.
Например, правильно выбрать pathlib для работы с путями файловой системы, вместо определения, какие же слэши для путей (os.sep) нам нужны - прямые или обратные.
Не знаю, как сейчас, но psutil долгое время была доступна только для *nix-like систем, потому что работает с встроенным в *nix-системы инструментарием, о чём говорит даже само название: ps - это встроенная команда, доступная например, в Linux, но никак не в Windows.
То есть, мы изначально пишем программу, модуль, функцию, класс с учетом того, что операционная система может отличаться от той, что имеется у разработчика. Соответственно, и тестируем написанный код под разными системами. Для этого можно использовать виртуальное окружение, например, VirtualBox справится с этой задачей.
(это была первая часть).
#сериал101, #37
Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.
Сериал-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" с описанием подводных камней, неочевидностей и загвоздок.