В наши дни Python кажется всем модным, и не без причины - потому что это действительно язык, с которым почти нравится получать решение новой проблемы. Но, как однажды сказал мудрец (называя его мудрым только потому, что я понятия не имею, кто на самом деле это сказал; не уверен, был ли он вообще таким мудрым), чтобы действительно знать язык, он не только знает его. синтаксис, дизайн и т. д., достоинства, но также и недостатки. Ни один язык не идеален, некоторые просто лучше других.
Итак, что бы на ваш взгляд объективных недостатков Python.
Примечание: я не прошу здесь сравнение языков (то есть C # лучше, чем Python, потому что ... yadda yadda yadda) - более объективное (до некоторого уровня) мнение о том, какие особенности языка плохо разработаны, будь то, что может быть некоторые вам не хватает в этом и так далее. Если необходимо использовать другой язык для сравнения, но только для иллюстрации того, что было бы трудно развить в другом случае (например, для простоты понимания)
Ответы:
Я использую Python несколько регулярно, и в целом я считаю, что это очень хороший язык. Тем не менее, ни один язык не идеален. Вот недостатки в порядке важности для меня лично:
Это медленно. Я имею в виду очень, очень медленно. Много раз это не имеет значения, но это определенно означает, что вам понадобится другой язык для этих критичных для производительности битов.
Вложенные функции отстой в том, что вы не можете изменять переменные во внешней области видимости. Изменить: Я все еще использую Python 2 из-за поддержки библиотеки, и этот недостаток дизайна раздражает меня, но, видимо, это исправлено в Python 3 из-за нелокальной инструкции. Не могу дождаться портирования библиотек, которыми я пользуюсь, так что этот недостаток может быть навсегда отправлен в кучу пепла истории.
В нем отсутствуют некоторые функции, которые могут быть полезны для библиотечного / универсального кода, и ИМХО простота доведена до нездоровых крайностей. Наиболее важные из них, которые я могу придумать, - это определяемые пользователем типы значений (я предполагаю, что они могут быть созданы с помощью магии метакласса, но я никогда не пробовал), и параметр функции ref.
Это далеко от металла. Нужно написать потоковые примитивы или код ядра или что-то еще? Удачи.
Хотя я не возражаю против отсутствия возможности улавливать семантические ошибки заранее в качестве компромисса за динамизм, который предлагает Python, мне бы хотелось, чтобы существовал способ отлавливать синтаксические ошибки и глупые вещи, такие как ошибочные имена переменных, без необходимости фактически запускать код.
Документация не так хороша, как языки типа PHP и Java, которые имеют сильную корпоративную поддержку.
источник
with
утверждение или методы наlist
. Все, что описано в руководстве, в основном не поддается исследованию. Мне повезло больше с документацией Microsoft для C ++.Я ненавижу, что Python не может различить объявление и использование переменной. Вам не нужна статическая типизация, чтобы это произошло. Было бы неплохо иметь способ сказать: «Это переменная, которую я намеренно объявляю, и я собираюсь ввести новое имя, это не опечатка».
Кроме того, я обычно использую переменные Python в стиле однократной записи, то есть я рассматриваю переменные как неизменяемые и не изменяю их после их первого назначения. Благодаря таким функциям, как понимание списка, это на самом деле невероятно просто и облегчает отслеживание потока кода.
Однако я не могу задокументировать этот факт. Ничто в Python не мешает мне перезаписывать или повторно использовать переменные.
Таким образом, я хотел бы иметь два ключевых слова на языке:
var
иlet
. Если я пишу в переменную, не объявленную ни одним из них, Python должен вызвать ошибку. Кроме того,let
объявляет переменные только для чтения, в то время какvar
переменные являются «нормальными».Рассмотрим этот пример:
Обратите внимание, что типы все еще неявные (но
let
переменные для всех намерений и целей статически типизированы, поскольку они не могут быть привязаны к новому значению, в то время какvar
переменные все еще могут быть динамически типизированы).Наконец, все аргументы метода должны быть автоматически
let
, т.е. они должны быть доступны только для чтения. Как правило, нет веских причин для изменения параметра, за исключением следующего:Это может быть заменено немного другой идиомой:
источник
use strict;
иuse warnings;
в perl на скрипте любого размера. Python лишил разработчика слишком большого количества средств отладки.var
иlet
(или подобный механизм) является недостатком. Другими словами: будь я дизайнером Python, я бы сделал что-то подобное. Тем не менее , будущие версии могут включать это при загрузке специального пакета (аналогично__future__
). Скажем,import strict
. Это не произойдет, хотя, так как это требует синтаксических хаков ...Моя главная жалоба - это многопоточность, которая во многих случаях не так эффективна (по сравнению с Java, C и другими) из-за глобальной блокировки интерпретатора (см. Доклад «Внутри Python GIL» (ссылка на PDF) )
Тем не менее, существует многопроцессорный интерфейс, который очень прост в использовании, однако он будет тяжелее использовать память для того же числа процессов по сравнению с потоками, или сложным, если у вас много общих данных. Однако преимущество заключается в том, что если у вас есть программа, работающая с несколькими процессами, она может масштабироваться на нескольких машинах, а многопоточная программа не может этого сделать.
Я действительно не согласен с критикой документации, я думаю, что она превосходна и лучше, чем большинство, если не все основные языки.
Также вы можете поймать много ошибок во время выполнения Pylint .
источник
Можно утверждать , что отсутствие статической типизации, которая может привести к определенным классам ошибок времени выполнения , не стоит дополнительной гибкости, которую обеспечивает утка.
источник
int foo = 4; Console.Write(foo.Length);
не компилируется, поэтому ошибка «Int32 не имеет свойства Length» не может случайно попасть в опубликованное программное обеспечение. В python, если вы не запускаете дополнительные вспомогательные инструменты для поиска подобных ошибок, код, который обращается к несуществующим членам объектов, может остаться незамеченным, пока не закончится, вызывая ошибки времени выполнения.Я думаю, что объектно-ориентированные части Python чувствуют себя как-то «на болтах». Можно сказать, что необходимость явно передавать «я» каждому методу является признаком того, что его ООП-компонент не был явно спланирован ; это также показывает иногда бодрые правила обзора Python, которые были раскритикованы в другом ответе.
Редактировать:
Когда я говорю, что объектно-ориентированные части Python чувствуют себя «запертыми», я имею в виду, что время от времени ООП кажется довольно непоследовательным. Возьмем, к примеру, Ruby: в Ruby все является объектом, и вы вызываете метод, используя знакомый
obj.method
синтаксис (за исключением, конечно, перегруженных операторов); в Python все тоже объект, но некоторые методы вы вызываете как функцию; т. е. вы перегружаете,__len__
чтобы вернуть длину, но вызываете ее, используяlen(obj)
вместо более привычного (и непротиворечивого)obj.length
общего в других языках. Я знаю, что есть причины этого дизайнерского решения, но они мне не нравятся.Кроме того, в модели ООП Python отсутствует какая-либо защита данных, т. Е. Нет частных, защищенных и открытых членов; Вы можете имитировать их, используя методы
_
и__
перед ними, но это отчасти уродливо. Точно так же Python не совсем правильно понимает аспект передачи сообщений в ООП.источник
Что мне не нравится в Python:
lambda
может содержать только одно выражение).cin
иscanf
в C ++ и C илиScanner
в Java).источник
raw_input
и 'sys.stdin' довольно скелеты. Они не поддерживают форматированный ввод (например, что-то вроде «% d:% d:% d»% (часы, минуты, секунды) для чтения во времени). Пока что в Python нет ничего похожего на функциональность scanf (в C) или Scanner (Java).Аргументы по умолчанию с изменяемыми типами данных.
Обычно это результат некоторых тонких ошибок. Я думаю, что было бы лучше, если бы он создавал новый объект списка всякий раз, когда требовался аргумент по умолчанию (а не создавал отдельный объект для использования при каждом вызове функции).
Изменить: Это не огромная проблема, но когда что-то нужно ссылаться в документах, это обычно означает, что это проблема. Это не должно быть обязательным.
Особенно, когда это должно было быть по умолчанию. Это просто странное поведение, которое не соответствует ожидаемому и бесполезно для большого количества обстоятельств.
источник
Некоторые из возможностей Python, которые делают его настолько гибким, как язык разработки, также рассматриваются как основные недостатки тех, которые используются для статического анализа «всей программы», проводимого процессом компиляции и компоновки в таких языках, как C ++ и Java.
Локальные переменные объявляются с использованием обычного оператора присваивания. Это означает, что привязки переменных в любой другой области требуют, чтобы компилятор подобрал явную аннотацию (глобальные и нелокальные объявления для внешних областей, нотация доступа к атрибутам для областей экземпляров). Это значительно уменьшает количество шаблонов, необходимых при программировании, но означает, что сторонние инструменты статического анализа (такие как pyflakes) необходимы для выполнения проверок, которые обрабатываются компилятором в языках, которые требуют явного объявления переменных.
Содержимое модулей, объектов класса и даже встроенное пространство имен могут быть изменены во время выполнения. Это очень мощный инструмент, позволяющий использовать множество чрезвычайно полезных техник. Однако такая гибкость означает, что Python не предлагает некоторые функции, общие для статически типизированных ОО-языков. В частности, параметр «self» для методов экземпляра является явным, а не неявным (поскольку «методы» не нужно определять внутри класса, их можно добавить позже, изменив класс, что означает, что он не особенно практичен передать ссылку на экземпляр неявно), а управление доступом к атрибуту не может быть легко реализовано в зависимости от того, находится ли код «внутри» или «снаружи» класса (так как это различие существует только во время выполнения определения класса).
Это также верно для многих других языков высокого уровня, но Python имеет тенденцию абстрагироваться от большинства аппаратных деталей. Языки системного программирования, такие как C и C ++, по-прежнему гораздо лучше подходят для обработки прямого доступа к оборудованию (однако, Python с радостью будет общаться с ними либо через модули расширения CPython, либо, что более удобно, через
ctypes
библиотеку).источник
Пример для разбитой области видимости; стенограмма с сессии переводчика:
global
иnonlocal
ключевые слова были введены, чтобы исправить эту глупость дизайна.источник
global
илиnonlocal
в Python. Настолько редко, что я забываю, что эта проблема существует, и приходится пересматривать ее несколько раз, несмотря на то, что я пишу код Python каждый день на работе. Для меня код, который должен изменять глобальные переменные (или, что еще хуже, внешние неглобальные переменные) - это запах кода. Там обычно (не всегда) лучший способ.Я считаю, что сочетание Python объектно-ориентированного
this.method()
и процедурного / функциональногоmethod(this)
синтаксиса очень тревожно:Это особенно плохо, потому что большое количество функций (а не методов) просто сбрасывается в глобальное пространство имен : методы, относящиеся к спискам, строкам, числам, конструкторам, метапрограммированию, все смешано в один большой отсортированный по алфавиту список.
По крайней мере, функциональные языки, такие как F #, имеют все функции, правильно расположенные в модулях:
Так что они не все вместе. Кроме того, это стандарт, которому следуют во всей библиотеке, так что, по крайней мере, он соответствует.
Я понимаю причины использования функции против метода , но я все еще думаю, что плохая идея смешивать их вот так. Я был бы намного счастливее, если бы следовал синтаксису метода, по крайней мере, для обычных операций:
Независимо от того, являются ли методы мутирующими или нет, их использование в качестве методов объекта имеет несколько преимуществ:
Module
при звонкеModule.method(x)
. Если взять приведенный выше пример функционального списка, почему я должен повторятьList
снова и снова? Он должен знать, что этоList
и я не хочу вызыватьNavigation.map()
функцию! Использованиеx.map()
синтаксиса делает его СУХИМЫМ и все еще однозначным.И, конечно, имеет преимущества по сравнению с пут-все , в-глобальном пространстве имен- способ сделать это. Дело не в том, что нынешний способ неспособен добиться цели. Это даже довольно кратко (
len(lst)
), так как ничто не является пространством имен! Я понимаю преимущества использования функций (поведение по умолчанию и т. Д.) Перед методами, но мне все еще не нравится это.Это просто грязно. А в больших проектах грязь - твой злейший враг.
источник
len()
, это функция, и каковы преимущества. Я также заявил, почему я считаю, что это плохая идея, почему я считаю, что глобальные функции - это особенно плохая идея, и почему я считаю, что методы предоставляют удобный метод организации и определения объема вашей функциональности =)def
,class
и другие вызовы , не функции. Сравните это со 100+ в большинстве других популярных языков. Кроме того , рассмотрим линию отimport this
:Namespaces are one honking great idea -- let's do more of those!
. Я думаю, что вы можете неправильно понять пространства имен Python;)Отсутствие гомойконичности .
Python должен был ждать 3.x, чтобы добавить ключевое слово «with». На любом гомоиконическом языке его можно было бы добавить в библиотеку.
Большинство других вопросов, которые я видел в ответах, относятся к одному из 3 типов:
1) Вещи, которые можно исправить с помощью инструментов (например, pyflakes) 2) Детали реализации (GIL, производительность) 3) Вещи, которые можно исправить с помощью стандартов кодирования (т. Е. Функции, которые люди не хотели бы видеть)
# 2 не проблема с языком, IMO # 1 и # 3 не являются серьезными проблемами.
источник
with
был доступен из Python 2.5 сfrom __future__ import with_statement
, но я согласен, я иногда с сожалениемif
for
print
Python - мой любимый язык, так как он очень выразителен, но все же не дает вам совершать слишком много ошибок. У меня все еще есть несколько вещей, которые меня раздражают:
Нет реальных анонимных функций. Лямбда может использоваться для функций с одним оператором, а
with
оператор может использоваться для многих вещей, где вы использовали бы блок кода в Ruby. Но в некоторых ситуациях это делает вещи немного более неуклюжими, чем они должны быть. (Далеко не так неуклюже, как это было бы в Java, но все же ...)Некоторая путаница в отношении между модулями и файлами. Запуск «python foo.py» из командной строки отличается от «import foo». Относительный импорт в Python 2.x также может вызвать проблемы. Тем не менее, модули Python намного лучше, чем соответствующие функции C, C ++ и Ruby.
Явное
self
. Несмотря на то, что я понимаю некоторые причины этого, и хотя я использую Python ежедневно, я склонен делать ошибку, забывая об этом. Другая проблема заключается в том, что делать класс из модуля становится немного утомительно. Явное «я» связано с ограниченной областью видимости, на которую жаловались другие. Наименьшая область действия в Python - это область действия функции. Если вы сохраняете свои функции небольшими, как и должно быть, это само по себе не проблема, и IMO часто дает более чистый код.Некоторые глобальные функции, такие как
len
, что вы ожидаете, чтобы быть методом (который на самом деле это за кадром).Значительный отступ. Не сама идея, которая, на мой взгляд, хороша, но, поскольку это единственное, что не дает многим людям попробовать Python, возможно, Python будет лучше с некоторыми (необязательными) символами начала / конца. Игнорируя этих людей, я мог бы полностью жить с принудительным размером для отступа.
Что это не встроенный язык веб-браузеров, а не JavaScript.
Из этих жалоб только первая, которая меня беспокоит, и я думаю, что она должна быть добавлена к языку. Другие довольно незначительны, за исключением последнего, что было бы здорово, если бы это случилось!
источник
datetime.datetime.now()
когда один проект может писать,datetime.now
а затем смешивать два проекта, один способ написания этого исключает другой, и, конечно же, этого не произошло бы в Java, которая не назвала бы модуль таким же, как файл (?) Если вы видите, как распространенный способ состоит в том, что модуль путает нас с файлом, когда оба применения практикуются и являются явными,self
я все еще пытаюсь понять, так как вызовы не имеют того же количества аргументов, что и функции. И вы могли бы подумать, что виртуальный питон работает медленно?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.
источник
Область видимости Python сильно нарушена, что делает объектно-ориентированное программирование на Python очень неловким.
источник
self.
перед каждой ссылкой свойство и метод экземпляра. Это делает невозможным использование Python для создания DSL, как это легко сделать в Ruby.Мои жалобы о Python:
источник
Модификаторы доступа в Python не являются обязательными для исполнения - затрудняет написание хорошо структурированного, модульного кода.
Я предполагаю, что это часть разбитой области видимости @ Mason - большая проблема в целом с этим языком. Для кода, который должен быть читабельным, кажется довольно сложным определить, что может и должно быть в области видимости, и каким будет значение в любой данный момент времени - в настоящее время я думаю о переходе от языка Python из-за этих недостатков. ,
Просто потому, что «мы все взрослые по соглашению» не означает, что мы не совершаем ошибок и не работаем лучше в рамках сильной структуры, особенно при работе над сложными проектами - отступы и бессмысленные подчеркивания кажутся недостаточными ,
источник
Но у него есть несколько замечательных возможностей:
источник
Я предпочитаю Python, и первый недостаток, который приходит мне в голову, заключается в том, что при комментировании такого утверждения
if myTest():
вы должны изменить отступ всего исполняемого блока, что вам не нужно делать с C или Java. На самом деле, в python вместо того, чтобы комментировать предложение if, я начал комментировать его следующим образом: `if True: #myTest (), поэтому мне также не придется менять следующий блок кода. Поскольку Java и C не полагаются на отступы, это упрощает комментирование операторов в C и Java.источник
if something()
наif False and something()
. Другой трюк - «закомментировать», используя многострочную строку.Многократная отправка плохо интегрируется с установленной системой однократной отправки и не очень эффективна.
Динамическая загрузка является серьезной проблемой в параллельных файловых системах, где POSIX-подобная семантика приводит к катастрофическим замедлениям для операций с интенсивным использованием метаданных. У меня есть коллеги, которые сожгли четверть миллиона ядерных часов, просто получая Python (с numpy, mpi4py, petsc4py и другими модулями расширения), загруженными на 65-тысячные ядра. (Моделирование дало значительные новые научные результаты, поэтому оно того стоило, но это проблема, когда более одной барреля нефти сжигают, чтобы загрузить Python за один раз.) Неспособность связать статически вынудила нас пойти на большие усилия, чтобы получить разумное время загрузки в масштабе, включая исправление libc-rtld для обеспечения
dlopen
коллективного доступа к файловой системе.источник
dlopen
находится в нашей библиотеке collfs . Этот репозиторий также содержит дополнительные трюки zipimport, вдохновленные кэшированием пути Ашера Лэнгтона. Мы работаем над лучшим распространением и бумагой.Во всяком случае, Python - мой основной язык уже 4 года. Быть фанатами, элитами или мономаньяками не является частью культуры питона.
источник
len(s)
через__len__(self)
и другие «особые методы»__add__
и__iadd__
для+
и+=
)self
в качестве первого параметра методаисточник
«Неизменность» - это не совсем сильная сторона. Числа AFAIK, кортежи и строки неизменяемы, все остальное (т.е. объекты) изменчиво. Сравните это с функциональными языками, такими как Erlang или Haskell, где все является неизменным (по крайней мере по умолчанию).
Тем не менее, неизменность действительно действительно сияет параллелизмом *, что также не является сильной стороной Python, так что, по крайней мере, это является следствием.
(* = Для придирки: я имею в виду параллелизм, который, по крайней мере, частично параллельный. Я думаю, Python в порядке с «однопоточным» параллелизмом, в котором неизменность не так важна. (Да, любители FP, я знаю, что неизменность отлично даже без параллелизма.))
источник
Я хотел бы иметь явно параллельные конструкции. Чаще всего, когда я пишу список понимания, как
Мне все равно порядок, в котором элементы будут обрабатываться. Иногда мне даже не важно, в каком порядке они возвращаются.
Даже если CPython не может сделать это хорошо, когда мой f - чистый Python, подобное поведение может быть определено для использования другими реализациями.
источник
В Python нет оптимизации хвостового вызова, в основном по философским причинам . Это означает, что хвостовая рекурсия в больших структурах может стоить O (n) памяти (из-за ненужного стека) и потребует от вас переписать рекурсию как цикл для получения O (1) памяти.
источник