LINUX.ORG.RU

Объектная модель питона

 , ,


2

4

- Сколько нужно архитекторов, чтобы создать язык программирования?
- Сто. Один будет писать язык, а 99 - говорить, что могут сделать лучше.

Так скажем, я решил вспомнить обсуждение по теме треда: Generics в Python или помогите победить mypy

Да, наркоманский питон захватывает мир, и с этим нужно что-то делать. Нет, я не намерен делать питон 4 - я вижу свет в конце тоннеля в рамках третьей версии. Но мне нужна ваша помощь: какие фундаментальные фичи, по-вашему, в питоне вообще не нужны, а какие - должны быть переработаны?

Прежде всего, я хотел бы вспомнить про RPython ( https://rpython.readthedocs.io/en/latest/rpython.html ).
Смысл особенностей языка прост - поддержка вывода типов. В частности, из языка убраны динамические определения классов и функций, динамическая типизация переменных, глобальные переменные стали константами, функции-генераторы транслируются в классы-итераторы и потеряли большую часть своих фич. У RPython есть большой минус - эти его ограничения сильно раздувают код, затрудняют писание и читание.
Итак, мои соображения:

1. Множественное наследование. Его нет даже на уровне C-функций в реализации питона и API расширений. «Но как же интерфейсы?» - возразите вы. Интерфейсы в C++ и Java нужны в роли объявления протоколов вызова методов объекта с целью последующей статической проверки этих протоколов при компиляции, а также для формирования таблиц методов, которые можно использовать независимо от объекта во время выполнения. Эти роли полностью потеряны в питоне, потому нет никакого оправдания их существованию. Мне нравится то, как сделаны интерфейсы в Go - это очень похоже на питоновые ABC: https://www.python.org/dev/peps/pep-3119

2. Генераторы - зло. Это прямо-таки запущенный случай GoTo, когда выполнение не просто бесконтрольно прыгает по коду - оно прыгает по стэкам. Особенно лютая дичь происходит, когда генераторы пересекаются с менеджерами контекста (привет PEP 567). В треде, скорее всего, опишу веселости реализации генераторов в PyPy/RPython. В питоне есть общая тенденция запутывать приложение в тесный клубок связанных изменяемых состояний, что не дает возможности параллелить и оптимизировать выполнение программы, а генераторы - вишенка на этом торте.

3. Изменение классов для существующих экземпляров объектов. Не, я понимаю, что класс в питоне объявляется во время выполнения. Но, блин, зачем в него совать изменяемые переменные? Зачем в старые объекты добавлять новые методы? Причем, попрошу обратить внимание на то, как нужно нагибаться раком для того, чтобы добавить аналогичные методы в сам объект, а не в класс - для этого нужны types.MethodType, function.__get__, functools.partial, и так далее. Методы в питоне вообще понадобились по простой причине - гвидо не придумал других способов сделать короткие имена функций (чтобы не было gtk_button_set_focus_on_click), поскольку не ясно, как выбирать из кучи похожих функций с коротким именем нужную под этот конкретный объект. Так в питоне появились len, iter, next, isinstance, slice, dict, dir, str, repr, hash, type - сейчас это обертки над соответствующими методами классов с подчеркиваниями в имени, а когда-то встроенные простые типы не являлись классами и работали только через эти функции. Так-то, я не вижу особой разницы между записью method(object) и object.method - особенно если method является статичной функцией, которой, в общем-то, все равно, какой первый аргумент (self) принимать.

Вот. Прошу дополнять. Да, я знаю, что у питона основные проблемы две: отсутствие статической типизации и многопоточности - но это черезчур абстрактные требования. К тому же, Javascript безо всяких типизаций достиг производительности Java, при том, что жавамакакам постоянно приходится гнуться под язык, а JS-кодеры испытывают удовольствие от говнокодинга.

★★★★

Ответ на: комментарий от byko3y

Global Interpreter Lock (GIL) — это способ синхронизации потоков, который используется в некоторых интерпретируемых языках программирования, например в Python и Ruby. Когда один поток захватывает его, GIL, работая по принципу мьютекса, блокирует остальные.

Понял, дядя? «блокирует остальные». Это значит мультипоточности нет в принципе, в отличие от ява. А что там про научный софт написанный дядей Васей на видеокартах, то это глубоко пофигу. Я этот софт могу и из баша вызывать, но это не делает его мультипоточным.

Liz812
()
Ответ на: комментарий от n008_b4800n

Берем ruby. Есть генераторы, есть и GIL, точно как в питоне. Берем JRuby, НЕТ GIL, синтаксис на 100% совместим с ruby. Проблема не в сахарке, а в реализации.

Что за генераторы в руби? Это которые Enumerator поверх fibers? Так их редко же используют, обычно там просто дергают колбеки. Думаю если все итерации переписать на генераторах, случится неиллюзорный п-ц. В питоне кстати тоже генераторы редко юзают, так что ТС из пальца высосал проблему.

anonymous
()
Ответ на: комментарий от n008_b4800n

я разве сказал, что эликсир не надо брать?

Выглядело, что так. Я подумал может есть какие-то аргументы против и заинтересовался.

ddidwyll ★★★★
()
Ответ на: комментарий от anonymous

Насчет генераторов в питоне - выражения-генераторы (i for i in expr) - достаточно часто, но обычно они не перегружены. Функции-генераторы - ну такое себе, да. С руби шапочно знаком, че там обычно используют, не знаю =)

n008_b4800n
()
Ответ на: комментарий от n008_b4800n

перегружены Под перегрузкой имею в виду «чрезмерное усложнение». Обычно простенькая выборка/обработка items из iterable.

n008_b4800n
()
Ответ на: комментарий от n008_b4800n

Да пофигу. Если бы он умел на 128 ядрах работать одновременно как ява, тогда и вопросов не возникало.

Liz812
()
Ответ на: комментарий от Liz812

Я этот софт могу и из баша вызывать, но это не делает его мультипоточным.

Так питон это такой же баш, только он юзает код напрямую из библиотек, а не через внешние утилиты. Зачем бы сдалась многопоточность для самих скриптов? Только в том случае, если ты ССЗБ и пишешь всю тяжелую обработку на скриптах.

anonymous
()
Ответ на: комментарий от anonymous

В голову не приходит что задачи можно параллельно выполнять? Нужно получить 10 страничек с разных URL почему не запустить каждую в свой поток?

Liz812
()
Ответ на: комментарий от byko3y

конструктивный разговор

это мне нравится, это не нравится

Оукей.

Nervous ★★★★★
()
Ответ на: комментарий от Liz812

Я совсем не в теме всего что связано с математикой, сможешь объяснить почему без разделяемой памяти никак?

ddidwyll ★★★★
()
Ответ на: комментарий от x3al

Спасибо, первый развернутый ответ в треде.

Может, стоит для начала определиться с областью применения всего этого? Питон бывает сильно разный.

Вообще по жизни я больше трусь об GUI, многопотоки, и СУБД. То есть, всё то, с чем питон не особо дружит.

Если у тебя ML — там собственно питона не так много и тот же гугль давно продвигает использовать swift вместо питонов в том же tensorflow для тех, кто хочет нормальные типы.

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

Для веба — для начала определись, как ты собираешься заменять asyncio. Это интереснее, чем обзывать генераторы злом.

Да пусть остается, ради бога. Но потанцевал асинхронного ввода-вывода будет побольше, чем то, что может освоить asyncio нынче. По крайней мере, такой скороспелый вывод я делаю по бенчмаркам.

Для проектов, способных потенциально вырасти до сотен тысяч SLOC: не используй питон. Это хуже даже чем пхп и javascript, не говоря о более энтерпрайзных языках.

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

Это DSL для JIT, который чисто случайно имеет внешне похожий на питон синтаксис. Неплохой язык для написания своих интерпретаторов, но зачем мучаться и юзать его как general purpose?

Совпадение? Не думаю. Конечно же, его взяли потому, что писали проект питонисты, при этом язык всегда можно запустить на CPython, потому что RPython полностью совместим с CPython (но не наоборот).
Лично меня он интересует в контексте того, чем пожертвовал Гвидо для обретения читаемости и потери производительности.

И одна из основных проблем — тонны исключений на каждый чих и продвижение антипаттерна DontUseExceptionsForFlowControl как «питоничного». Их нельзя типизировать даже в теории.

Я не совсем понял - имеется в виду чрезмерное использование исключений в питоне? Ну те же StopIteration. А то в статье описывается обратное - использование как можно меньшего числа исключений. То есть, в стиле Go.

Система типов в языке здорового человека умеет такое: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ . В питоне взять [0] от потенциально пустого списка — вообще не проблема: функция тупо бросит IndexError и ни один статический анализатор не предупредит, что его нужно ловить. Никогда. By design. И Гвидо лично считает, что это — ок.

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

У питона ровно одна проблема: некоторые проекты случайно вырастают до размеров, где питон становится неюзабелен. Для вещей на примерно 10-30к SLOC у питона никаких проблем нет.

Блин, ну валом же проектов на 100k+. Есть десяток-другой питоновых библиотек на 200-300 к строк. Отдельные частные проекты до 1M+ вырастают.

byko3y ★★★★
() автор топика
Ответ на: комментарий от ddidwyll

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

Liz812
()
Ответ на: комментарий от Nervous

Нет, но я собралась стать Петей и начать новую жизнь.

Liz812
()
Ответ на: комментарий от Liz812

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

что сожрет весь процессор и сеть

Пока звучит не очень убедительно. И причем здесь сеть?

ddidwyll ★★★★
()
Последнее исправление: ddidwyll (всего исправлений: 2)
Ответ на: комментарий от ddidwyll

А ты на чем собрался свои 10 млн. процессов запускать? Эликсир для того и нужен что его можно сразу на сотне компьютеров запустить, а так он нафиг не нужен.

Liz812
()
Ответ на: комментарий от anonymous

В питоне кстати тоже генераторы редко юзают, так что ТС из пальца высосал проблему.

List comprehension, async/await - ага редко. Пиши еще.

byko3y ★★★★
() автор топика
Ответ на: комментарий от byko3y

Async/await вчера только завезли. Comprehensions мало кто юзает, особенно генераторные. Вообще, генераторы это продвинутая тема, большинство питонистов их не вкуривает, а часто и вовсе не знает что есть какие-то генераторы.

anonymous
()
Ответ на: комментарий от Liz812

В голову не приходит что задачи можно параллельно выполнять? Нужно получить 10 страничек с разных URL почему не запустить каждую в свой поток?

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

anonymous
()
Ответ на: комментарий от anonymous

Async/await вчера только завезли. Comprehensions мало кто юзает, особенно генераторные.

Вчера сахар завезли, а генераторная асинхронщина на asyncio.coroutine уже давно была.

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

Большинство питонистов не разбирается в питоне. Такова специфика языка, что ж поделать. Так же бесполезно ждать от кодера на JS понимания работы promisе-ов.

byko3y ★★★★
() автор топика
Ответ на: комментарий от Liz812

А ты на чем собрался свои 10 млн. процессов запускать?

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

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

Хм, это крайне неаргументированные лозунги, ожидал больше конструктива.

ddidwyll ★★★★
()
  1. Полностью согласен.
  2. И да, и нет. Ленивость нужна, а итераторы не всегда решают. Они банально удобные, стоят того.
  3. С первой частью полностью согласен, а дальнейший поток мыслей про методы я не понял.

К тому же, Javascript безо всяких типизаций достиг производительности Java

Это не основная фишка типизации и не то, чтобы действительно достиг.

Сейчас появилась проблема с async/await — это гораздо хуже генераторов.

WitcherGeralt ★★
()
Ответ на: комментарий от ddidwyll

А что ты хотел услышать? Эликсир это про массово-параллельные системы. Но между процессами нельзя передавать гигабайты в секунду для обработки.

Liz812
()
Ответ на: комментарий от Liz812

Но под капотом действительно можно запустить код в потоке, который не будет иметь ничего общего с питоническими фреймами, гил его никак не затронет.

P.S. Очень забавно, что ты здесь меня ни капли не слушаешь, а мою статью цитируешь как библию.

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от Liz812

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

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от Liz812

и сеть

Wrong, во-первых, ipc вообще ничто не обязывает работать через сеть, во-вторых выделить общую память никто не запрещает. Не так всё и ужасно. Но это всё костыли, да.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

И да, и нет. Ленивость нужна, а итераторы не всегда решают. Они банально удобные, стоят того.

Тут ситуация «либо трусы оденьте, либо очки снимите». Хорошо, давайте делать полноценные зеленые потоки, только, ой, где же они? Как мне перекинуть генератор в другой поток? Блокировочки и менеджеры ресурсиков? То-то. Асинхронщина на генераторах стала очередным костылем в груде подобных костылей.
Вот удобные итераторы я всецело поддерживаю. Но Гвиду этот вопрос аще не волнует, насколько я вижу - наоборот, подпитывается практика чрезмерного использования исключений, как второго инструмента нарушения структурированности кода. И это хорошее дополнение к моему исходному тезису про генераторы - спасибо x3al.

С первой частью полностью согласен, а дальнейший поток мыслей про методы я не понял.

Объекту нельзя добавить функцию в атрибут - получится функция вместо метода.
По поводу функций - питон мог бы выглядеть вот так:

def reverseWords(input): 
    inputWords = split(input, " ")
    inputWords = inputWords[-1::-1] 
    output = join(' ', inputWords)
    return output 
Или даже вот так:
def reverseWords(input): 
    inputWords = split(input " ")
    inputWords = inputWords[-1::-1] 
    output = join(" " inputWords)
    return output 

К тому же, Javascript безо всяких типизаций достиг производительности Java

Это не основная фишка типизации и не то, чтобы действительно достиг.

Ну хорошо, допустим, JS проигрывает в 2-3 раза. Все равно не та разница. Контроля типов нету - да, это серьезная проблема.

Сейчас появилась проблема с async/await — это гораздо хуже генераторов.

Какая проблема? Сами асинки? Я не совсем понимаю тогда - генераторные с 3.3 не были проблемой?

byko3y ★★★★
() автор топика
Ответ на: комментарий от WitcherGeralt

Чур не гуглить

Выхода не будет? По-моему, очевидно.

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

byko3y ★★★★
() автор топика
Ответ на: комментарий от WitcherGeralt

3.4 и 3.5 — пропасть прям

В 3.3 уже вроде было asyncio, хотя для асинхронщины они применялись и раньше - просто никто не оформлял это в виде библиотеки с обработкой в главном цикле.

Кстати, https://www.python.org/dev/peps/pep-0525/ грит нам:

Performance is an additional point for this proposal: in our testing of the reference implementation, asynchronous generators are 2x faster than an equivalent implemented as an asynchronous iterator.

byko3y ★★★★
() автор топика
Ответ на: комментарий от Liz812

Так, сорян, я не уловил контекст. Не понял, что речь строго про эликсир.

Но вообще, сисколов же там не может не быть. Так что мьютекст, наверное, можно заюзать.

А вообще, вне контекста тэликсирв, shared memory и spinlock — спасут отца русской демократии.

WitcherGeralt ★★
()
Ответ на: комментарий от Liz812

И того сколько у вас процессов? 1) Ядро Linux 2) База Данных 3) Ядро Python осталось еще 1 ядро. А Кеш у вас у каждого ядра свой? Вы хотите расплодить 10000 потоков? Лично я на однопоточной проге в сто раз повысил скорость. Более того когда я учился моя однопоточная программа по перемножению матриц обогнала все многопоточные. Преподаватель пол часа сидел чтоб понять что происходит.

Что вас так мучает GIL. Вы думаете что самые умные и Гугл его просто так оставил?

dem ★★
()
Ответ на: комментарий от WitcherGeralt

Можно и бейцы дверью прищемить - не так ли?

dem ★★
()
Ответ на: комментарий от dem

Это ты думаешь что самый умный, если матрицы научился перемножать. И зачем процессоры с сотнями потоков делают ума не приложу.

Liz812
()
Ответ на: комментарий от Liz812

Ты говорила про несколько процессов же. Не важно, я изначально не в кассу ответил, так или иначе.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Ты показал один конкретный и для него ответ правильный.

Прикинь, варианта два даже на стандартном CPython. Если из консоли запускать, то будет:

Вход
Конец

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

Вход
Конец
Выход

Это магия костылей.

byko3y ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.