Каковы недостатки Python? [закрыто]

147

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

Итак, что бы на ваш взгляд объективных недостатков Python.

Примечание: я не прошу здесь сравнение языков (то есть C # лучше, чем Python, потому что ... yadda yadda yadda) - более объективное (до некоторого уровня) мнение о том, какие особенности языка плохо разработаны, будь то, что может быть некоторые вам не хватает в этом и так далее. Если необходимо использовать другой язык для сравнения, но только для иллюстрации того, что было бы трудно развить в другом случае (например, для простоты понимания)

Ладья
источник
50
Я думаю, что это полезный субъективный вопрос, и было бы стыдно закрыть его.
Эрик Уилсон
25
Кажется, здесь есть фанат-питон, который просто отрицает все ответы на анти-питоне.
Зврба
2
@ TMN: Это все еще рассматривает пробелы как токены, просто не возвращая их - и это точно, что делает грамматику Python тоже.
9
@ Роджер: соглашение по SO - комментировать отрицательные голоса. Так как это сайт для субъективных мнений, я не вижу причин для отрицательных голосов, особенно без комментариев. Итак, я поддерживаю свое «обзывание».
zvrba 29.10.10
8
@zvrba: Downvotes по-прежнему означает «не полезно», как всегда.

Ответы:

109

Я использую Python несколько регулярно, и в целом я считаю, что это очень хороший язык. Тем не менее, ни один язык не идеален. Вот недостатки в порядке важности для меня лично:

  1. Это медленно. Я имею в виду очень, очень медленно. Много раз это не имеет значения, но это определенно означает, что вам понадобится другой язык для этих критичных для производительности битов.

  2. Вложенные функции отстой в том, что вы не можете изменять переменные во внешней области видимости. Изменить: Я все еще использую Python 2 из-за поддержки библиотеки, и этот недостаток дизайна раздражает меня, но, видимо, это исправлено в Python 3 из-за нелокальной инструкции. Не могу дождаться портирования библиотек, которыми я пользуюсь, так что этот недостаток может быть навсегда отправлен в кучу пепла истории.

  3. В нем отсутствуют некоторые функции, которые могут быть полезны для библиотечного / универсального кода, и ИМХО простота доведена до нездоровых крайностей. Наиболее важные из них, которые я могу придумать, - это определяемые пользователем типы значений (я предполагаю, что они могут быть созданы с помощью магии метакласса, но я никогда не пробовал), и параметр функции ref.

  4. Это далеко от металла. Нужно написать потоковые примитивы или код ядра или что-то еще? Удачи.

  5. Хотя я не возражаю против отсутствия возможности улавливать семантические ошибки заранее в качестве компромисса за динамизм, который предлагает Python, мне бы хотелось, чтобы существовал способ отлавливать синтаксические ошибки и глупые вещи, такие как ошибочные имена переменных, без необходимости фактически запускать код.

  6. Документация не так хороша, как языки типа PHP и Java, которые имеют сильную корпоративную поддержку.

димча
источник
60
@ Кейси, я должен не согласиться. Индекс ужасен - попробуйте поискать withутверждение или методы на list. Все, что описано в руководстве, в основном не поддается исследованию. Мне повезло больше с документацией Microsoft для C ++.
Марк Рэнсом
17
Около 5 - просто используйте pyflakes. Это написано, чтобы поймать именно эти ошибки.
Александр Соловьев
4
Что касается скорости: с ростом PyPy многие пользователи Python теперь смогут справиться с проблемой скорости, просто используя интерпретатор со встроенным JIT-компилятором (на данный момент пользователи Python 3 и пользователи модулей расширения C не обрабатываются cpyext нет такой опции).
ncoghlan
29
Я презираю документы по Python. Конечно, они красивее, чем большинство, но много раз много полезной информации сводится на одной странице, например, методы для строк и списков - и все типы последовательностей также объединяются. Когда я ищу эту информацию, я просто попадаю на огромный том, и мне приходится искать вниз по странице, чтобы найти то, что я хочу. Я также нахожу индекс на этих страницах трудным для чтения, и иногда трудно сказать, какой раздел я хочу.
Карсон Майерс
5
Как расстояние от металла может быть аргументом? Python когда-либо подразумевал себя системным языком?
Марк Канлас
66

Я ненавижу, что Python не может различить объявление и использование переменной. Вам не нужна статическая типизация, чтобы это произошло. Было бы неплохо иметь способ сказать: «Это переменная, которую я намеренно объявляю, и я собираюсь ввести новое имя, это не опечатка».

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

Однако я не могу задокументировать этот факт. Ничто в Python не мешает мне перезаписывать или повторно использовать переменные.

Таким образом, я хотел бы иметь два ключевых слова на языке: varи let. Если я пишу в переменную, не объявленную ни одним из них, Python должен вызвать ошибку. Кроме того, letобъявляет переменные только для чтения, в то время как varпеременные являются «нормальными».

Рассмотрим этот пример:

x = 42    # Error: Variable `x` undeclared

var x = 1 # OK: Declares `x` and assigns a value.
x = 42    # OK: `x` is declared and mutable.

var x = 2 # Error: Redeclaration of existing variable `x`

let y     # Error: Declaration of read-only variable `y` without value
let y = 5 # OK: Declares `y` as read-only and assigns a value.

y = 23    # Error: Variable `y` is read-only

Обратите внимание, что типы все еще неявные (но letпеременные для всех намерений и целей статически типизированы, поскольку они не могут быть привязаны к новому значению, в то время как varпеременные все еще могут быть динамически типизированы).

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

def foo(bar = None):
    if bar == None: bar = [1, 2, 3]

Это может быть заменено немного другой идиомой:

def foo(bar = None):
    let mybar = bar or [1, 2, 3]
Конрад Рудольф
источник
6
Мне бы так хотелось, чтобы в Python было выражение "var". Помимо (очень хорошей) причины, по которой вы заявляете, это также облегчит чтение кода, потому что тогда вы можете просто просмотреть страницу, чтобы найти все объявления переменных.
Джоккинг
25
Как будто разработчики Python игнорировали уроки прошлого. Не объявлять переменные, не объявлять функции - ошибка, впервые совершенная в 1950-х годах. Те трудно найти ошибки, которые возникли из-за трудно опознаваемой опечатки, были достаточно удивительно впервые сделаны в 1950-х. Эта языковая ошибка была сделана (и позже исправлена) снова и снова. Объявление переменных не является огромным бременем. Это спасло мой приклад несколько раз. Я неизбежно use strict;и use warnings;в perl на скрипте любого размера. Python лишил разработчика слишком большого количества средств отладки.
Дэвид Хаммен
19
@David, чтобы быть справедливым по отношению к python, он вызовет исключение, если вы попытаетесь получить доступ к переменной, которая не была назначена. Многие языки, в которых отсутствуют объявления, будут возвращать какое-то значение по умолчанию. В результате версия Python гораздо менее проблематична, чем те.
Уинстон Эверт
1
@yi_H Предложение не должно быть обратно совместимым - или даже реальное предложение. Вопрос заключался в том, «каковы недостатки Python»… ну, не имея varи let(или подобный механизм) является недостатком. Другими словами: будь я дизайнером Python, я бы сделал что-то подобное. Тем не менее , будущие версии могут включать это при загрузке специального пакета (аналогично __future__). Скажем, import strict. Это не произойдет, хотя, так как это требует синтаксических хаков ...
Конрад Рудольф
3
+1 Для добавления лучших «функциональных» возможностей программирования.
Эван Плейс
44

Моя главная жалоба - это многопоточность, которая во многих случаях не так эффективна (по сравнению с Java, C и другими) из-за глобальной блокировки интерпретатора (см. Доклад «Внутри Python GIL» (ссылка на PDF) )

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

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

Также вы можете поймать много ошибок во время выполнения Pylint .

Casey
источник
2
+1 за пилинт. Я не знал об этом. В следующий раз, когда я сделаю проект на Python, я попробую его. Кроме того, многопоточность работает нормально, если вы используете Jython вместо эталонной реализации CPython. OTOH Jython несколько медленнее, чем CPython, поэтому это может частично победить цель.
дсимча
3
Потоки не очень хорошо поддерживаются? Библиотеки потоков были там еще до 2.1.
rox0r
2
Я знаю, что есть поддержка потоков, но по сравнению с Java или C, GIL действительно снизит вашу производительность. Вот почему многопроцессорный модуль предпочтительнее многопоточности.
cmcginty
2
Документация хороша, если вам удастся ее найти. Googling Java классы намного проще, чем Python.
Брендан Лонг
@Casey Я уточнил формулировку в ответе, поскольку многопоточность поддерживается, просто демонстрирует некоторую странную производительность (добавил ссылку и несколько ссылок на документы)
dbr
28

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

Иаков
источник
5
Это правильно, хотя существуют инструменты, такие как PyChecker, которые могут проверять на ошибки компилятор в таких языках, как C / Java.
Оливер Вейлер
24
Динамическая типизация - это осознанное дизайнерское решение, а не недостаток.
фактор
14
Это то же самое, что сказать, что слабым местом Java является отсутствие динамической типизации.
МАК
12
@missingfaktor, @MAK, очевидно, что вводить утку было намечено . Но большинство проектных решений имеют объективные преимущества и недостатки. Добавленная гибкость кода является преимуществом динамической типизации, а дополнительные классы потенциальных ошибок времени выполнения являются недостатком. Субъективная часть - стоит ли эта функция.
Джейкоб
6
Отсутствие статической типизации облегчает программистам написание кода с ошибками во время выполнения. В C # int foo = 4; Console.Write(foo.Length);не компилируется, поэтому ошибка «Int32 не имеет свойства Length» не может случайно попасть в опубликованное программное обеспечение. В python, если вы не запускаете дополнительные вспомогательные инструменты для поиска подобных ошибок, код, который обращается к несуществующим членам объектов, может остаться незамеченным, пока не закончится, вызывая ошибки времени выполнения.
Джейкоб
27

Я думаю, что объектно-ориентированные части Python чувствуют себя как-то «на болтах». Можно сказать, что необходимость явно передавать «я» каждому методу является признаком того, что его ООП-компонент не был явно спланирован ; это также показывает иногда бодрые правила обзора Python, которые были раскритикованы в другом ответе.

Редактировать:

Когда я говорю, что объектно-ориентированные части Python чувствуют себя «запертыми», я имею в виду, что время от времени ООП кажется довольно непоследовательным. Возьмем, к примеру, Ruby: в Ruby все является объектом, и вы вызываете метод, используя знакомый obj.methodсинтаксис (за исключением, конечно, перегруженных операторов); в Python все тоже объект, но некоторые методы вы вызываете как функцию; т. е. вы перегружаете, __len__чтобы вернуть длину, но вызываете ее, используя len(obj)вместо более привычного (и непротиворечивого) obj.lengthобщего в других языках. Я знаю, что есть причины этого дизайнерского решения, но они мне не нравятся.

Кроме того, в модели ООП Python отсутствует какая-либо защита данных, т. Е. Нет частных, защищенных и открытых членов; Вы можете имитировать их, используя методы _и __перед ними, но это отчасти уродливо. Точно так же Python не совсем правильно понимает аспект передачи сообщений в ООП.

оборота мипади
источник
17
Параметр self просто делает явным то, что другие языки оставляют неявным. Эти языки явно имеют параметр «я».
13
@Roger Pate: Да, но эта явная потребность в «себе» немного раздражает (и, я бы сказал, дырявая абстракция). Это также не было преднамеренным дизайнерским решением, но из-за «странных» правил Python. Я не могу быстро найти статью, но есть электронное сообщение от Гвидо ван Россума, в котором хорошо объясняется, почему требуется параметр «self».
Мипади
2
@Roger Pate: в объектно-ориентированных языках передача цели в качестве первого параметра все еще может рассматриваться как деталь реализации. Моя точка зрения, однако, не в том, хорошая это идея или нет; Дело в том, что в Python это связано не с осознанным дизайнерским решением, а скорее с обходом бородавок в области видимости.
Mipadi
3
@mipadi: Обновление более обосновано (поэтому я уберу понижение), но если вы рассматриваете len как оператор, который вы перегружаете, это больше OO в Python. Хотелось бы увидеть пример или рассуждения о том, как Python неправильно передает передачу сообщений.
8
Явное «я» является результатом того факта, что методы - это просто функции (и, как заметил Уинстон, неявные объявления локальных переменных). Вы можете не любить это дизайнерское решение, но глупо называть ООП «болтовым» на языке, где все доступно как объект во время выполнения.
ncoghlan
19

Что мне не нравится в Python:

  1. Threading (я знаю, что это уже упоминалось, но стоит упомянуть в каждом посте).
  2. Нет поддержки многострочных анонимных функций ( lambdaможет содержать только одно выражение).
  3. Отсутствие простой , но мощный вход чтения функции / класса (как cinи scanfв C ++ и C или Scannerв Java).
  4. Все строки не являются Unicode по умолчанию (но исправлены в Python 3).
MAK
источник
5
Что касается (2), я думаю, что это компенсируется возможностью иметь вложенные функции.
Конрад Рудольф
3
@KonradRudolph Моя главная проблема с вложенными функциями вместо многострочных лямбд - это то, что порядок чтения меняется местами.
CookieOfFortune
2
@wkschwartz: raw_inputи 'sys.stdin' довольно скелеты. Они не поддерживают форматированный ввод (например, что-то вроде «% d:% d:% d»% (часы, минуты, секунды) для чтения во времени). Пока что в Python нет ничего похожего на функциональность scanf (в C) или Scanner (Java).
MAK
2
@limscoder: в Java все строки по умолчанию имеют юникод. Я не вижу веской причины иметь отдельные классы str и unicode. ИМХО, строки и массивы байтов не должны быть представлены одной и той же абстракцией. Строковый класс должен быть предназначен для хранения и манипулирования текстом - о внутреннем представлении которого мы на самом деле не заботимся. Мы не должны хотеть делать такие вещи, как усечение / замена / удаление / вставка для определенного байта в строке - мы хотим сделать это для определенного символа . Легко забыть это различие, и ваш код будет взорван при вводе неанглийского ввода.
MAK
1
@limscoder: если вы хотите увидеть легкий юникод, попробуйте Tcl. Несколько лет назад мне пришлось переключиться с Tcl на Python, и я был удивлён тем, насколько сравнительна поддержка юникода примитивного python. Это действительно невидимо в Tcl, и основная боль в питоне.
Брайан Оукли
18

Аргументы по умолчанию с изменяемыми типами данных.

def foo(a, L = []):
    L.append(a)
    print L

>>> foo(1)
[1]
>>> foo(2)
[1, 2]

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

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

def foo(a, L = None):
    if L is None:
        L = []
    ...

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

оборота Йтернберг
источник
Я вижу много жалоб по этому поводу, но почему люди настаивают на том, чтобы в качестве аргумента по умолчанию был пустой список (который модифицируется функцией)? Это действительно такая большая проблема? Т.е. это реальная проблема?
Мартин Вилканс
8
Это нарушает принцип наименьшего удивления. Нельзя ожидать, что параметры функции выживут при вызовах.
AIB
Это следствие того, что он является языком сценариев. Вы будете только озадачены этой ошибкой ОДНАЖДЫ, и никогда больше. Выяснение этой ошибки на самом деле дает вам толчок, чтобы напомнить вам, что да, это все еще язык сценариев. И это только потому, что язык настолько хорош, что скрывает аспект сценариев (при условии, что вы используете его правильно).
Зоран Павлович
@ZoranPavlovic из любопытства, почему это является следствием того, что он является языком сценариев? Кажется, проблема в том, когда данные связаны и списки изменчивы (это две вещи, которые обычно хороши, но в итоге оказываются плохими при объединении). Та же проблема может возникнуть в языке без сценариев, если вы связываете данные во время создания функции, а не создаете новый список при каждом вызове функции.
Йтернберг
@aib: я так не думаю - параметр здесь, как и любой другой объект Python, - это указатель на объект. В этом случае объект является изменяемым, и переменная связывается при объявлении функции. Параметр «выживает через вызовы», но выживает ссылка на изменяемый объект.
Патрик Коллинз
14

Некоторые из возможностей Python, которые делают его настолько гибким, как язык разработки, также рассматриваются как основные недостатки тех, которые используются для статического анализа «всей программы», проводимого процессом компиляции и компоновки в таких языках, как C ++ и Java.

  • Неявное объявление локальных переменных

Локальные переменные объявляются с использованием обычного оператора присваивания. Это означает, что привязки переменных в любой другой области требуют, чтобы компилятор подобрал явную аннотацию (глобальные и нелокальные объявления для внешних областей, нотация доступа к атрибутам для областей экземпляров). Это значительно уменьшает количество шаблонов, необходимых при программировании, но означает, что сторонние инструменты статического анализа (такие как pyflakes) необходимы для выполнения проверок, которые обрабатываются компилятором в языках, которые требуют явного объявления переменных.

  • «Обезьяны патчинг» поддерживается

Содержимое модулей, объектов класса и даже встроенное пространство имен могут быть изменены во время выполнения. Это очень мощный инструмент, позволяющий использовать множество чрезвычайно полезных техник. Однако такая гибкость означает, что Python не предлагает некоторые функции, общие для статически типизированных ОО-языков. В частности, параметр «self» для методов экземпляра является явным, а не неявным (поскольку «методы» не нужно определять внутри класса, их можно добавить позже, изменив класс, что означает, что он не особенно практичен передать ссылку на экземпляр неявно), а управление доступом к атрибуту не может быть легко реализовано в зависимости от того, находится ли код «внутри» или «снаружи» класса (так как это различие существует только во время выполнения определения класса).

  • Вдали от металла

Это также верно для многих других языков высокого уровня, но Python имеет тенденцию абстрагироваться от большинства аппаратных деталей. Языки системного программирования, такие как C и C ++, по-прежнему гораздо лучше подходят для обработки прямого доступа к оборудованию (однако, Python с радостью будет общаться с ними либо через модули расширения CPython, либо, что более удобно, через ctypesбиблиотеку).

оборота нкоглан
источник
12
  1. Использование отступов для блоков кода вместо {} / begin-end, что угодно.
  2. Каждый новый современный язык имеет правильную лексическую область видимости, но не Python (см. Ниже).
  3. Хаотичные документы (сравните с документацией Perl5, которая превосходна).
  4. Смирительная рубашка (есть только один способ сделать это).

Пример для разбитой области видимости; стенограмма с сессии переводчика:

>>> x=0
>>> def f():
...     x+=3
...     print x
... 
>>> f()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment

globalи nonlocalключевые слова были введены, чтобы исправить эту глупость дизайна.

zvrba
источник
2
Что касается области видимости, для любопытных, возможно, стоит заглянуть на python.org/dev/peps/pep-3104, чтобы понять обоснование текущего метода.
Уинстон Эверт
Согласна с +1. Итак, +1.
Jas
34
Наличие одного способа сделать это является преимуществом. Когда вы читаете чужой код, вы не можете расшифровать ни одного утверждения. Как только идиомы запрограммированы в вашем мозгу, вы должны получить мгновенное признание.
rox0r
9
Полностью согласен с @ rox0r. «Прямая куртка» предотвращает любые синтаксические войны.
Keithjgrant
8
Если честно, мне очень редко нужны ключевые слова globalили nonlocalв Python. Настолько редко, что я забываю, что эта проблема существует, и приходится пересматривать ее несколько раз, несмотря на то, что я пишу код Python каждый день на работе. Для меня код, который должен изменять глобальные переменные (или, что еще хуже, внешние неглобальные переменные) - это запах кода. Там обычно (не всегда) лучший способ.
Бен
11

Я считаю, что сочетание Python объектно-ориентированного this.method()и процедурного / функционального method(this)синтаксиса очень тревожно:

x = [0, 1, 2, 3, 4]
x.count(1)
len(x)
any(x)
x.reverse()
reversed(x)
x.sort()
sorted(x)

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

По крайней мере, функциональные языки, такие как F #, имеют все функции, правильно расположенные в модулях:

List.map(x)
List.reversed(x)
List.any(x)

Так что они не все вместе. Кроме того, это стандарт, которому следуют во всей библиотеке, так что, по крайней мере, он соответствует.

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

x.count(1)
x.len()
x.any()
x.reverse()
x.reversed()
x.sort()
x.sorted()

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

  • Единственное место для поиска «общих» операций над типом данных: другие библиотеки / и т. Д. могут иметь другие причудливые действия, которые они могут делать с типами данных, но все операции «по умолчанию» находятся в методах объекта.
  • Не нужно повторять Moduleпри звонке Module.method(x). Если взять приведенный выше пример функционального списка, почему я должен повторять Listснова и снова? Он должен знать, что это Listи я не хочу вызывать Navigation.map()функцию! Использование x.map()синтаксиса делает его СУХИМЫМ и все еще однозначным.

И, конечно, имеет преимущества по сравнению с пут-все , в-глобальном пространстве имен- способ сделать это. Дело не в том, что нынешний способ неспособен добиться цели. Это даже довольно кратко ( len(lst)), так как ничто не является пространством имен! Я понимаю преимущества использования функций (поведение по умолчанию и т. Д.) Перед методами, но мне все еще не нравится это.

Это просто грязно. А в больших проектах грязь - твой злейший враг.

оборота Хаойи
источник
1
да ... я действительно скучаю по стилю LINQ (я уверен, что LINQ не первый, кто реализует его, но я больше всего знаком с ним), обработка списка.
CookieOfFortune
1
Не думайте о len (x) как о методе. «лен» - это функция. У Python есть функции и методы, и я не вижу ничего плохого в этом подходе. Нехватка правильных функций, как правило, является источником множества ненужных печатаний.
rbanffy
Я знаю len(), это функция, и каковы преимущества. Я также заявил, почему я считаю, что это плохая идея, почему я считаю, что глобальные функции - это особенно плохая идея, и почему я считаю, что методы предоставляют удобный метод организации и определения объема вашей функциональности =)
Haoyi
Я не думаю, что 42 (или это 43?) Ключевых слова - это «большое» число. Это также включает в себя такие вещи , как def, classи другие вызовы , не функции. Сравните это со 100+ в большинстве других популярных языков. Кроме того , рассмотрим линию от import this: Namespaces are one honking great idea -- let's do more of those!. Я думаю, что вы можете неправильно понять пространства имен Python;)
Уэйн Вернер
8

Отсутствие гомойконичности .

Python должен был ждать 3.x, чтобы добавить ключевое слово «with». На любом гомоиконическом языке его можно было бы добавить в библиотеку.

Большинство других вопросов, которые я видел в ответах, относятся к одному из 3 типов:

1) Вещи, которые можно исправить с помощью инструментов (например, pyflakes) 2) Детали реализации (GIL, производительность) 3) Вещи, которые можно исправить с помощью стандартов кодирования (т. Е. Функции, которые люди не хотели бы видеть)

# 2 не проблема с языком, IMO # 1 и # 3 не являются серьезными проблемами.

Aidenn
источник
1
withбыл доступен из Python 2.5 с from __future__ import with_statement, но я согласен, я иногда с сожалением ifforprint
отмечал,
7

Python - мой любимый язык, так как он очень выразителен, но все же не дает вам совершать слишком много ошибок. У меня все еще есть несколько вещей, которые меня раздражают:

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

  • Некоторая путаница в отношении между модулями и файлами. Запуск «python foo.py» из командной строки отличается от «import foo». Относительный импорт в Python 2.x также может вызвать проблемы. Тем не менее, модули Python намного лучше, чем соответствующие функции C, C ++ и Ruby.

  • Явное self. Несмотря на то, что я понимаю некоторые причины этого, и хотя я использую Python ежедневно, я склонен делать ошибку, забывая об этом. Другая проблема заключается в том, что делать класс из модуля становится немного утомительно. Явное «я» связано с ограниченной областью видимости, на которую жаловались другие. Наименьшая область действия в Python - это область действия функции. Если вы сохраняете свои функции небольшими, как и должно быть, это само по себе не проблема, и IMO часто дает более чистый код.

  • Некоторые глобальные функции, такие как len, что вы ожидаете, чтобы быть методом (который на самом деле это за кадром).

  • Значительный отступ. Не сама идея, которая, на мой взгляд, хороша, но, поскольку это единственное, что не дает многим людям попробовать Python, возможно, Python будет лучше с некоторыми (необязательными) символами начала / конца. Игнорируя этих людей, я мог бы полностью жить с принудительным размером для отступа.

  • Что это не встроенный язык веб-браузеров, а не JavaScript.

Из этих жалоб только первая, которая меня беспокоит, и я думаю, что она должна быть добавлена ​​к языку. Другие довольно незначительны, за исключением последнего, что было бы здорово, если бы это случилось!

Мартин Вилканс
источник
+1 Меня интересует, писать ли, datetime.datetime.now()когда один проект может писать, datetime.nowа затем смешивать два проекта, один способ написания этого исключает другой, и, конечно же, этого не произошло бы в Java, которая не назвала бы модуль таким же, как файл (?) Если вы видите, как распространенный способ состоит в том, что модуль путает нас с файлом, когда оба применения практикуются и являются явными, selfя все еще пытаюсь понять, так как вызовы не имеют того же количества аргументов, что и функции. И вы могли бы подумать, что виртуальный питон работает медленно?
Никлас Розенкранц
Относительно вашей проблемы с явным ключевым словом self. Могу ли я предложить для этого хорошую IDE Python? Я знаю, что PyDev в Eclipse автоматически завершает собственную часть сигнатуры функции, если обнаруживает, что вы пишете внутри класса.
Зоран Павлович
5

Python не является полностью зрелым: на данный момент язык Python 3.2 имеет проблемы с совместимостью с большинством распространяемых в настоящее время пакетов (обычно они совместимы с Python 2.5). Это большой недостаток, который в настоящее время требует больше усилий для разработки (найдите необходимый пакет; проверьте совместимость; взвесите выбор не очень хорошего пакета, который может быть более совместимым; выберите лучшую версию, обновите ее до версии 3.2, что может занять несколько дней; затем начать делать что-то полезное).

Вероятно, в середине 2012 года это будет меньшим недостатком.

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

Достижение зрелости в одном главном смысле означает, что команда может использовать эту технологию и очень быстро работать и работать без скрытых рисков (включая проблемы совместимости). Сторонние пакеты python и многие приложения не работают под 3.2 для большинства пакетов сегодня. Это создает больше работы по интеграции, тестированию, повторной реализации самой технологии вместо решения стоящей перед вами проблемы == менее зрелой технологии.

Обновление за июнь 2013: у Python 3 все еще есть проблемы со зрелостью. Время от времени члены команды упоминают о необходимом пакете, а затем говорят «за исключением того, что это только для 2.6» (в некоторых из этих случаев я использовал обходной путь через сокет localhost, чтобы использовать пакет только для 2.6 с 2.6, а остальные наши инструменты остаются с 3.2). Даже MoinMoin, чистый вики Python, не написан на Python 3.

Джонатан Клайн IEEE
источник
2
Я согласен с вами только в том случае, если ваше определение зрелости не совместимо с версией, несовместимой по дизайну .
Чепанг
3
Я согласен, что два несовместимых потока Python - это проблема (хотя и понятно, почему это было сделано), но я не рассматриваю это как проблему «зрелости».
Уинстон Эверт
Зрелость в каком-то смысле означает, что команда может использовать эту технологию и очень быстро работать и работать без скрытых рисков (включая проблемы совместимости). Сторонние пакеты python и многие приложения не работают под 3.2 для большинства пакетов сегодня. Это создает больше работы по интеграции, тестированию, повторной реализации самой технологии вместо решения стоящей перед вами проблемы == менее зрелой технологии.
Джонатан Клайн IEEE
2
Тогда просто используйте Python 2.x. Вы знаете ... версия, которую используют все. Или прочитайте документацию по пакетам в течение 2 секунд, чтобы выяснить, с какими версиями он совместим.
Йстернберг
2
«То, что Python 3.0 был выпущен в течение некоторого времени, не означает, что вы должны использовать версию. Python 3.0 и 2.x разрабатываются одновременно. Я надеюсь, что в будущем мы все сможем использовать python 3.0, но сейчас использование 2.x - хорошее решение "-> Это 500-символьный способ сказать: он еще не зрел.
Джонатан Клайн IEEE
4

Область видимости Python сильно нарушена, что делает объектно-ориентированное программирование на Python очень неловким.

Мейсон Уилер
источник
8
можешь привести пример? (Я уверен, что вы правы, но я хотел бы привести пример)
Уинстон Эверт
24
Мне нравится Python, но я абсолютно презираю необходимость ставить self.перед каждой ссылкой свойство и метод экземпляра. Это делает невозможным использование Python для создания DSL, как это легко сделать в Ruby.
Адам Кроссленд
35
Я не нахожу себя неловко, мне нравится откровенность.
Уинстон Эверт
9
Я не понимаю, что же такого в явном «я». В C ++, Java и D люди часто делают условные переменные явными, так или иначе, по соглашению, например, ставя перед ними подчеркивание.
дсимча
7
Вы используете self в методах, отличных от их объявления: def foo (self), но self.foo (). Я нахожу эту смесь явного определения, но неявного закулисного материала не слишком симпатичной.
LennyProgrammers
4

Мои жалобы о Python:

  • ООП на болтах (подробности см. В ответе @ mipadi)
  • Сломанная реализация лямбд
  • Проблемы с областью
  • Нет постоянных коллекций в стандартной библиотеке
  • Плохая пригодность для встроенных DSL
missingfaktor
источник
Почему отрицательный голос?
фактор
Я не downvoter, но вы можете объяснить, почему вы думаете, что OO на болтах? У Python всегда было ОО, это основная часть языка.
Дейнит
Смотрите ответ @ mipadi.
фактор
4

Модификаторы доступа в Python не являются обязательными для исполнения - затрудняет написание хорошо структурированного, модульного кода.

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

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

Майки
источник
Таким образом, отсутствие контроля доступа - это плохо ... но явная область видимости записи переменных в любое нелокальное пространство имен тоже плохо?
ncoghlan
@ncoghlan: 1 - эта функция является стандартной во многих современных языках, в зависимости от того, как вы конфигурируете свой проект. 2 - Это под контролем программиста. 3 - не уверен, что в этом такого хорошего - вы можете легко управлять своей областью с помощью нескольких настроек проекта на большинстве скомпилированных языков / IDE. Если «мы все взрослые по согласию», мы должны иметь возможность принимать собственные решения и корректировать сферу в соответствии с нашим уровнем комфорта.
Вектор
2
Дело в том, что люди, требующие «принудительного контроля доступа», просят нас убрать одну из тех вещей, которые делают Python таким замечательным связующим языком: разработчикам преднамеренно сложно контролировать, как их код впоследствии используется. Какая основная часть шаблонов C ++ и Java предназначена исключительно для работы с принудительным контролем доступа? Я определенно могу понять людей, решивших не использовать Python по этим причинам, но статическое применение никогда не станет заменой строгого тестирования.
ncoghlan
1
@ncoghlan - для меня отличными особенностями Python являются элегантность синтаксиса и краткость - выразительность. И, как я уже сказал, область видимости имеет меньшее отношение к программистам, которые возятся с вещами, которые они не должны делать, чем к структуре и организации кода - поэтому концепция «соглашающихся взрослых» не имеет смысла. Я работаю над сложными проектами, а не над простыми утилитами и скриптами - код должен быть тщательно модульным и структурированным - модификаторы доступа являются одним из наиболее важных способов обеспечения этого.
Вектор
1
И обзор кода, обучение и анализ связи другие. На мой взгляд, принудительное управление доступом относится к той же категории, что и статическая типизация: они помогают обеспечить некоторую дополнительную уверенность в правильности (но не настолько, чтобы избежать необходимости в широком тестировании), но с высокой стоимостью в производительности разработки. (На практическом уровне элементы управления доступом к атрибутам класса также не соответствуют объектной модели Python, где методы - это просто обычные функции, извлекаемые из классов. Границы «внутри / снаружи» для классов на самом деле не существует, поэтому она не может быть принудительно)
ncoghlan
3
  1. Производительность не хорошая, но улучшается с Pypy,
  2. GIL предотвращает использование потоков для ускорения кода (хотя обычно это преждевременная оптимизация),
  3. Это полезно только для разработки приложений,

Но у него есть несколько замечательных возможностей:

  1. Это идеально подходит для RAD,
  2. С C легко взаимодействовать (и для C встроить интерпретатор Python),
  3. Это очень читабельно,
  4. Это легко учиться,
  5. Это хорошо задокументировано,
  6. Батареи действительно включены, стандартная библиотека огромна, а pypi содержит модули практически для всего,
  7. У него здоровое сообщество.
dan_waterworth
источник
Что вдохновило упомянуть о преимуществах? Вопрос по проблемам. В любом случае, что вы имеете в виду, это полезно только для разработки приложений? Какие еще программы есть? Для чего конкретно это не хорошо?
Чепанг
5
Я перечислил преимущества, потому что я думаю, что они перевешивают минусы. Вы когда-нибудь пытались реализовать модуль ядра Linux в Python.
dan_waterworth
3

Я предпочитаю Python, и первый недостаток, который приходит мне в голову, заключается в том, что при комментировании такого утверждения if myTest():вы должны изменить отступ всего исполняемого блока, что вам не нужно делать с C или Java. На самом деле, в python вместо того, чтобы комментировать предложение if, я начал комментировать его следующим образом: `if True: #myTest (), поэтому мне также не придется менять следующий блок кода. Поскольку Java и C не полагаются на отступы, это упрощает комментирование операторов в C и Java.

Никлас Розенкранц
источник
1
Вы бы серьезно отредактировали код C или Java, чтобы изменить уровень блока некоторого кода без изменения отступа?
Бен
4
@Ben Временно, да ...
альтернатива
1
@ben то же самое здесь.
Кристофер Махан
2
Я использую хитрость перехода if something()на if False and something(). Другой трюк - «закомментировать», используя многострочную строку.
Мартин Вилканс
1
@ Мартин Конечно! если Ложь ...
Кристофер Махан
3

Многократная отправка плохо интегрируется с установленной системой однократной отправки и не очень эффективна.

Динамическая загрузка является серьезной проблемой в параллельных файловых системах, где POSIX-подобная семантика приводит к катастрофическим замедлениям для операций с интенсивным использованием метаданных. У меня есть коллеги, которые сожгли четверть миллиона ядерных часов, просто получая Python (с numpy, mpi4py, petsc4py и другими модулями расширения), загруженными на 65-тысячные ядра. (Моделирование дало значительные новые научные результаты, поэтому оно того стоило, но это проблема, когда более одной барреля нефти сжигают, чтобы загрузить Python за один раз.) Неспособность связать статически вынудила нас пойти на большие усилия, чтобы получить разумное время загрузки в масштабе, включая исправление libc-rtld для обеспечения dlopenколлективного доступа к файловой системе.

Джед
источник
Вау, кажется, очень технически, у вас есть какие-либо справочные материалы, примеры, сообщения в блогах или статьи на эту тему? Интересно, могу ли я столкнуться с такими случаями в ближайшем будущем.
Винсент
Арон выступил с докладом на SciPy 2012 . Материал dlopenнаходится в нашей библиотеке collfs . Этот репозиторий также содержит дополнительные трюки zipimport, вдохновленные кэшированием пути Ашера Лэнгтона. Мы работаем над лучшим распространением и бумагой.
Джед
3
  • довольно много очень распространенных сторонних библиотек и программного обеспечения, которые широко используются, совсем не питонны. Несколько примеров: soaplib, openerp, reportlab. Критика выходит за рамки видимости, она там, она широко используется, но это делает питонскую культуру запутанной (это повреждает девиз, который гласит: «Должен быть один - и предпочтительно только один - очевидный способ сделать это»). Известные питонические успехи (такие как django или trac) кажутся исключением.
  • потенциально неограниченная глубина абстракции экземпляра, класса, метакласса концептуально прекрасна и уникальна. Но чтобы освоить его, вы должны глубоко знать интерпретатор (в каком порядке интерпретируется код Python и т. Д.). Он не широко известен и не используется (или не используется правильно), в то время как подобная чёрная магия, такая как дженерики C #, концептуально более запутанная (IMHO), кажется более широко известной и используемой пропорционально.
  • чтобы получить хорошее представление о памяти и поточной модели, вы должны иметь большой опыт работы с python, потому что нет полной спецификации. Вы просто знаете, что работает, может быть, потому что вы прочитали источники переводчика или испытали причуды и обнаружили, как их исправить. Например, есть только сильные или слабые ссылки, а не мягкие и фантомные ссылки java. В Java есть поток для сборки мусора, в то время как нет формального ответа о том, когда сборка мусора происходит в python; вы можете просто наблюдать, что сборка мусора не происходит, если не выполняется код на python, и сделать вывод, что это, вероятно, иногда происходит при попытке выделить память. Может быть сложно, когда вы не знаете, почему заблокированный ресурс не был выпущен (мой опыт по этому поводу был mod_python в freeswitch).

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

Винсент
источник
+1. Спецификация для памяти и многопоточность модели прямо на. Но FWIW, сборщик мусора Java, находящийся в потоке (и большинство всего остального в GC), не является аспектом языка Java или спецификаций виртуальных машин как таковых, но является вопросом конкретной реализации JVM. Однако основная Sun / Oracle JVM тщательно документирована в отношении поведения и конфигурирования GC в той степени, в которой опубликованы целые книги по настройке JVM. Теоретически можно документировать CPython одинаково, независимо от языковой спецификации.
Эндрю Янке
2
  • Странно ООП:
    • len(s)через __len__(self)и другие «особые методы»
    • дополнительные специальные методы, которые могут быть получены из других специальных методов ( __add__и __iadd__для +и +=)
    • self в качестве первого параметра метода
    • Вы можете забыть вызвать конструктор базового класса
    • нет модификаторов доступа (частный, защищенный ...)
  • нет постоянных определений
  • нет неизменности для пользовательских типов
  • GIL
  • низкая производительность, которая приводит к смешению Python и C и проблемам со сборками (поиск библиотек C, зависимостей платформы ...)
  • плохая документация, особенно в сторонних библиотеках
  • несовместимость между Python 2.x и 3.x
  • плохие инструменты анализа кода (по сравнению с тем, что предлагается для статически типизированных языков, таких как Java или C #)
Deamon
источник
5
Лично я считаю, что несовместимость между 2.x и 3.x - одно из самых больших преимуществ Python. Конечно, это тоже недостаток. Но смелость разработчиков нарушить обратную совместимость также означает, что им не нужно было бесконечно таскать с собой кучу денег. Больше языков нуждается в таком капитальном ремонте.
Конрад Рудольф
0

«Неизменность» - это не совсем сильная сторона. Числа AFAIK, кортежи и строки неизменяемы, все остальное (т.е. объекты) изменчиво. Сравните это с функциональными языками, такими как Erlang или Haskell, где все является неизменным (по крайней мере по умолчанию).

Тем не менее, неизменность действительно действительно сияет параллелизмом *, что также не является сильной стороной Python, так что, по крайней мере, это является следствием.

(* = Для придирки: я имею в виду параллелизм, который, по крайней мере, частично параллельный. Я думаю, Python в порядке с «однопоточным» параллелизмом, в котором неизменность не так важна. (Да, любители FP, я знаю, что неизменность отлично даже без параллелизма.))

Kosta
источник
0

Я хотел бы иметь явно параллельные конструкции. Чаще всего, когда я пишу список понимания, как

[ f(x) for x in lots_of_sx ]

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

Даже если CPython не может сделать это хорошо, когда мой f - чистый Python, подобное поведение может быть определено для использования другими реализациями.

rbanffy
источник
// порождаем кучу потоков // передаем очередь очереди во все потоки que.extend ([x для x в lots_of_sx]) que.wait () # Ожидание обработки всех lots_of_sx потоками.
Зоран Павлович
0

В Python нет оптимизации хвостового вызова, в основном по философским причинам . Это означает, что хвостовая рекурсия в больших структурах может стоить O (n) памяти (из-за ненужного стека) и потребует от вас переписать рекурсию как цикл для получения O (1) памяти.

a3nm
источник