Блог разработчиков

5 вещей, которые мне не нравятся в Python

Макс Ищенко
Опубликовано 25.05.2007 в Python, Инструменты, Статьи

Иван Сагалаев написал про 7 вещей, которые я не люблю в Django. Я предлагаю эту тему развить и написать каждому о тех вещах, которые вам не нравятся в используемых инструментах программирования.

Итак, 5 вещей, которые мне не нравятся в Python:

  • не-юникодные строки. Дихотомия str/unicode принесла всем разработчикам не-ascii приложений кучу головной боли. Остается ждать Python 3.0, где обещаны только unicode строки и отдельный тип byte для несимвольных данных (да-да, в Java так было с самого начала).
  • инструментальные средства. Вспомнив о Java, сразу вспоминаются мощные IDE типа Eclipse, реально ускоряющие разработку. Лучшая IDE для разработки на Python это, ИМХО, vim + ctags + grep. Связка не плохая, нет, но хотелось бы большего, чего-то из 21 века, а не из конца 70-х.
  • семантические пробелы (significant whitespace). К этому, конечно, привыкаешь, но все равно, я бы предпочел обычные пробелы, не несущие смысловой нагрузки. Не говоря о том, что в итоге мы остались с lambda-выражениями вместо полноценных анонимных функций. Плюс, массу времени можно было бы сэкономить на flame wars.
  • качество stdlib. Не все модули, входящие в Python standard library, одинаково хороши. Многие были включены чересчур поспешно и непродумано. Фиксация в stdlib означает как правило фиксацию API (иногда кривого) и невозможность избавиться от модуля в будущем.
  • GIL и работа на multicore окружении. Не очень ясно, насколько хорошо (или плохо) будет вести себя Python с повсеместным распространением multicode машин.

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

top of hotblogs.org.ua
1 звезда2 звезды3 звезды4 звезды5 звезд (Еще не оценили)
Загрузка ... Загрузка ...

Понравилась статья? Подпишись на обновления по RSS/E-mail

Подписаться, не оставляя комментарий

Все комментарии (38) к “5 вещей, которые мне не нравятся в Python”

  1. Иван Сагалаев говорит:

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

    Вот, откопал ссылочку: http://mail.python.org/pipermail/python-3000/2007-May/007414.html

  2. Макс Ищенко говорит:

    Иван: ссылку читал и не доверять Гвидо особых оснований нет. Но “осадок остался”. ;)

  3. Муркт говорит:

    семантические пробелы (significant whitespace). К этому, конечно, привыкаешь, но все равно, я бы предпочел обычные пробелы, не несущие смысловой нагрузки.

    С этим пунктом не согласен.

  4. pdima говорит:

    також згодний зі всім крім “significant whitespace”, як на мене це невелика плата за більш читаємий код. А чому хочеться саме анонімності функцій? В пітоні і звичайну написати не складніше. ( я серйозно, самому цікаво ).

  5. pdima говорит:

    ну і api stdlib зафіксований не намертво, нечасто але міняють. надіюсь на кращий в python 3000.

  6. Ferroman говорит:

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

  7. rushman говорит:

    А чем эклипс + pydev неустраивает в качестве иде?

  8. pdima говорит:

    для екліпса є pydev, ну і крім нього ряд відкритих і комерційних IDE ( Wings, BlackAdder, Eric, python режим в slickedit але він не настільки розвинутий як для С++ )

  9. mkdir говорит:

    Отступы в питоне - это его плюс. В целом претензий к язку не имею вообще.

  10. Ferroman говорит:

    Я пробовал практически все - не подошли по-разным причинам…
    Как-нибудь напишу статью что к чему :)

  11. bialix говорит:

    вместо пробелов меня достает скорость питона. точнее тот факт, что на нем писать многое из того, что приходится писать на Сях.

  12. bialix говорит:

    Сорри — слово пропустил
    вместо пробелов меня достает скорость питона. точнее тот факт, что на нем нельзя писать многое из того, что приходится писать на Сях.

  13. rushman говорит:

    bialix

    можно пример того что нельзя писать?

  14. Муркт говорит:

    можно пример того что нельзя писать?

    Например, ray tracing. Написать можно, а толку? :)

  15. rushman говорит:

    Ну если в академических целях то можно наверное.

    Потом оформить критический по скорости функционал в отдельный модуль, и переписать на C :)

  16. igorekk говорит:

    На Mac’е для питона хорош TextMate. Он вообще для всего хорош :)

  17. GladAlex говорит:

    По поводу IDE это ты загнул: посмотри на eric и удивись!

  18. GladAlex говорит:

    http://en.wikipedia.org/wiki/Eric_Python_IDE
    http://www.die-offenbachs.de/detlev/eric.html

  19. turist говорит:

    И снова про IDE. Попробуй WingIDE. Платное, правда. Как-нить разживусь деньгами и может куплю. Но пока что лучшее, что видел для питона. Пробовал много всякого, кроме Eclipse+pydev - говорят тормозит порядочно, да и зависимостей слишком много emerge-ить :)

    Самая лучшая штука в это IDE, это её дебаг(брякпоинты, Step out/in/over). Недостаток - пока что однотредовый. Но в версии 3.0, которая ща в альфе, обещают multithread. Так же обещают автодополнение в debug-консоли. Это облегчит жизнь.

    Кстати, об автодополнении. В Wing оно просто великолепное.

    Вобщем, must have, как говорится.

  20. levsha говорит:

    Мои претензии:
    Создание переменной просто по присвоению. Вроде же практически все интерпретируемые языки прошли это и пришли к необходимости явного декларирования переменных, а тут такая деская болезнь. Это же касается создания атрибутов объекта по присвоению, хотя и не в такой мере: его в принципе можно решить частично решить через __getatts___/__setattr .
    Обращение к методу без () дает просто ссылку, которая в логинческом представлении дает true. Само по себе было бы терпимо если бы не каша даже в стандартных библиотеках: почему у файлового дескриптора isatty это метод, а closed это атрибут?
    Вроде еще что-то было, но уже забыл :)

  21. Uznick говорит:

    Отступы в python это большой плюс, на мой взгляд.

    А как среду разработки можно попробовать Komodo.

  22. oleg noga говорит:

    str+unicode - почти не проблема:

    import sys
    reload(sys)
    sys.setdefaultencoding(’Cp1251′)

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

  23. undebugger говорит:

    Ещё пара-тройка вещей:

    отсутствие статической типизации (пример, как сделано грамотно - boo); хотя, по-моему, это неспешно так рассматривается для python 3.0;

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

    отсутствие общего namespace для стандартных модулей, типа

    import std.re
    from std import cgi

  24. Sashka говорит:

    А отсутствие унарного оператора инкремента/декремента? :-)

    А что же таки мешает выбрать язык/технологию по задаче/вкусу? Нравится питон - пользуй питон. Хочешь статики и модных иде - возьми жабу с нетбинсом. Со тредами - туда же :-) И с удобными гуями. Нужна скорость - сиплюсы юзай. Полностью, или только для модуля - согласно Ответственному Решению.

    Бывает, правда, заказчик диктует, на чем надо писать… Но даже тут можно найти компромис :-)

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

  25. motus говорит:

    многое из перечисленного на самом деле не проблемы питона. т.е. большую часть можно либо принять как фичу, либо списать как нечто, не относящееся к языку как к таковому. например, пресловутые пробелы это однозначно фича - без них питон не питон. отсутствие статической типизации - вещь полезная, но опять же, язык задумывался без нее, так что можно смириться. IDE, скорость, GIL - это все особенности окружения или конкретной реализации языка (пусть даже единственно кошерной реализации). аналогично, operator++() не меняет язык принципиально - ну будет он чуть ближе к С, и что?

    А вот что действительно раздражает - так это когда фича есть, и вроде полезная, но сделана настолько криво, что каждый раз морщишься, когда ее используешь. те же однострочные лямбды, или эти подчеркивания и self этот идиотский. и что интересно, все привыкают, и пользуются, и ходят, как клиенты от Levine the Genius Language Designer. впрочем, справедливости ради должен заметить, что в других подобных языках (ruby, perl) таких горбов куда больше, так что Pythonic Way это все-таки скорее хорошо, чем плохо, как мне кажется.

    отсутствие объявления локальных переменных, типа my в перле;

    о да. кривость питоновского пространства имен и поиска в нем это конечно горбуха номер раз в моем списке.

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

  26. Mourner говорит:

    А я в Python терпеть не могу __совершенно_омерзительные_конвеншны__ с использованием знака подчеркивания, отсутствие нормальной инкапсуляции и необходимость указывать self в качестве первого параметра любого метода.

  27. Макс Ищенко говорит:

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

  28. slav0nic говорит:

    мне вот не нравитcя отсутсвие полиморфизма как аткового и невозможность операции присвоения в условиях

  29. Сергей говорит:

    Спасибо, посмиялси =)

  30. oleg.noga говорит:

    * нет iif
    http://lambda-the-ultimate.org/node/1402#comment-16034
    * нет встроенной поддержки lazy evaluation выражений
    * dict.setdefault: аргумент default должен быть lazy evaluated

  31. Alexander Solovyov говорит:

    > терпеть не могу __совершенно_омерзительные_конвеншны__ с использованием знака подчеркивания

    Варианты? Вполне нормальная штука, имхо. Никак не мешает и не напрягает.

    > необходимость указывать self в качестве первого параметра любого метода.

    Это как раз плюс. Или надо иметь какие-то два магических типа функций? Одни - которые функции, вторые - которые методы? А у меня вот сейчас есть функция, которая одновременно служит в некоторых местах функцией, а в некоторых классах - методом. Что ты предлагаешь взамен?

  32. bialix говорит:

    * нет iif
    http://lambda-the-ultimate.org/node/1402#comment-16034
    * нет встроенной поддержки lazy evaluation выражений
    * dict.setdefault: аргумент default должен быть lazy evaluated

    Не так давно в комментах про обсуждение ФЯ некто указал, что мои вопросы про словари в Хаскеле сводятся к тривиальному “как писать на Хаскелле питон-программы”. Здесь аналогичный случай, только наоборот.

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

    Хотя, иногда костыли получаются очень даже ничего. Например, реализация ленивого импорта модулей: чтобы не импортировать сразу все, а только по мере надобности, это очень интересная вещь. Реализована (наверное первыми) в исходниках Mercurial, под названием demandload. Затем эту идею Джон Майнел из команды Bazaar перенес ее в базу кода bzr и попутно внес некоторые правильные изменения (модуль lazy_import). Так что (кому интересно) — можно и поглядеть.

  33. Сергей говорит:

    bialix, а для чего собственно Python недостаточно быстр? (Т.е. где же это lazy evaluation спасает ситуацию?)

  34. bialix говорит:

    bialix, а для чего собственно Python недостаточно быстр? (Т.е. где же это lazy evaluation спасает ситуацию?)

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

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

    Касательно lazy import. Как все знают при первом импорте модуль не только компилируется в байт-код, но и исполняется. Если в вашей программе куча импортируемых модулей, которые не обязательно испольуются все сразу, а некоторые операции вообще нуждаются в минимальном наборе импортируемых данных — вы получите большой оверхед при старте приложения. Чтобы уменьшить этот оверхед целесообразно использовать ленивый импорт.

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

  35. koder говорит:

    Всем любителям lazy_somethig посвящается ;)))

    1) lazy_import - идея неплохая но, к сожалению, __очень__ слабо применимая,
    причем ее обязательно нужно делать “вручную”, автоматически питон это не сделает.
    Причины следующие:
    а)Зачастую импорт идет не import something, а from something import x,y,z
    как легко понять никакой lazy в таком случае не поможет.
    б)Некоторые модули делают разные умные(или не очень ;) вещи при импорте, которые должны
    быть сделаны именно в момент импорта. Например модифицируют
    стек обработчиков urllib2, или добавляют onexit функции, устанавливают
    перехватчики исключений,etc.
    Отдельный прикол такое -
    …..

    try:
    if dt == nnn:
    import XXX
    except:
    sys.stderr.write("Can't load appropriate plugin for nnn exit.")
    sys.exit(1)

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

    try:
    import XXX
    except ImportError:
    try:
    import YYY as XXX
    except ImportError:
    XXX = Default

    Иначе говоря если модуль импортируется - он должен быть исполнен, поскольку
    компилятор не способен определить имеется ли внутри модуля зависимость от
    порядка загрузки и т.п.
    2) lazy_evaluated данные.
    Тут все сложнее, если сразу - то они автоматиски совсем никак не возможны,
    а неавтоматически Вы можете сделать их сами, только толк от них будет в
    крайне редких случаях.
    Код примерно такой:

    class Lazy(object):
    def __init__(self,f,*dt,**mp):
    self._func_ = [f,dt,mp]
    def __getattr__(self,name):
    try:
    return getattr(self.__dict__['_x_'],name)
    except KeyError:
    self._x_ = self._func_[0](*(self._func_[1]),**(self._func_[2]))
    return getattr(self.__dict__['_x_'],name)
    c = Lazy(lambda : [])
    print c.append
    print c.append(1)

    Код очень примерный, для толковой работы нужно перегрузить
    почти все остальные специальные методы в классе X и все равно
    грабли останутся. К тому-же видно что на каждое обращение
    к аттрибуту объекта есть весьма основательные накладные расходы.
    Есть еще вариант модификации вверхлежашего локального скопа
    с заменой там себя, примерно так:

    import sys
    class Lazy(object):
    def __init__(self,f,*dt,**mp):
    self._func_ = [f,dt,mp]
    def __getattr__(self,name):
    if ‘_x_’ not in self.__dict__:
    self._x_ = self._func_[0](*(self._func_[1]),**(self._func_[2]))
    _lk = sys._getframe(1).f_locals
    keys = list(_lk.keys())
    for i in keys:
    if self is _lk[i]:
    break
    _lk[i] = self._x_
    return getattr(self.__dict__['_x_'],name)
    #Это тоже нужно основательно дописывать, но идея видна
    c = Lazy(lambda : [])
    print c
    print c.append
    print c
    print c.append(1)

    Это гораздо быстрее, но имеет одну важную проблему(см. ниже).
    Но в обоих случаях остаются следующие грабли:
    1)Невозможно перехватить обращение к специальным аттрибутам
    __dict__,__slots__,__str__,etc. А это широко используется
    т.н. pythonic кодом.
    2)Такие объекты будут очень плохо дружить с C-кодом,
    точнее первый вариант кое-как, а второй вообще никак,
    т.к. он промодифицирует питоновский локальный скоп,
    что на C объекте никак не отразится.
    3)Основная проблема - невозможность перехватить операции
    and,or,not,is + ф-ции type,isinstance,etc.
    Отдельный прикол - оператор =. Можно написать
    x = my_lazy_object
    y = my_lazy_object
    …..
    Это все - дополнительные минусы в копилку второго варианта,
    т.к. каждый их x,y,.. будет лезть в скоп наверх и там себя
    по разу тыкать.
    Других способов сейчас AFAIK быть не может.

    По поводу изменения компилятора с целью поддержки lazy_objects.
    Это так-же имеет вагон проблем, сходных с предыдущими + еще вагончик(
    очень долго все описывать - не буду здесь) + две полные
    “бяки”, а именно как бы Вы не внесли lazy в интерпретатор Вы замедлите
    работу с non-lazy объектами из-за необходимости из С-кода
    проверять “А не с lazy ли это мы сейчас работаем”. Плюс куча проблем
    по отслеживанию, где же именно lazy нужно расчитать и подставить.
    Не стоит сравнивать питон с лиспом - он __совсем__ другой и то
    что лиспу хорошо потону надо еще переварить.

    И на последок - всем советчикам по кардинальному улучшению питона.
    Оформите свои предложения на английском и запостите в python-dev
    рассылку, а мы посмеемся читая комментарии к этому посту ;)).
    Или просто последите за python-dev с полгода и мысли типа
    “а я вот тут такую клевую штуку придумал - вот бы ее в питон засунуть,
    а то они там дураки сами-то еще за 15 лет не дошли”
    будут основательно фильтроваться минимум недельным обдумыванием.

  36. koder говорит:

    Блин, пробелы в коде съелись (((. Но, имхо, для истинных питонеров,
    их восстановить не проблема. )

  37. Deepwalker говорит:

    А все таки GIL. Если запускать отдельный питоновский процесс, то сколько памяти съест каждый такой процесс?

  38. bialix говорит:

    Товарищ koder привел мощную критику lazy_something, однако он глубко не вникал, поэтому она хоть и кажется правдоподобной. но таковой не всегда является.

    1) lazy_import - идея неплохая но, к сожалению, __очень__ слабо применимая,
    причем ее обязательно нужно делать “вручную”, автоматически питон это не сделает.

    Нет, не сделает. В самом питоне оно не встроено, поэтому не сделает. В проекте Базар ленивый импорт делается так:
    from brzlib import lazy_import
    lazy_import.lazy_import("""
    from bzrlib import error, osutils
    """)

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

    а)Зачастую импорт идет не import something, а from something import x,y,z
    как легко понять никакой lazy в таком случае не поможет.

    Как показано в примере выше — помогает. Замечание мимо кассы.

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

    Пример неудачный. Чем ленивый импорт в этом случае будет отличаться от импорта скажем внутри какой-то функции?
    def foo(arg):
    import spam
    return spam.eggs(arg)

    try:
    if dt == nnn:
    import XXX
    except:
    sys.stderr.write(”Can’t load appropriate plugin for nnn exit.”)
    sys.exit(1)

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

    Делать sys.exit(1) только потому, что что-то не импортируется — это плохой стиль. Замечание опять же мимо кассы, потому что ленивый импорт следует применять тогда, когда он нужен, а не где попало.

    в)Автоматическим lazy_import невозможно такое обработать
    (приведен упрощенный пример, все может быть гораздо хуже)

    Ленивый импорт предназнаен для другого. Ловить ImportError — это когда вы не знаете загрузится какая-то внешняя либа или нет. В проекте Базар лениво импортируются только внутренние модули, отстствие которых означает, что у вас поломанная инсталляция или ваш диск начал сдыхать.

    2) lazy_evaluated данные.
    Тут все сложнее, если сразу - то они автоматиски совсем никак не возможны,
    а неавтоматически Вы можете сделать их сами, только толк от них будет в
    крайне редких случаях.

    Удивительно, и для чего же в Питоне duck-typing??? Подменить в ран-тайме даже один класс другим можно, а вы вот так, с места в карьер. В вашем примере не хватает одной малости. Lazy данные так всегда и остаются lazy. И все время будет срабатывать __getattr__. Lazy должен быть временным промежуточным объектом, который подменяется на реальный при первом обращении. Например, смотрите в исходниках Базар модуль lazy_regexp, который позволяет откладывать компиляцию регулярного выражения до первого использования.

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

    И на последок - всем советчикам по кардинальному улучшению питона.
    Оформите свои предложения на английском и запостите в python-dev

    Да, это ценное предложение. Учитывая, что патчи для исправления ошибок в самом питоне (не добавление новой функциональности!) лежат годами на sf.net, а теперь в новом раундап трекере, то, да, кардинально улучшать питон бессмысленная затея. В проекте Базар никтоне ставит перед собой такую задачу. Нам нужно, чтобы Базар работал как задумано. Поэтому мы сами переписываем неустраивающие части питона под себя. Никто в python-dev никакие депеши не шлет.

Оставить комментарий

Указать свой сайт могут только зарегистрированные пользователи. Регистрация или вход.

Архив

Вакансии rss icon

Все вакансии

Комментарии