От hackerfactor, автор: Нил Кравец, составлено сердцем машины.
У автора этой статьи есть группа друзей-гиков, которые часто обсуждают технические темы, а иногда и языки программирования. «Я ненавижу Python», — сказал автор. Он ужасно ненавидит Python. Даже если доступен готовый код Python, он скорее перепишет его на C. Чтобы систематически жаловаться на Python, автор написал этот блог, чтобы подробно описать «восемь смертных грехов» Python.
Эта тема вызвала оживленную дискуссию на Hacker News (более 400 комментариев), и заинтересованные читатели могут посмотреть или принять участие.
Хакер Новости обсуждает:новости. чем com Nat or.com/item?ID=187…
1. Версия
Если вы хотите установить операционную систему Linux по умолчанию, то вам, скорее всего, потребуется установить несколько версий Python: Python2, Python3 или даже 3.5, 3.7. Причина в том, что Python3 не полностью совместим с Python2. Даже некоторым десятичным версиям (например, 3.5, 3.7) не хватает обратной совместимости.
Я полностью за добавление новых функций в язык программирования, и я даже не против выкинуть некоторые старые версии. ноPythonно устанавливается отдельно. Мой код Python 3.5 не работает с установкой Python 3.7, если я специально не импортирую его в 3.7. Многие разработчики Linux считают, что экспортировать его слишком обременительно, поэтому при установке Ubuntu они устанавливают и Python2, и Python3, потому что для некоторых основных функций требуется первый, а для других — второй.
Отсутствие обратной совместимости и фрагментированные версии часто служили для него похоронным звоном. Commodore создала первые домашние компьютеры (намного раньше IBM PC и Apple). Но Commodore PET несовместим с последующим Commodore CBM. CBM не совместим с VIC-20, Commodore-64, Amiga и т.д. Таким образом, вы либо тратите много времени на импорт кода с одной платформы на другую, либо отказываетесь от платформы. (Где Commodore сегодня? Пользователи уже давно забросили его...)
Точно так же Perl существует уже некоторое время. Но Perl3 несовместим с большим количеством кода Perl2. В сообществе было много ругани, поэтому одни хорошие коды были экспортированы, а другие заброшены. То же самое касается Perl4. Когда вышел Perl5, люди просто перешли на другой, более стабильный язык программирования. Сегодня лишь небольшой процент людей по-прежнему интенсивно использует Perl для поддержки предыдущих проектов. Но никто больше не использовал Perl для создания новых больших проектов.
Точно так же каждая версия Python имеет эффект амбара. Предыдущая версия все еще существует, и в итоге вы получаете кучу старого бесполезного кода Python, потому что никто не хочет тратить время на его перенос на последнюю версию. Насколько мне известно, нового кода для Python2 никто не создавал, но мы его сохраняем, потому что никому не хочется переносить требуемый код на Python3.x. Документация для Python 2.7, 3.5, 3.6, 3.7 по-прежнему активно поддерживается на веб-сайте Python, потому что они не могли решиться отказаться от предыдущего кода. Python подобен языку программирования-зомби: мертвые части все еще существуют как ходячие мертвецы.
2. Установка
Существует множество пакетов, которые помогут вам легко запустить apt, yum, rpm или какую-либо другую установочную библиотеку и получить последнюю версию кода. Но это не относится к Python. Если вы устанавливаете с помощью «apt-get install python», вы не знаете, какая версия у вас установлена, и она может быть несовместима со всем кодом, который вам нужен.
Поэтому вам нужно установить нужную вам версию Python. Один из моих проектов использует Python, но должен использовать Python 3.5. В итоге на моем компьютере установлены Python2, Python2.6, Python3 и Python3.5. Два из них от операционной системы, один для проекта, а другой обслуживает посторонний софт, установленный по другим причинам. Хотя оба являются Python, этот Python не является другим Python.
Если вы хотите установить пакеты Python, вы должны использовать «pip» (Pip Installs Packages). Но так как в вашей системе есть куча Python, вам нужно быть осторожным, чтобы использовать правильную версию pip. В противном случае «pip» может запускать «pip2» вместо «pip3.7», который вам нужен. (Если имя не существует, вам нужно указать явный реальный путь для pip3.7)
Товарищ по команде предложил мне настроить свою собственную среду, чтобы каждое программное обеспечение могло использовать базовую среду Python3.5. Это работало отлично, пока мне не понадобилось начать другой проект с Python 3.6, но потребность в Python 3.6 потребовала создания другой среды. Два проекта, две версии Python, вообще никак не сочетаются (ухмыляется жизни).
Установщик pip помещает файлы в локальный каталог пользователя. Установите общесистемные библиотеки без pip. Gawd не позволяет запускать "sudo pip" с ошибками, потому что это разрушит весь ваш компьютер! Запуск sudo может привести к тому, что некоторые пакеты будут установлены на системном уровне, некоторые для неправильной версии Python, а некоторые файлы в вашем домашнем каталоге могут оказаться в собственности root, поэтому будущие установки pip без sudo могут страдать от проблем с разрешениями и не удалось. Не делай это.
Кто поддерживает эти модули pip? Конечно сообщество. То есть нет четкого владельца и обязательной цепочки происхождения или ответственности. Ранее в этом году в версии PyPI был обнаружен бэкдор для кражи учетных данных SSH. Это также ожидается. (По той же причине я не использую Node.js и npm и не доверяю их проектам сообщества.)
3. Синтаксис
Я ярый сторонник читабельности кода. На первый взгляд Python кажется читабельным. Но вы так не думаете, когда начинаете создавать большие кодовые базы.
Большинство языков программирования используют некоторую нотацию для определения области действия — где начинаются и заканчиваются функции, операции, содержащиеся в условных операторах, область определения переменной и т. д. C, Java, JavaScript, Perl и PHP используют {...} для определения областей видимости, Lisp использует (...). Как насчет Питона? Он использует пробелы! Если вы хотите определить диапазон сложного кода, вы можете сделать отступ для следующих нескольких строк кода, и когда отступ закончится, диапазон закончится.
В руководстве по Python сказано, что вы можете определять диапазоны с любым количеством пробелов или табуляций. Однако лучше всего использовать четыре пробела на отступ! Если вы хотите сделать двойной отступ для вложения, используйте восемь пробелов! Сообщество Python стандартизировало это, хотя это явно не указано в руководстве по Python. Это сообщество любит использовать четыре пробела. Поэтому, если вы не собираетесь никому показывать свой код, лучше всего использовать четыре пробела на отступ.
Когда я впервые увидел код Python, я подумал, что можно использовать отступы для определения областей видимости, но это было огромным недостатком. Вы можете сделать глубокую вложенность, но при этом каждая строка будет такой длинной, что вам придется оборачивать ее в текстовом редакторе. Длинные функции и условные операторы могут затруднить сопоставление начального и конечного диапазонов. И когда вы случайно принимаете три пробела за четыре, вы склонны к просчету и можете часами заниматься отладкой и отслеживанием.
Для других языков я привык отлаживать код без каких-либо отступов. Таким образом, я могу быстро просмотреть код, а затем легко идентифицировать и удалить код отладки. Но как насчет Питона? Любой код с неправильным отступом вызовет ошибку отступа.
4. includes
В большинстве языков программирования есть способ импорта других блоков кода. Например, язык C использует «#include», а язык PHP может использовать «include, include_once, require, require». Python, с другой стороны, использует «импорт».
Python может импортировать целые модули, части модулей или определенные функции внутри модуля. язык Си? Вы можете посмотреть "/usr/include/". Для Python лучше всего указать все пути с помощью «python -v», а затем выполнить поиск каждого файла в каждом каталоге и подкаталоге из списка. Некоторые из моих друзей любят Python, но когда я вижу что-то, что они хотят импортировать, им приходится просматривать стандартные модули.
Функция импорта также позволяет пользователям переименовывать импортированный код. Они в основном определяют пользовательское пространство имен. На первый взгляд, вы будете чувствовать себя довольно хорошо, но в конечном итоге это сказывается на удобочитаемости и долгосрочной поддержке. Переименование подходит для небольших сценариев, но не для долгосрочных проектов. Тех, кто использует 1-2 буквы в качестве пространств имен (например, «импортировать numpy как n») и не называет их обычным способом, следует просто вытащить и расстрелять!
Это не самое худшее. Когда большинство языков программирования включают код, они просто импортируют код. Некоторые языки, такие как объектно-ориентированный C++, могут выполнять код, если имеется глобальный объект с конструктором. Точно так же некоторый код PHP может определять глобальные переменные, поэтому импорт может запускать код, но эта практика обычно считается плохой. Напротив, многие модули Python содержат функции инициализации, которые запускаются во время импорта. Вы не знаете, что работает, что он делает, и вы можете даже не заметить. Если нет конфликта пространств имен, что в этом случае забавно, вам придется потратить много времени, пытаясь понять, почему.
5. Номенклатура
В других языках массивы называются просто «массивами», но в Python они называются «списки». Ассоциативные массивы в некоторых местах называются «хэшем» (Perl), но Python называет их «словарем». Python, кажется, движется полностью в своем собственном темпе, не используя общепринятую терминологию в области информатики и информатики.
Также есть проблема с именованием библиотеки Python. PyPy, PyPi, NumPy, SciPy, SymPy, PyGtk, Pyglet, PyGame… (первые две библиотеки произносятся одинаково, но работают совершенно по-разному). Я понимаю, что «py» означает Python, но не могут ли они все появляться до или после одного и того же?
Некоторые распространенные библиотеки отказываются от каламбурного соглашения об именах «Py», в том числеmatplotlibнос,Pillowи SQLAlchemy. В то время как некоторые имена могут указывать на его назначение (например, SQLAlchemy содержит SQL, поэтому это может быть интерфейс SQL), другие могут быть просто случайными словами. Если вы не знаете, что делает библиотека BeautifulSoup, можете ли вы сказать по названию, что это парсер HTML/XML? Тем не менее, BeautifulSoup хорошо документирован и прост в использовании, и я бы не жаловался, если бы каждый модуль Python был таким, но у большинства библиотек Python ужасная документация.
В целом, я думаю, что Python — это набор библиотек с непоследовательными соглашениями об именах. Я часто жалуюсь на ужасные названия проектов с открытым исходным кодом. Вы ничего не можете сказать по самому названию, если не знаете, что делают проекты. Если вы не знаете, какую библиотеку вы ищете, вы найдете некоторые библиотеки только по случайному упоминанию имен или случайно. Большинство библиотек Python усугубляют это явление и негативный опыт использования Python.
6. Странная операция
В каждом языке есть свои довольно своеобразные операции. Номенклатура в C для использования & и * для получения адресного пространства и значения очень странная. Также есть ярлыки для реализации инкремента/декремента в C с помощью ++ и —. В языке Bash вам всегда нужно учитывать, «когда использовать escape-символ (\)» при заключении в кавычки определенных символов (например, круглых скобок и точек, используемых в регулярных выражениях). Совместимость с JavaScript проблематична (не каждый браузер поддерживает все полезные функции). Но в Python больше странных операций, чем в любом другом языке, который я видел. как:
В C строки заключаются в двойные кавычки, а символы заключаются в одинарные кавычки.
В PHP и Bash оба вида кавычек могут заключать строки. Однако строки, заключенные в двойные кавычки, могут содержать переменные. Напротив, строки в одинарных кавычках являются литералами; любые встроенные имена, подобные переменным, не расширяемы.
В JavaScript нет разницы между одинарными и двойными кавычками.
В Python нет разницы между одинарными и двойными кавычками. Однако, если вы хотите, чтобы строка занимала несколько строк, используйте тройные кавычки, например """string""" или '''string'''. Если вы хотите использовать двоичный код, вам нужно предпочесть строки с b (b'binary') или r (r'raw'). Иногда вы используете str(string) для преобразования строки в строку или string.encode('utf-8') для преобразования в формат utf8.
Если вы сначала думали, что символы =, ==, === в PHP и JavaScript выглядят странно, вы, вероятно, не поймете, когда будете использовать кавычки в Python.
7. Пройти через ссылку на объект
Передача параметра функции в большинстве языков программирования осуществляется по значению. Если функция изменяет значение, результат не передается вызывающему коду. Но, как я объяснил, Python должен быть другим. Python по умолчанию использует передачу по объектной ссылке для передачи аргументов функции. Это означает, что изменение исходной переменной может привести к изменению значения.
Это самая большая разница между процедурными, функциональными и объектно-ориентированными языками программирования. Если каждая переменная передается по ссылке на объект, и любое изменение переменной изменяет все ссылки, вы, вероятно, используете глобальный объект. Вызов одного и того же объекта с другим именем не изменяет объект, поэтому он фактически является глобальным. Кроме того, как давно усвоили программисты на C, глобальные переменные отвратительны, не используйте их.
В Python вы должны передавать переменные по значению, например, «a=b» просто присваивает другое имя тому же объектному пространству, но не копирует значение b в a. Если вы действительно хотите скопировать значение b, вам нужно использовать функцию копирования, обычно имеющую вид «a=b.copy()». Заметьте, однако, что я сказал «обычно». Не все типы данных имеют прототип «копии», или функция копирования может быть неполной. В этом случае вы можете использовать отдельную библиотеку "copy": "a=copy.deepcopy(b)".
8. Локальное именование
Общепринятым приемом программирования является присвоение программе имени используемой библиотеки или функции. Например, если бы я тестировал программу захвата экрана с библиотекой C под названием «libscreencapture.so», я бы назвал программу «screencapture.c» и скомпилировал ее в «screencapture.exe».
gcc -o screencapture.exe screencapture.c -lscreencapture
В таких языках, как C, Java, JavaScript, Perl, PHP и т. д. это обычно хорошо работает, потому что эти языки могут легко различать нативные программы и репозитории, у которых разные пути. Но как насчет Питона? В любом случае, не делай этого. Зачем? Python предполагает, что вы хотите сначала импортировать нативный код. Если бы у меня была программа под названием «screencapture.py», которая использовала бы «импорт снимков экрана», она импортировала бы себя вместо системной библиотеки. По крайней мере, вы должны назвать родную программу «myscreencapture.py».
не зря
Python — очень популярный язык программирования, имеющий множество поклонников. Даже многие из моих друзей любят Python. Я обсуждал с ними эти вопросы на протяжении многих лет, и каждый раз они согласно кивают. Они не против того, чтобы у Python были эти проблемы, они просто не думают, что этого достаточно, чтобы ослабить их энтузиазм в отношении языка.
Мои друзья часто упоминают эти действительно крутые библиотеки Python. Я согласен, что некоторые библиотеки очень полезны. Например, BeautifulSoup — один из лучших парсеров HTML, которые я когда-либо использовал, NumPy упрощает реализацию многомерных массивов и сложной математики, а TensorFlow отлично подходит для машинного обучения. Однако я бы не стал создавать монолитные программы на Python только потому, что мне нравится TensorFlow или SciPy. Жертвовать читабельностью и ремонтопригодностью ради этих "мелких барышей" я не собираюсь, оно того не стоит.
Обычно, когда я пишу критику по теме, я также стараюсь писать что-то позитивное. Но я не могу перечислить все хорошее, что есть в Python, потому что считаю его отстойным.