Pull to refresh

Comments 54

Да если б кто-то это отредоктировал в плане форматирования текста было бы отлично, а то форматирование текстов это моя ахилесова пята.
> Armin Ronacher довольно известный разработчик
Тире.
> но обвинить его в истерике и ретроградстве не так-то просто, его возражения
Вместо запятой необходимо ставить двоеточие.
> Все труднее становиться вести
tsya.ru/
> Когда кто-либо начинает обсуждение поддержки Unicode в двух ветках Python — это весьма сложная тема.
Чо? (Wat?.jpg)
> С тех пор как мне пришлось сопровождать большое
Возможно, здесь имеет смысл поставить запятую.
> С другой стороны в Python 2 у нас есть
Запятая.
> интервал в 7 битов, а кроме него есть
«А»? Мы уже сказали, что есть два типа, откуда «а»? Почему не «и»?
> Присмотревшись к ситуации вы можете заметить
Запятая.

> а то форматирование текстов это моя ахилесова пята.
Ваша ахиллесова пята это русский язык, а не форматирование текстов.

Называйте меня буквоедом, занудой (али ещё чего придумаете), но текст, каждое второе предложение которого содержит ошибки (как стилистические, грамматические, так и орфографические), читать сложно.
Что ж замечания в большей части справедливы, относительно пунктуации есть некоторые сомнения, спасибо
Да не нужно там тире! Наречие между подлежащим и сказуемым, а тире ставится в отсутствии связки. Последнее время я заметил, что на хабре втыкают это тире куда ни попадя. Вероятно, чтобы подчеркнуть свою грамотность. Но тире — это как специя. Хороша к месту.
Тире — это не специя, а знак препинания. Оно нужно там, где этого требуют правила русского языка. Если не нравится тире, можно переформулировать предложение.
Почему не нужно?.. «Тире ставится между подлежащим и сказуемым, выраженным существительным в именительном падеже (без связки).» Наречие тут вообще не причём.
Стоило бы добавить, что Армин «сломался») и перевел свои проекты на Python3 с выходом версии 3.3. В этой версии были учтены его пожелания (PEP414).
Судя по всему нет, так как PEP414 представлен в феврале 2012 г. и подтвержден тогда же, а троллит разработчиков он этим постом 5 января 2014 г.
Просто подписываюсь под каждым словом статьи!
В конце декабря переводил библиотеку для работы с .kdb на 3 питон, в частности стоит 3.3, на нем и тестировал. Больше всего вызвало проблемы корректно обрабатывать b"" в новом питоне вместо старого доброго str во втором.
Ну а в u"" в старом питоне не напрягает? Мне кажется разработчики третьей версии правильно поступили с уникодом, сделав его типом по-умолчанию для строк. Если вам нужно работать с байтами, используйте тип bytes, разве это не логично?
Значит никак не уймется) Ну в принципе дело полезное пусть додавливает нормальный юникод в третьей версии.
Сейчас возникло движение за создание python2.8. Надеюсь, Гвидо это выдержит, и мы не получим маргинальных форков. Конечно переход на 3 идет намного, намного хуже, чем ожидалось. Я застал еще 1.x -> 2.x, это произошло в момент, все хотели безусловно лучший язык, но к 3 накопилась критическая масса проектов.
Ну вы и придумаете же сравнение. При переходе от 1.x к 2.x нужно было парочку-троечку багов у себя в программе поправить и всё. И полученный код при этом оставался работоспособных в обоих версиях. Python3 же — это, строго говоря, вообще другой язык с кучей несовместимых изменений. Причём таких, что писать python2/3 код возможно, но… весьма и весьма непросто.

Это всё равно что сравнить переход с K&R C на ANSI C с переходом на C++.
Ну вообще разработчики Python признают что держать две ветки питона была не очень хорошей идеей. Из-за того что python 2.x работает особо никто на python 3.x не движется, опять же да там свои тараканы.
Армин упускает главную идею: есть две логические сущности — строки и массивы байт. Строки — это текст. То, что люди пишут друг другу. То, что пользователь читает на сайте (имено пользователь и именно читает, а не то, как это видит компьютер). А вот массивы байт — это просто массивы байт. С ними работают компьютеры. Компьютеры пишут массивы байт в сокеты, компьютеры считывают их из файлов на диске, и компьютеры же преобразуют их в строки, чтобы люди могли их прочитать.

В Python 2 эти концепции были смешаны, в Python 3 — разделены. То, что часть старого функционала, которая опиралась на хаки с кодеками (encode/decode в JSON? вы серьёзно?) перестала работать, вполне закономерно. Но это не значит, что ради некрасивых хаков нужно отказаться от красивой концепции. И если для массивов байт нужны функции, аналогичные функциям для строк, то нужно просто перенести эти функции в Python 3, а не смешивать две идеи, разводя зоопарк с кучей кодирований, декодирований, __str__ и __unicode__, настройками системы и т.д.
Нифига они не разделены в Python 3. Или вы скажете, что у вас теперь u'\u0065\u0308' и u'\u00eb' — это теперь вдруг одно и то же? А с точки зрения «именно пользователя, который их именно читает» они неотличимы.

Всё с чем вы работаете и в Python2 и в Python3 и в любом другом языке — это массивы байт (short'ов или long'ов иногда), но никак не строки. «То, с чем работает пользователь» — штука сложная и многогранная и я не буду так уж сильно удивлён если кому-то Unicode для этого не хватит и он придумает свою структуру на основе, ну скажем, JSON. А тогда ему и потребуется перекодировать из Unicode в JSON — и почему этот процесс не должен называться encode, а обратный ему — decode?

То, что разработчики Python 3, с упорством, достойным лучшего применения, делают вид, что весь зоопарк с кучей кодирований, декодирований и прочего таки в природе есть его не отменяет. Имя файла — это у нас «то, что видит пользователь» или нет? А если это UNIX и эта строка вдруг не является валидной UTF-8 строкой — что тогда?
Вы передёргиваете. Моё послание было в том, что логический тип «строка» был придуман для передачи и обработки текстовой информации. Логическая строка состоит из набора логических символов — человеческих алфавитов, пунктуации, спецсимволов и, при необходимости, служебных невидимых символов. Это простая концепция, принятая в большинстве высокоуровневых языков программирования (из тех, что сходу вспомню, только в C тип «char» — числовой, а не символьный). Если хотите, это общепринятые понятия. Спорить с ними можно, но для этого должны быть действительно веские причины.
Всё с чем вы работаете и в Python2 и в Python3 и в любом другом языке — это массивы байт (short'ов или long'ов иногда), но никак не строки.


Только это по-разному типизированные массивы байт.
Массив байт, соответствующий представлению в памяти экземпляра какого-нибудь класса, типизирован как экземпляр этого класса.
Массив байт, соответствующий представлению в памяти строки, типизирован как строка, причём строка в конкретной кодировке.
Массив байт, соответствующий… кхм, массиву байт, не типизирован никак. Ну, или типизирован как массив байт.
В питон надо добавить нормализацию, да.

Всё, с чем я работают в высокоуровневых языках — это массивы unicode codepoints. Это не только символы, но и не просто байты.

А статья — ворчание на тему «как же так, почему я не могу говнокодить на python 3 как раньше?!?»
Статья о том, что важно знать весь технологический стек, от проектирования архитектуры до нюансов работы процессора. Аргументов, что строку нужно воспринимать просто как массив байт, я так и не увидел.

Более того, статья прекрасно показывает, как быстро растёт сложность при усложнении задач. Хранение строки — просто. Конкатенация строк — уже сложнее. Разбор структур типа XML — ещё сложнее. Думать о том, в какой кодировке к вам пришёл документ при разборе структуры в поисках атрибута доменной области, — это уже чертовский трудно. Абстракция «строка» по крайней мере разделить проблему на две части: считывание байт из входного потока и приведение их к объекту в памяти, и дальнейшая обработка таких объектов с известной структурой.
Аргументов, что строку нужно воспринимать просто как массив байт, я так и не увидел.

Не нужно, а стоит. И это там есть. Основная мысль про то что надо это про это помнить. Иначе можно словить много лулзов.
Честно говоря, я не понимаю, о чём мы спорим. Если вы хотели сказать, что важно знать, как работают ваши строки, то я с этим уже согласился. Я же хотел подчеркнуть другую идею, а именно то, что строки очень часто бывает полезно воспринимать как некую отдельную абстрактную сущность. Чтобы можно было сказать «объедини эти строки», а не «выдели столько-то памяти, скопируй строки в выделенный блок, поставь в конце нуль-терминанту». Это не значит, что не нужно знать, как такое «объедени строки» будет работать внутри и надеяться на лучшее. Но это значит, что при написании программ вы можете мыслить абстракциями более высокого уровня, концетрируясь на основной задаче, а не на выделении памяти или кодировке ваших строк.
Поясню Армин ругается на то, что сейчас после python 2.x существенно усложнили работу с однобайтной кодировкой. За счет как раз такого отделения строк в абстрактную сущность. Причем где эта работа со строками была вполне естественной. Вообще говоря эта проблема со строками была сразу начиная с выпуска первого python 3. Это является основным препятствием перехода на 3 ветку питона.
В Python 3 однобайтная кодировка — это как раз тип bytes. И если для него нет каких-то функций (которые были в 2-ке для str), то нужно просто добавить эти функции.

Ну не знаю, для меня основной причиной неперехода на Python 3 является отсутсвие некоторых (довольно уникальных) библиотек и доисторический CentOS 5.9 на серверах, где системным является вообще Python 2.4. А вот как раз со строками лично мне в последнее время гораздо проще работать из Python 3.
Как раз проблема что просто str на bytes не заменить.

А вот как раз со строками лично мне в последнее время гораздо проще работать из Python 3.

Если чисто со строками и они у вас изначально уникодные конечно проще.
И если для массивов байт нужны функции, аналогичные функциям для строк

Да, нужны. «GET / HTTP/1.1» — это, несомненно, массив байтов. Там если и есть не-ASCII символы, то они должны быть закодированы urlencode. Однако ж я не вижу ничего зазорного в том, чтобы создавать и обрабатывать «это» с помощью «строковых» функций, работающих с байтовыми строками как со строками, а не как с массивами.

В Python 2 эти концепции были смешаны, в Python 3 — разделены.

Ок, давайте посмотрим, действительно ли они разделены. Я ткнул в первое попавшееся нетривиальное место.
> urllib.request.urlopen(«example.com/корова.jpg»)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 5-10: ordinal not in range(128)
> urllib.request.urlopen(b«example.com/%D0%BA%D0%BE%D1%80%D0%BE%D0%B2%D0%B0.jpg»)
AttributeError: 'bytes' object has no attribute 'timeout'
> urllib.request.urlopen(«example.com/%D0%BA%D0%BE%D1%80%D0%BE%D0%B2%D0%B0.jpg»)
urllib.error.HTTPError: HTTP Error 404: Not Found (и это правильный ответ)

Щито? Серьёзно? Вот эти кракозябры %D0%BA%D0%BE%D1%80%D0%BE%D0%B2%D0%B0 должны быть unicode? Ну, в общем, да. Потому что urlopen() делает примерно следующее:
1. http_conn.request(«GET», selector, headers=headers)
2. request = '%s %s %s' % (method, url, self._http_vsn_str)
3. request.encode('ascii')
Если честно b"" большой геморрой.

С точки зрения теоритической логики это верно и круто, но не полностью, т.к., как указал автор, не все гладко с форматированием и byte совсем не str.
На практике, короче говоря, проблемы.
Да и не тем они занялись, разработчики Питона, выходит перфекционизм какой-то, для решения проблемы с юникодом нет ни одного стороннего проекта, для решения проблемы с тредингом и локом — 10ки проектов с финансированием!

Только тут Гвидо говорит с этим все зашибись, хотя это не так, иначе не было бы Shedskin, Pypy, Stackless, Eventlet, Greenlet и десятков других проектов пытающихся поправить это недоразумение.

Имхо если 4ка не получит честный, полноценный трединг и мультипроцессинг — то Питон так и останется скриптовым языком для простых решений и забавой ученых без скалируемых алгоритмов.
Вы смешиваете понятия языка программирования и его реализации. Python 2/Python 3 — это версии языка. Эти названия сами по себе обозначают некую спецификацию (даже если эта спецификация определяется основной реализацией). Гвидо, в первую очередь, занимается развитием языка. Оптимизации (в том числе многопоточность), как говорит сам Гвидо, — это дело реализации.

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

О каком скалировании идёт речь? Научные библиотеки пишутся через C-расширения, где с потоками нет проблем (плюс плюшки от GPU, ага). Для ненаучных вполне можно использовать multiprocessing (который на Linux даёт не такой уж и большой оврехед по сравнению с потоками). В кластерных вычислениях производительность вообще чаще всего определяется каналом связи, скоростью считывания с диска или эффективностью алгоритмов, и очень редко опирается в линейную скорость работы интерпретатора (см., например, PySpark)
Я в целом о направлении разработки Питона. Для продвижения в корпоративных кругах вместо Явы проблема с разницей 2 и 3 слишком велика. Многие профессионалы Python 2 не хотят с 3-кой работать.

Надо было депрекейтед сделать и старый str вывести в загружаемый модуль (как было сделано со string).
А зачем продвигать Python в корпоративных кругах? У него уже есть достаточно большое и дружелюбное сообщество, отличная документация и куча первоклассный библиотек. А популяризовать язык просто ради факта не вижу смысла.
На практике та модель, к которой пришел Питон в третьей версии, практикуется в Java, .NET, Obj-C и многих других современных языках уже много лет. И все проблемы с ней решаются очень просто — если вы работаете со строками, представленными в виде байт, то преобразуйте их к строке и работайте с ней, а потом обратно. А если это на самом деле и не строка вовсе, тогда с какой стати на ней должны работать стандартные строковые операции?
Мне кажется им стоило бы оставить оба метода. Для маленьких скриптов геморой с энкод-декод не стоит того.
А для больших скриптов неявные преобразования увеличивают вероятность ошибки.

Ну и Zen of Python — «explicit is better than implicit».
Видимо Армин не очень часто сталкивается с начинающими разработчиками. Мало кто из них может сказать какой тип данных ожидается на вход функции — строка или юникод да и чем они черт возьми отличаются и зачем нужен юникод если есть строки. Это очень большая проблема для языка, который позиционируется (ну мне кажется, что он так позиционируется) как один из самых простых для восприятия языков. Так что я тут на стороне Гвидо — к чертям метод encode в «байтовых строках». Что можно энкодить в массиве байт? Господи, да люди, которые работают по полгода с питоном и не скажут какой метод используется для преобразования из строки в юникод — encode или decode.
Короче я за лучшее восприятие и читаемость. И да, я за то, что питон 3 хорош и, что резкий переход от 2 к 3 сделал много полезного в самой концепции языка. Переход конечно муторный и болезненный и далеко не все перейдут в ближайшее время, но, мне кажется, это стоит того
Я могу ошибаться, но все же предположу, что основная проблема — в неправильной смысловой интерпретации методов encode && decode для str && unicode. Еще проблем добавляет проставленная по умолчанию кодировка. Если бы ее не было, а она всегда указывалась явно, то половина ошибок выглядела бы при чтении так: «я пытаюсь из байтов с кучей искейпов сделать utf8 при помощи ascii».

Ну и всегда есть наводящие вопросы. Какой смысл у encode для str? Какой смысл у encode для unicode? И decode для них? Что они должны вернуть? Я лично до сих пор путаюсь. Поэтому вывод могу сделать только один: unicode в питоне несамоочевиден. Например, постоянные проблемы с чтением файлов, что проще использовать
codecs.open("file", "r", "utf-8")

чем преобразовать это руками. Или всякие там
hashlib.md5(sentence.encode('utf8'))

А иногда бывают и ужасы при работе с чужими либами:
r['name'].encode('utf8').decode('string_escape')

Ну и классика:
mimetypes.guess_type(self.file.path.encode('utf8'))


Не много ли encode'ов для таких простых вещей? Вроде же utf8 везде использую, но все равно приходится encodить или decodить. Поэтому теряется даже желание что-то там понимать. Чаще писать encode, чем decode. В особо плохих случаях, когда много непривычных escape'ов, писать decode. Смысл? Понимание? Не желаю. Поэтому совершенно согласен с python3, хотя, справедливости ради, там эти проблемы с кодировками иногда бывают еще более замороченные, когда что-то с escape'ами нужно делать.
Насколько я понимаю Армин и не выступает против перемен в языке как явления, и ситуацию с кодировками что в питоне3, что в питоне2 по его версии далека от идеала. Новички это довольно сложный аргумент: они чаще всего пользуются готовыми библиотеками, наляпать чтоб быстро работала, а дальше ситуация меня не интересует это аналогично новички, хотя и опытные в некоторых случаях такой подход используют. И с кодировками новичок редко сталкивается просто потому что этот вопрос на себя берет библиотека вместе с ее tutorial, но она должна быть еще написана, а автору библиотеки как раз обрабатывать различные кодировки нужно. Здесь дискуссия не об интересах новичков, они приспособятся к любому порядку использования, если он пригоден для человека. И многие элементы программы даже, вполне, наглядные будут для новичка выглядеть магией.
Ситуация далека от идеала, но скорее по причине изначальных проблем с этими сущностями во 2 питоне. Делать как говорит Армин — это перетаскивать эти проблемы в 3 питон.

— Почему бы не вернуть эти методы преобразования кодировки(encode и decode) назад?
— годами команда разработки Python не хочет вернуть возможность форматирования для байтовых строк.

По-моему, нельзя возвращать эти функции, иначе будет такая же проблема — мало кто будет понимать различие строк и «байтовых строк». Опять же, я не считаю название «байтовые строки» подходящим. Это неизменяемый байтовый массив, и относиться к нему надо как к массиву байт. Мне нравится этот подход, Армину нет.
Работаете с низкоуровневыми протоколами, которые возвращают бинарные данные? Да у вас байтовый массив. После преобразования это может быть текст или другие типы данных. Чем более четко разделяются типы данных тем меньше проблем в понимании как программа работает.
Конечно, теперь будет больше перекодирования из байт в в строки и обратно, ведь раньше можно было просто взять бинарные данные, поработать с ними как с текстом и выплюнуть куда-нибудь наружу, сохранив тип «байтовой строки». Однако после выкатки в бой, внезапно можно обнаружить, что один раз из ста получаем на выходе юникод. Ну добавим просто в конце encode, зачем там особо разбираться, мало ли где у нас произошло неявное преобразование. Мне этот подход кажется плохим, я двумя руками за новый со сломом совместимости.
Я вполне с вами согласен, неявные преобразования в таком месте программы весьма опасны.
UFO just landed and posted this here
Боюсь именно чтобы объяснить вашу ошибку и сделан python3. У вас совершенно нереальный мир, если в нем нет ни файлов ни передачи данных по сети. Любые данные извне программы приходят в некоторой кодировке, абсолютно все программы работают с кодировками.
UFO just landed and posted this here
Именно. utf-8 — это всего лишь цепочка байт, а не строка, объясняет вам python3.
И он совершенно прав. Потому что цепочка байт может быть и не utf-8, и вообще не строкой.

Если это строка — то скажите об этом интерпретатору (decode). И вы получите юникодную строку, с которой можно работать. А потом, когда её нужно отдать обратно, сделайте encode. Таким образом, код, который работает со строками, не парится с кодировками — они фигурируют только на interop boundary, и при этом везде в явном виде. И в чем проблема?
Так вот эта статья что мы комментируем про «И в чем проблема?»
Если бы люди так сильно не привязывались, то и недовольных было бы меньше.
Все-таки большую свинью подложили разработчики компьюторов, когда за единицу адресации выбрали 8 бит. И 4 гирабайта для 32-битных систем, и разные типы строк.
Правильно, надо было выбрать 10 бит! Тогда бы никто не путался, переводя между килобайтами, мегабайтами и т.п. ;)
Похоже, что иронию, без выделения ее цветом, на хабре понимать перестали ;)
UFO just landed and posted this here
В свете поста может быть полезен и этот материал, который стал уже довольно известным насколько я понимаю, так как на него есть ссылки в FAQ по Unicode в Python: Презентация о Unicode в Python 2\3 Посмотрел статью и комментарии, вроде бы ее не было.
У меня ощущение, что у Армина где-то жёсткая ошибка в проектировании и он не хочет в этом признаваться. Иначе, я не знаю, как это объяснить…
Sign up to leave a comment.

Articles