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-кодеры испытывают удовольствие от говнокодинга.

★★

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

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

anonymous ()

Итак, про генераторы. Как вы думаете, какой будет результат выполнения вот этого кода?

import contextlib
@contextlib.contextmanager
def context_manager():
    try:
        print('Вход')
        yield
    finally:
        print('Выход')

def gen_in_manager():
    m = context_manager()
    with m:
        for i in range(5):
            yield i

g1 = gen_in_manager()
next(g1)
print('Конец')
Чур не гуглить. Меня особо радует то, что contextlib.contextmanager сам требует генератор на входе. В итоге выполнение носится слабо предсказуемо между функциями их стэками, грубо нарушая структурированность вызовов функций. В питоне уже давно есть механизм, которые намного лучше генераторов - это итераторы. Причем, сами генераторы имеют интерфейсы итераторов.

Давайте посмотрим, как разбирается RPython с генераторами. Есть такой простой кусок кода

def gen(n):
    if n > 0:
        yield n
    else:
        yield 0
    
def func(n):
    sum = 0
    for i in gen(n):
        sum += i
После трансляции func не меняется, а вот с кодом gen происходят волшебные трансформации:
def gen__next(entry):
    if isinstance(entry, Entry):
        if entry.g_n > 0:
            return (Resume2(), entry.g_n)
        else:
            return (Resume1(), 0)
    else:
        if isinstance(entry, Resume1):
            raise StopIteration()
        elif isinstance(entry, Resume2):
            raise StopIteration()

class GeneratorIterator
    def __init__(self, entry):
        self.current = entry
    def __iter__(self):
        return self
    def next(self):
        entry = self.current
        self.current = None
        assert entry is not None  # else, recursive generator invocation
        (next_entry, return_value) = gen__next(entry) # gen__next(entry)
        self.current = next_entry
        return return_value

def gen(n):
    v49 = Entry()
    v49.g_n = n
    return GeneratorIterator(v49)
Ниче так раздуло, да? К слову, list(gen(n)) вообще выдало ошибку при компиляции, но я не уверен, что эта проблема имеет отношение к ограничениям генераторов в RPython. Если кому интересно погонять транслятор RPython - вот инструкции: https://rpython.readthedocs.io/en/latest/getting-started.html

byko3y ★★ ()
  1. Множественное наследование - может, оно и не надо?
  2. Генераторы -зло. Вермишель из колбеков - добро. так?
  3. В жопаскрипте прототипное ООП тоже не торт.

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

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

Чтобы этим говном пользоваться надо сначала хорошо изучить Qt и С++ а потом спросить себя а зачем мне тут питон с его тормозами, когда мышь на экране залипает на СЕКУНДЫ?

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

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

Вот это была моя позиция, когда я был студентом: «зачем мне этот кусок дерьма?». Но в процессе выяснилось, что миллионы мух не могут ошибаться, и даже великий гугл использует питон - это данность, с ней уже ничего не сделать. Более того, четвертого питона никто не выпустит. Можно упорно пытаться продолжать быть адептом лиспа, а можно адаптировать форму ануса к форме дерьма - в каком-смысле второй вариант сложнее и интереснее.

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

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

Не хватает нормальной GUI библиотеки с дизайнером форм и виджетов. Без этого он практически не нужен на десктопе.

Да. Мы работаем над вашей проблемой - оставайтесь, пожалуйста, на связи.

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

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

RPython

«Нативный» питон - CPython.

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

Генераторы по сути сахарок для итераторов.

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

Множественное наследование - может, оно и не надо?

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

Генераторы -зло. Вермишель из колбеков - добро. так?

Итераторы же. Колобки - это стиль жавы/крестов, а не высокоуровневых языков. Например, код генератора выше

def gen(n):
    for i in range(5):
        yield i
может быть переписан как
def gen(n):
    return iterator_from(range(5), lambda x: x)

В жопаскрипте прототипное ООП тоже не торт.

Да.

А вот ГИЛ - зло, да, но как уже написали - он никуда не уйдет, проще новый питон накропать.

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

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

А Tcl не тормозит? Он же не компилируемый как и питон?

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

byko3y ★★ ()

какие фундаментальные фичи, по-вашему, в питоне вообще не нужны, а какие - должны быть переработаны

А зачем заниматься пустопорожним переливанием, если это никогда не будет переработано? Я не вижу ни одной причины почему нужно «улучшать» питон, вместо того чтобы взять другой язык. Ведь «улучшенный» питон по факту и будет другой язык, на котором нужно будет всё переписывать (используя новые, хорошие фичи). Но его при этом нужно сначала выдумать, а потом ещё реализовать. Для чего этим заниматься когда есть 100500 других языков, где уже есть то, что тебе хочется? ЯННП.

no-such-file ★★★★★ ()
Ответ на: комментарий от byko3y

но он многопоточен, по крайней мере, потому отдельные потоки будут отдельно тормозить

Что ты мне врешь? Специально посмотрела, там один поток ОС на интерпретатор, получается такое же гавно как и питон?

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

множественное наследование не нужно,

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

Зачем, если не нужно?

может быть переписан как

Тогда уж return (x for x in range(5)). Правда, возвращается generator object, хех. Но с чего ты взял, что есть разница? В потреблении ресурсов, или в чем? Попробуй возьми нативный cpython и измерь.

В жаве тоже есть глобальная блокировка,

жаба рассчитана на многопоток изначально. жопаскрипт на асинхрон. питон - на однопоточный скрипт, дергающий c-либы. И в этом проблема, а не в ГИЛ, да.

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

RPython

«Нативный» питон - CPython.

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

Генераторы по сути сахарок для итераторов.

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

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

Но применяет она только при сборе мусора, а в питоне ВСЕГДА поэтому в нем работающих потоков только один.

Ввод-вывод и потоки внешних либ прекрасно работают, GIL берется только при интерпретации питонового кода.

byko3y ★★ ()
Ответ на: комментарий от no-such-file

Я не вижу ни одной причины почему нужно «улучшать» питон, вместо того чтобы взять другой язык. Ведь «улучшенный» питон по факту и будет другой язык, на котором нужно будет всё переписывать (используя новые, хорошие фичи). Но его при этом нужно сначала выдумать, а потом ещё реализовать. Для чего этим заниматься когда есть 100500 других языков, где уже есть то, что тебе хочется?

А я - вижу. Такие дела. Не видел, не видел, а потом увидел.

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

Генераторы - это, по сути, говно для итераторов.

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

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

Специально посмотрела, там один поток ОС на интерпретатор, получается такое же гавно как и питон?

А тебе нужно два потока ОС на интерпретатор? Что ты собралась интерпретировать в два потока?

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

Генераторы - это, по сути, говно для итераторов.

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

В JRuby каждый генератор - это отдельный поток жавы, то есть, поток ОС: https://github.com/jruby/jruby/wiki/Differences-Between-MRI-and-JRuby

А больше - никак, continuation в JRuby не поддерживается совсем.

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

он многопоточен, по крайней мере, потому отдельные потоки будут отдельно тормозить

Ты писал? Понимаешь разницу между потоками в одном интерпретаторе с разделяемым стайт между потоками и пачкой независимых интепретаторов?

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

Тогда уж return (x for x in range(5)). Правда, возвращается generator object, хех. Но с чего ты взял, что есть разница? В потреблении ресурсов, или в чем? Попробуй возьми нативный cpython и измерь.

Да, list comprehension - это генератор. Разница в том, что генераторы превращают выполнение программы в спагетти с непредсказуемыми эффектами.

жаба рассчитана на многопоток изначально. жопаскрипт на асинхрон. питон - на однопоточный скрипт, дергающий c-либы. И в этом проблема, а не в ГИЛ, да.

Уже обсуждалось, но, видимо, не при тебе. Жаба расчитана на кроссплатформу и низкий уровень, и только к 2004 году в нее завезли нормальный многопоток. Как бы, сами жабовые сборщики мусора того времени намекают, что ни о каком многопотоке речи быть не могло, когда у тебя периодически все потоки зависают намертво. JS асинхронен в том смысле, что не явялется независимым языком, а только дергается изредка из гуя.

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

Понимаешь разницу между потоками в одном интерпретаторе с разделяемым стайт между потоками и пачкой независимых интепретаторов?

Я вас хорошо понимаю. Но я бы хотел создателей Go, которые посчитали, что «Don't communicate by sharing memory; share memory by communicating».

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

Макросов еще остро не хватает. Чтобы например сделать десериализацию JSON в иерархию классов.

Я не совсем понимаю, что это за задача такая. Я вот пока что не вижу проблем у либ, которые именно этим и занимаются - превращают JSON в иерархию ассоциативных массивов питона.

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

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

Какая связь? У всех так работает. Ты знаешь способ собирать мусор, когда у тебя другой поток модифицирует объект? Ты что то плывешь по матчасти, дядя. В яве потоки нормально работают.

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

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

Знаю. Сейчас в JS и жаве именно так и собирается мусор - параллельными потоками, которые получают инфу о параллельном изменении ссылок через барьеры записи. Может быть, такой способ и медленнее, чем stop-the-world, но зато без зависаний. Есть короткие остановки всех потоков, когда подготовленные к сбору мусора объекты резко убиваются, но они реально короткие.

В яве потоки нормально работают.

Для тех, кто родился в нулевых - да.

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

Либа работает в рантайме. Макрос рожает код программы.

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

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

в спагетти с непредсказуемыми эффектами.

Какими? Твой код вывел Вход и Конец. Что тебе не так-то?

Жаба расчитана на кроссплатформу и низкий уровень

Той жабы уже давно нет, вроде как.

JS асинхронен в том смысле, что не явялется независимым языком, а только дергается изредка из гуя.

И этого жопаскрипта, на котором писались перделки для сайтов, тоже давно нет. Сейчас фронтенд может представлять из себя полноценное клиентское приложения. +существуют всякие service worker.

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

А что плохого в прототипах? Имхо, отличная модель для таких языков как C, и очень гибкая, кстати! Местами, конечно, многословная… её бы «рефакторить» и в Go/C присобачить было бы интересно

menangen ★★★★★ ()