Подтвердить что ты не робот

Ошибки дизайна Python

Некоторое время назад, когда я изучал Javascript, я изучал Javascript: хорошие части, и мне особенно понравились главы о плохих и уродливых частях. Конечно, я не согласен со всем, поскольку суммирование дефектов дизайна языка программирования в определенной степени субъективно - хотя, например, я думаю, что все согласятся с тем, что ключевое слово with было ошибкой в Javascript. Тем не менее, я считаю полезным читать такие обзоры: даже если кто-то не согласен, есть чему поучиться.

Есть ли запись в блоге или какая-нибудь книга, описывающая ошибки дизайна для Python? Например, я предполагаю, что некоторые люди посчитали бы отсутствие оптимизации хвостового вызова ошибкой; могут быть другие проблемы (или не проблемы), о которых стоит узнать.

4b9b3361

Ответ 1

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

Возможно, один из способов начать думать об этом - посмотреть на изменения языка с Python 2.x на 3.x. Некоторые люди, конечно, утверждают, что print как функция неудобна, в то время как другие считают ее улучшением. В целом, изменений не так много, и большинство из них довольно маленькие и тонкие. Например, map() и filter() возвращают итераторы вместо списков, range() ведет себя как xrange(), а методы dict такие как dict.keys() возвращают представления вместо списков. Затем есть некоторые изменения, связанные с целыми числами, и одно из больших изменений - обработка двоичных/строковых данных. Это теперь текст и данные, а текст всегда Unicode. Есть несколько синтаксических изменений, но они больше касаются согласованности, чем обновления всего языка.

С этой точки зрения, кажется, что Python был довольно хорошо разработан на уровне языка (синтаксиса и семантики) по крайней мере с 2.x. Вы всегда можете поспорить о блочном синтаксисе на основе отступов, но мы все знаем, что это ни к чему не приведет... ;-)

Другой подход - посмотреть, какие альтернативные реализации Python пытаются решить. Большинство из них так или иначе связаны с производительностью, некоторые проблемы с платформой, а некоторые добавляют или вносят изменения в сам язык для более эффективного решения определенных задач. Разгрузившаяся ласточка хочет значительно ускорить Python за счет оптимизации этапов байт-компиляции и выполнения. Stackless добавляет функциональность для эффективных многопоточных приложений, добавляя конструкции, такие как микропотоки и тасклеты, каналы, позволяющие двунаправленную связь с тасклетами, планируя запуск тасклетов совместно или превентивно, и сериализацию, чтобы приостановить и возобновить выполнение тасклетов. Jython позволяет использовать Python на платформе Java и IronPython на платформе .Net. Cython - это диалект Python, который позволяет вызывать функции C и объявлять типы C, позволяя компилятору генерировать эффективный код C из кода Cython. Shed Skin добавляет неявную статическую типизацию в Python и генерирует C++ для автономных программ или модулей расширения. PyPy реализует Python в подмножестве Python и изменяет некоторые детали реализации, такие как добавление сборки мусора вместо подсчета ссылок. Цель состоит в том, чтобы позволить языку Python и разработке реализации стать более эффективными благодаря языку более высокого уровня. Py V8 соединяет Python и JavaScript с помощью движка V8 JavaScript - можно сказать, что это решает проблему с платформой. Psyco - это особый тип JIT, который динамически генерирует специальные версии работающего кода для данных, которые в настоящее время обрабатываются, что может дать ускорение для вашего кода Python без необходимости написания оптимизированных модулей Си.

Что-то из этого можно сказать о текущем состоянии Python, взглянув на PEP-3146, в котором описывается, как Unladen Swallow будет объединен с CPython. Этот PEP принят и, таким образом, является решением разработчиков Python о том, какое наиболее целесообразное направление выбрать в данный момент. Обратите внимание, что это касается производительности, а не языка как такового.

Поэтому на самом деле я бы сказал, что основные проблемы проектирования Python находятся в области производительности, но это в основном те же проблемы, с которыми сталкивается любой динамический язык, и семейство языков и реализаций Python пытается решить эти проблемы. Что касается прямых ошибок проектирования, подобных перечисленным в Javascript: хорошие части, я думаю, что значение "ошибки" должно быть более четко определено, но вы можете проверить следующие мысли и мнения:

Ответ 2

Есть ли запись в блоге или какая-то книга, описывающая ошибки дизайна для Python?

Да.

Он назвал список Py3K обратно-несовместимых изменений.

Начните здесь: http://docs.python.org/release/3.0.1/whatsnew/3.0.html

Прочтите все примечания к выпуску Python 3.x для получения дополнительной информации о ошибках в Python 2.

Ответ 3

Мой самый большой peeve с Python - и тот, который на самом деле не рассматривался при переходе на 3.x, - это отсутствие правильных соглашений об именах в стандартной библиотеке.

Почему, например, модуль datetime содержит класс, называемый datetime? (Не говоря уже о том, почему у нас есть отдельные модули datetime и time, но также класс datetime.time!) Почему datetime.datetime в нижнем регистре, но decimal.Decimal - это верхний регистр? И, пожалуйста, скажите мне, почему у нас есть этот ужасный беспорядок в пространстве имен xml: xml.sax, но xml.etree.ElementTree - что там происходит?

Ответ 6

Мой личный язык - это имя, обязательное для lambdas/local functions:

fns = []
for i in range(10):
    fns.append(lambda: i)

for fn in fns:
    print(fn()) # !!! always 9 - not what I'd naively expect

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

В настоящее время вы должны обходить его, привязывая i к новому имени. Значение whos не изменяется, используя закрытие функции.

Ответ 7

Это скорее второстепенная проблема с языком, чем фундаментальная ошибка, но: переопределение свойств. Если вы переопределите свойство (используя геттеры и сеттеры), нет простого способа получение свойства родительского класса.

Ответ 8

Да, это странно, но я предполагаю, что вы получаете за переменные переменные.

Я думаю, причина в том, что "i" относится к коробке, которая имеет изменяемое значение, а цикл "for" изменит это значение с течением времени, поэтому при чтении значения поля позже вы получите единственное значение, которое осталось. Я не знаю, как можно было бы исправить это, не сделав его функциональным языком программирования без изменяемых переменных (по крайней мере, без неконтролируемых изменяемых переменных).

Обходной путь, который я использую, заключается в создании новой переменной со значением по умолчанию (значения по умолчанию оцениваются в DEFINITION time в Python, что раздражает в другое время), что приводит к копированию значения в новое поле:

fns = []
for i in range(10):
    fns.append(lambda j=i: j)

for fn in fns:
    print(fn()) # works

Ответ 10

Одна из вещей, которые я нахожу наиболее раздражающими в Python, - это использование writelines() и readlines() в файле. readlines() не только возвращает список строк, но также имеет \n символов в конце каждой строки, поэтому вы всегда должны делать что-то вроде этого, чтобы разделить их:

lines = [l.replace("\n", "").replace("\r", "") for l in f.readlines()]

И когда вы хотите использовать writelines() для записи строк в файл, вам нужно добавить \n в конце каждой строки в списке перед их написанием, например:

f.writelines([l + "\n" for l in lines])

writelines() и readlines() должны заботиться о концевых символах независимым от ОС образом, поэтому вам не придется иметь дело с ним самостоятельно.

Вы должны просто уйти:

lines = f.readlines()

и он должен возвращать список строк без символов \n или\r в конце строк.

Аналогично, вы должны просто уйти:

f.writelines(lines)

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

Ответ 12

Моя самая большая неприязнь - range(), потому что она не делает то, что вы ожидаете, например:

>>> for i in range(1,10): print i,
1 2 3 4 5 6 7 8 9

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

Ответ 13

Я думаю, что в python много странных вещей, так как они обрабатывают встроенные/константы. Как показано ниже:

True = "hello"
False = "hello"
print True == False

Что печатает True...

def sorted(x):
  print "Haha, pwned"

sorted([4, 3, 2, 1])

Lolwut? sorted - встроенная глобальная функция. Худшим примером на практике является list, который люди склонны использовать в качестве удобного имени для локальной переменной и в конечном итоге сбрасывают глобальное встроенное.