Как стать автором
Обновить

Комментарии 124

Мне кажется, автор таки перегибает палку местами. Unicode в именах файлов должен быть. Кодировка по умолчанию и в самом деле должна определяться из системной локали — а почему, собственно, должно быть по-другому, ведь зачем она тогда? Многие другие языковые рантаймы так делают уже давно, и вроде бы всех это устраивает.
P.S. Вышесказанное не значит, что я против Python 2, Python 3 или чего-либо ещё.
кодировка работы с конослью — да, берите из LANG и LC_*
Но если я открыл файл на чтение — почему ЭТО должно зависеть от локали?
Я блин свой конфиг не смогу прочитать если зайдёт пользователь с другой локалью!
./somescript <text.txt — какая должна быть кодировка? С одной стороны это обычный файл, с другой консоль.
не путайте STDIN и консоль!!!
Так я привёл пример, когда это не одно и то же.
Ну так скажите, что вам нужно строго UTF-8, если это так важно. Проблемы-то какие?
Конфиг не Ваш, а пользовательский. Пользователь решил, в какой кодировке его хранить, а Вам сказал это через LC_*.
А если сисадмин и пользователь пользуются разной локалью?
«Пользователь» в данном контексте — «пользователь программы». Администратор — тоже пользователь.
Пример. Администратор пишет конфиг в /etc/someapp/someapp.conf, пользуется там русскими буквами. А читается он пользователем, у которого другая локаль.
Чтоб конкретнее было. Администратор олдскульный и пользуется ru_RU.KOI8-R, а пользователь ru_RU.UTF-8 по умолчанию.
Гнать такого админа въетнамским веником!
Хм… Установка программы глобально (в /usr/… например, глобальные конфиги в /etc/… соответственно), один пользователь с ja_JP.EUC-JP, другой с ru_RU.KOI8-R. Что-то мне подсказывает, что проблемы будут у обоих при чтении конфига.
Подавляющее большинство программ позволяют оверрайдить system-wide конфиги юзерскими.
Позволяют, конечно, но далеко не все пользователи этим пользуются, да и первый старт всё равно с глобальными пойдёт.

Статус отношений — всё сложно!)

С одной стороны, да, должна определяться из локали. Хотя бы для корректного вывода в консоль (Windows уже перешла на Unicode в консоли?). С другой — записывая файл на внешний носитель я, наверное, хочу чтобы он прочитался на другой машине, на которой локаль может быть совсем другая и уж точно не хочу потери информации при записи. Стандартом де-факто для такой записи является одна из кодировок Unicode (UTF-8 в подавляющем большинстве случаев). Универсального решения в голову не приходит, разве что сделать по умолчанию UTF-8, а для stdin/stdout/stderr писать в кодировке локали. Но костыль явный.
Нет же. Дать вменяемый API. Нужно Вам ISO-8859-1 — сказали [fconfigure $f -encoding iso-8859-1]. Нужно UTF-8 — [fconfigure $f -encoding UTF-8]. Нужно, чтобы пользователь сам определил — ничего не указывайте. Нужно байтами пожонглировать — [fconfigure $f -encoding binary]
Что вменяемый API нужен это понятно. Вопрос в умолчании. Почему пользователь, а не общее для всех скриптов умолчание? А хочешь учесть пользовательские хотелки — [fconfigure $f -encoding locale].
Так умолчание пользователь задаёт. Локалью. Она ж для того и предусмотрена.
Некоторые пользователи слов таких не знают… И даже на одной машине к общим файлам могут обращаться пользователи с разной локалью.
Если не знают — ну будут использовать локаль по умолчанию, тем более.
Не знаю, по мне так лучше бы было чтобы кодировка по умолчанию была одна во всех возможных средах. Решил пользователь сменить локаль (или за него решили) и у него файлы перестали читаться.
Я ж говорю: если какие-то конкретные файлы нужно читать с другой кодировкой, программа явно её запросит (а её об этом, в свою очередь, попросит юзер, если захочет). А пока не запросит — дефолтом должна быть та кодировка, которой пользуется пользователь, а не какая-то там UTF-8.
Ну вот стоит у меня, к примеру, какая-нибудь EBCDIC по умолчанию. А программа XYZ требует (!) конфиг в UTF-8. Какого-такого? Мне ради этой программы в редакторе переключать кодировку? Да ни разу, она должна сразу брать конфиг в моём любимом EBCDIC.
Не согласен.
Поясните.
Просто мнение, что файлы на диске, при передаче по сети и т. п., должны храниться в единой кодировке. Грубо говоря, скопировали вы свой конфиг в EBCDIC на флэшку и пришли ко мне поработать, а у меня UTF-8. Что будете делать?

Мнение сформировалось давно, самое позднее в эпоху перехода от CP866 к Windows-1251.
Нет единой кодировки. Просто не существует. Unicode не покрывает множество всех возможных символов. Не говоря уже о том, что собственно юникодных кодировок выше крыши.
Ну Unicode, афаик, наиболее близок к этому идеалу и ещё имеет резерв на расширение, не ломающий (почти) обратную совместимость.
Вот это верно, юникодных слишком много разновидностей.
А что буду делать — у Вас перекодирую. Или Вы перекодируете. В зависимости от того, где и кому нужно. Но у себя я буду хранить в EBCDIC, причём буду ожидать от программ, чтобы они работали сразу в ней без дополнительных телодвижений. На то настройки локали и нужны, чтобы указывать, в какой кодировке работать. (Вообще странно, мне казалось, что это должно быть очевидно, но, видимо, не всегда и не всем.)
Вы правы, не всем. Настройки локали в плане кодировок считаю костылём, обусловенным историческими причинами.
Как-то вы не о том рассуждаете, не логично получается. Как бы надо отличать для чего предназначен файл. Вы же ко мне не придете с конфигом microsoft word, так? Вы придете со своим юзерским файлом file.txt. То же самое должно быть и у программы на python.

Те данные, которые определяют настройки программы должны быть записаны в определенный файл в кодировке, например, utf-8 и не должны содержать юзерских данных в его кодировке (раз этот файл настроек един для всех юзеров системы).

А вот юзер делает себе какой-либо файл с помощью этой проги и прога сохраняет в кодировке его локали, например, в Вашей EBCDIC. Когда этот файл попадет другому юзеру, тот должен будет позаботиться о его перекодировке (как и всякий из нас получивший странный txt), прежде чем дать его проге. Либо прога может помочь ему с перекодировкой, попытавшись ее определить.

Коротко: конфиг общий — UTF-8, конфиг юзера — его кодировка (EBCDIC).
Господи, 21й век, а все еще обсуждают эти кодировки. Всё кроме юникода должно отправиться к праотцам, туда же, куда отправились четырехкилобайтные машины, неужели это неочевидно?
Расскажите это китайцам и японцам, а потом мы все вместе посмеёмся.
А что там не так? Погуглил, не нагуглил.
В юникоде нет части китайского-японского, и не осталось свободных мест?
Ну значит и он должен отправиться к праотцам.

Времена четырехкилобайтных машин прошли. На текст можно тратить сколько угодно места.
Во-первых, не прошли, а во-вторых, узнайте у тех и других, насколько их устраивает Юникод. Будете удивлены.
Так вы, кажется, знаете, чем он их не устраивает. Может расскажете? Не знаком ни с одним китайцем чтобы спросить :(
Краткий ответ я уже здесь писал, а за подробностями отправляйтесь в гугль, там Вам лучше расскажут, чем я.
Да, и не забывайте про:

А ASCII? вообще-то, очень часто используемая кодировка, и я часто к ней прибегал, когда тот же текст, например, с конфигом, где строковые данные не хранятся, если кодирован в UTF-8, то займет больше места, чем в ASCII. А информация в свою очередь не меняется!

Ну вот опять. Куда же вы так торопитесь?

Wikipedia: UTF-8 was designed for backward compatibility with ASCII: the first 128 characters of Unicode, which correspond one-to-one with ASCII, are encoded using a single byte with the same binary value as ASCII, so that valid ASCII text is valid UTF-8-encoded Unicode as well.

Хорошая статья, спасибо за перевод.
Вообще сложно себе представить как это всё происходит. Мелкие скрипты написать так, что бы работали и под python2 и под python3 не проблема, но вот портировать библиотеки… Наверное это действительно огромная головная боль. Плюс ничего не сказано про C-extensions — они остались вполне совместимы между Py2 and Py3?
C-extension'ам ещё больше досталось, т.к. очень много изменений в API. Причём есть такие мелкие моменты, что и не обратишь внимание:

Было:
static PyTypeObject mytype = { PyObject_HEAD_INIT(NULL) 0, ... };

Стало:
static PyTypeObject mytype = { PyVarObject_HEAD_INIT(NULL, 0) ... };
Я конечно считаю, что обратную совместимость часто можно выкинуть, но блин они либо не должны затрагивать разработчиков тысяч библиотек, либо должны приносить какую-то реальную и большую пользу.

Вот что полезного дало изменения которое вы показали? Наверное стало что-то «очевиднее», но совсем чуть-чуть.
они = «изменения ломающие обратную совместимость»
Кстати, вот интересная вещь. Есть такой язык, Tcl. Так вот, несмотря на то, что он постоянно развивается, API меняются таким образом, что минимально ломают обратную совместимость, а чаще всего не ломают совсем. Причём, как на уровне Tcl, так и на уровне C. С большой вероятностью C-расширение, написанное для бородатой версии Tcl, можно с полпинка завести на свежем срезе development-версии. Если же речь идёт о коде на Tcl, то 90% кода работать будет просто сразу, без модификаций, только быстрее :)
З.Ы. Tcl вспоминаю не холивора ради, а просто для того, чтобы показать, как бывает по-другому.
К сожалению с C-extensions имел очень мало дела на Python 3, но в данном примере — изменения описанные в PEP 3123, связанные с С-шным «strict aliasing rules». А вообще на практике очень многое решается с помощью макросов.
Ну я вообще работал только с cython и то просто побаловаться и сравнить. Пилил какую-то pygame штуку и привязывал к ней cython математику, собирался сравнить производительность — но так руки и не добрались.

offtop:
как там, кстати с играми на питоне? PyGlet вижу давно не обновлялся. Pygame вроде не плох, но все готовые либы для ускорения ччерез opengl как правило ломают стандартные спрайты и вводят свои. И когда я последний раз проверял такие либы, то все они были или бородатые или бесполезные.

Хочу rapid game development with python с opengl, коллизиями и физикой из коробки! Плюс много сторонних хороших либ для side-scrolling, изометрии, скролинга больших миров и т.д. Из последнего — почти всё есть в pygame, но порой трудно найти.
посмотрел новости pygame: на GSoC нынче три проекта — удобный гуи, улучшение спрайтов и сцен, и лёгкиё networking. В целом наверное неплохо, да и видно, что зазвитие идёт. Есть ли «крутые» долгоиграюзие проекты на pygame?
kivy.org?
Ну в Python 3 как раз и шли к максимальной очевидности.

Мне кажется, лучше переболеть один раз, зато избавиться от всех legacy проблем.
Согласен. Только проблема в том, что можно не вылечиться… к сожалению, болезни иногда переходят в хроническую стадию…
Обратную совместимость питона итак сломали, поэтому кромсали апи на всю катушку — такая возможность еще не скоро представится :)
Десять лет моя жизнь проходит вместе с Python. И пока это бОльшая часть моей жизни.

Правильно ли я понимаю, что Армину 19 лет и python он использует с девяти?
Ему 23 :) Думаю он имел ввиду «сознательную» часть жизни. Вот его профиль на stackoverflow.
Лично я не буду сильно переживать, если доля питона уменьшится. Уж слишком тормозные вещи на нем выходят.

PS Ну и замены Scheme на Python, в базовых курсах MIT, никогда не прощу.
Минусующие комрады, вы хоть скажите с чем не согласны? Или у меня одного запуск synaptic занимает неприлично много времени?
incogn1too, я лично не минусовал, но фраза «уж слишком тормозные вещи на нём выходят» без приведения конкретных примеров (да и сама по себе) — показывает твою некомпетентность в данной области.
Да я вроде указал пример — synaptic. Установлен почти во всех Linux дистрибутивах.
Что делать синаптику «почти на всех линукс дистрибутивах»?
И тормозит он совсем не из-за питона, тем более, что написан на С.
Могу предположить за пренебрежительное отношение к любимому языку минусующих :) А так, по сути, а кто ему на замену придёт? Ruby? JavaScript? прости господи, PHP?
Комрады, тормозные вещи на питоне, Scheme. Я думаю ты и двух заданий из SICP не сделал.
Так думать — ваше право, но думы не всегда соотвецтвуют действительности.
Орфография.
Благодарю.
* соответствуют
Не нравится — напишите свой synaptic на С.
Я считаю, Python вообще не для десктопных аппликаций. В вебе на нем писать легко и приятно, что доказывает огромное кол-во популярных фреймворков (начиная от Tornado, кончая Django и Flask). Замен для себя не вижу — Ruby медленнее (+ учить новый синтаксис, стандарты и тд. — не хочу), JS — пока несерьезно (нет даже неймспейсов — говорить не о чем), Java — на всяких JSF и Spring кол-во кода не идет ни в какое сравнение с тем-же Flask, C# — хоть и по работе занимаюсь с ASP.NET, для своих проектов windows-хостинг заводить не собираюсь (и выкладывать килобаксы за всякие TFS), ASP.NET MVC на Mono выглядит сыро.
В js (серверном, node.js/common js имею в виду), кстати, отличные неймспейсы через require, очень похоже на питоньи импорты, только магии меньше)
да в любом JS есть пространства имен.

(function() {
 ...
)();
у блоков Ruby восхитительный дизайн, но по многим причинам он не прижился бы в Python (в его текущем состоянии).

Вот про это было бы интересно почитать…
По файлам не согласен.
А так подо всем подпишусь.
Некоторые вопросы в Python 3 сделаны правильно, но они сделаны правильно в ущерб простоте. А конек Питона в простоте.
Наверное самая большая проблема Python 3 в том, что он ничего не принес нового, кроме проблем и головной боли. Требовалось избавиться от GIL. Чтобы получить быстроту с работающим кодом Python 2 с некоторыми возможными изменениями.
А изменения ради самих изменений ни к чему хорошему не приводят.
Раньше во времена одноядерников Python развивался, сейчас он стоит. Потому что не сделал шаг в сторону девелоперов, не решили проблемы с GIL и простым общением тредов/процессов.
Всё-таки GIL это часть CPython. Гвидо не раз указывал, что GIL остаётся в его реализации, чтобы не усложнять код. Есть же PyPy, или расширения вроде gevent.
Да, но ни PyPy, ни gevent не решают проблему GIL. Одновременное исполнение нескольких потоков с вычислительными операциями. Единственная попытка решить в лоб — это multiprocessing. А так есть способ писать эффективный код путем смены логики, но не редко за логикой идет и порядочное усложнение кода. Так что «не усложнять» не получается. Раз уж питон все равно обратно не совместим со второй веткой? можно было придумать что-то более эффективное пусть и сложнее. Например в Gо очень хитро придумали с машинами и многопоточностью.
Go всё-таки компилируемый язык со статической типиазацией изначально ориентированный на параллельные вычисления. Мне кажется, что ошибочно сравнивать эти языки.
Я ни в коем случае не сравнивал, просто указал как пример неплохой идеи по многопоточной обработке. Естественно для python такая модель не подойдет, но пока что люди не видят реальных продвижений в эту сторону.
Костыли, опять же.

То есть решения на уровне C нет.
Я свой веб-фрэймворк и шаблонизотор ене написал (пока), но о строках и кодировках успел составить противоположное мнение. С третьим Питоном функция, принимающая строку, ругается на байты и наоборт. Во втором же неявные decode('ascii')/encode('ascii') меня всегда запутывали. Кому вообще нужна кодировка ascii? Приходилось постоянно подглядывать в документацию, чтоб вспомнить, что же именно возвращает очередной метод — чистую строку или в какой-то кодировке. В простых случаях приходилось использовать костыль sys.setdefaultencoding('UTF-8').
Вы не поверите, но ASCII таки нужна…
Верю. Какой-нибудь URL прочитать, например. Это было маленькое эмоциональное преувеличение.
Нет, нормализованный. Такие, конечно, нужно читать как текст.
Вы не поверите, но ASCII таки нужна…

Зачем? Чтобы экономить на размере русских текстов?
Как связаны ASCII и русские тексты? КОИ-7?
Ну, если подходить с этой стороны, «де-юро», то КОИ-7 к ASCII как раз не относится, зато относятся CP-866 и ISO-8859-5. Русский я взял как более близкий местной аудитории и тот факт, что русские ASCII кодировки практически полностью уступили однобайтовой же ANSI — это лишь такой исторический курьёз. Вместо русского можно взять, к примеру, чешский, где едва ли ни основной (на ряду с ANSI CP-1250) однобайтовой кодировкой всё-ещё является ASCII ISO-8859-2 (если мне не изменяет память, именно она на чешских системах ставится кодировкой по умолчанию в почтовиках типа Outlook, Outlook Express, Windows Mail и Thunderbird).

Если Вы имеете ввиду нижнюю половину, чисто английские тексты, то я вообще не понимаю о чём тут дискутировать, ведь эти символы, на сколько я понимаю, кодируются в UTF-8 идентично ASCII и разницы тут между ними вроде бы нет.

Я говорил о том, что единственный (кроме относительной сложности реализации) известный мне аргумент против UTF-8 (в пользу однобайтовых ASCII/ANSI/KOI) — что текст на языке с интенсивным использованием специфических символов (в частности язык с не-латинской графикой) в однобайтовой кодировке занимает меньше места, чем в UTF-8. Кроме желания сэкономить на этом, не вижу причин использовать кодировки отличные от UTF-8 (можно, конечно, ещё вспомнить об UTF-16 и UTF-32 но, на сколько я понимаю (поправьте если ошибаюсь), по сравнению с UTF-8 они просто устарели).

Понимаю, что рискую прослыть максималистом и вызывать справедливое негодование многих, но считаю, что в современном языке программирования стандартным представлением любой строки (и без всяких костылей) должно быть UTF-8 (на крайняк UTF/UCS-чего-нибудь-ещё). При чтении текста из внешнего потока входная кодировка должна либо (в случае умолчания) браться из локали (на сколько я понимаю, тут так и сделано, что и вызвало негодование автора), либо не браться и считаться априори (спорно) UTF-8, либо указываться программистом явно (надеюсь такая возможность есть, иначе действительно фигня).

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

Если я не прав — буду признателен на указания в чём и почему (кроме соображений экономии — о них, как я уже указал, мне известно).
UTF-16 и UTF-32 не устарели. У них просто немного другая ниша — быстрая обработка данных.
Вот представь, что тебе нужно изменить один символ в UTF-8 и новый символ имеет другую байтовую длину. Получается, что нужно перестроить весь массив после этого символа, что довольно затратно. Плюс к этому, размер данных нельзя посчитать исходя из количества символов (бывает важно для низкоуровневых языков).
Или посмотри на алгоритм чтения символов из UTF-8… Нельзя просто брать нужное количество байт и не париться.
Поэтому, например, Qt используют UTF-16 для своего QString.
Проблема добавления поддержки 3го питона в библиотеки есть, но не так уж все и плохо. Новые библиотеки достаточно просто писать так, чтоб они поддерживали и 2.х, и 3.х без всяких утилит 2to3.

«Хаки вроде sys.exc_info()[1], для обхода синтактических различий, хаки конвертирования литералов во время исполнения для совместимости с 2.х и 3.x» — эти хаки не нужны, если не поддерживать 2.5. А его поддерживать imho не нужно, т.к. в него даже security-обновлений не будет больше, да и в хоть как-то актуальных ОС его нет (в предыдущем долгоиграющем red hat 2.4, а не 2.5, и это совсем другая история).

Очень многие «большие» старые библиотеки уже портированы (вот это бывает трудно, да). C-расширения можно писать не напрямую, а через ctypes, cython и тд — поддержка 3го питона тогда в них появляется более-менее автоматически. Писать C-расширения на C все равно не очень хорошо, т.к. под pypy они если и заведутся, то по-тормозному.

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

Я сейчас посчитал, у меня 8 штук своих open-source библиотек, которые под 2.х и 3.х работают из одного исходного кода (втч с C расширениями), + несколько чужих библиотек портировал (или помогал портировать). Писать новый код, который и там, и там работает — совсем не сложно, это просто дело привычки, и выглядит он ничем не хуже, чем код для 2.х (а часто даже и лучше, т.к. приучаешься к __future__ импортам и более новым языковым конструкциям). Портировать — сложнее, особенно большие, старые или трюкачистые, но тоже вполне реально (nltk так и не допортировал окончательно, но там большая часть тестов уже проходит, и пара глав из nltk book работает, жду помощи из-за границы теперь).
Кстати, какие реальные кейсы написания нового кода для 2х и 3х одновременно? Почему бы не писать сразу под 3х?
Я такой кейс встретил, когда разбирал работу ObjectID в MongoDB'шном BSON (имею ввиду биндинги для питона). Уж очень напоминает #ifdef WINDOWS ... и похожую лабуду.
Это смотря как писать. if PY3:… else:… — это дурной тон и почти никогда не нужно. Без ветвления 2-3 часто можно обойтись, а когда нельзя — оно выносится в отдельный модуль (типа compat.py) и не засоряет код.

pymongo (о нем ведь речь) еще недавно поддерживал (о ужас!) python 2.3, ясно-понятно там куча хаков будет даже без поддержки 3го питона. 2.4-то поддерживать невесело. По-моему писать код, совместимый с 2.3 — 2.7 посложнее будет, чем 2.6 — 3.2, и сам код жутковатым будет, в отличие от варианта 2.6-3.2.
Сейчас все еще бОльшая часть нового кода — под 2й питон пишется, и поддержка библиотекой 2го питона — большой плюс.
Спасибо за перевод и публикацию! Всё, что разрабатывает Армин отличается редкой элегантностью и продуманностью. Взять хотя бы его flask и Jinja2. Поэтому многое, что он пишет в своем блоге заслуживает внимательного прочтения и дальнейшего обдумывания.

PS: Только не понятно, почему вы сократили его фамилию(?) Фамилия австрийская и читается Ронахер. С ударением на первый слог.
Просто казалось, что «Ronacher» будет читаться как «Ронаха» по аналогии с напр. «Arbeiter» -> «Арбайта», где окончание сглатывается за счёт нисходящей интонации.

(P.S. это воспоминания из школьного немецкого, поправьте пожалуйста, если не прав).
:) это вы перегибаете. тогда уж «Ронахэ».

Но мы же говорим «Ганновер», а не «Ханофэ» просто потому что есть определенные традиции транскрибирования.
Спасибо за разъяснение. Изменил.
Мелкий нюанс перевода:
«Я насчитал сотню экземпляров одной заглавной буквы в этом тексте.»

В русском языке «я» далеко не всегда пишется с заглавной буквы, в отличие от английского. Поэтому людям незнакомым с английским фраза вероятно будет непонятна.

В целом же перевод хороший. Автору большое спасибо.
При всё моём уважении к Армину и его библиотекам/флеймвокам, он, всё-таки, истеричка. Нет, я совершенно не хочу его унизить, оскорбить или обидеть. Просто он очень испугался нововведений и тому, что нужно поддерживать две ветки своих проектов.
Его PEP-0414 вообще бредовый — ну зачем нужны эти атавизмы?
Даже не знаю, что ещё сказать… Например, имена файлов в py2 я уже лет пять, как пишу в юникоде и не вижу вообще никаких проблем. Зависимость от локали, это совершенно правильно — настраивайте свою локаль так, чтобы не было неоднозначностей.
Поддерживать 2.5… Да я и 2.6 предпочитаю не поддерживать, если для этого нужно большее, чем поставить индексы при форматировании строк (u'{0}-{1}'.format()).

В общем, делайте свои выводы из написаного, а не берите на веру.

P.S. Читал ещё полгода назад…
Можно пожалуйста пример Ваших проектов, или хотя бы приблизительное сравнение по размеру пользовательской базы с проектами Армина? Это к поддержке старых версий Python.
И при чём тут имена файлов в Py2? Он про работу фс в Py3 писал.
Вот находятся же умники… Ещё раз перечитай статью, потом мой комментарий и подумай, что ты спросил не так.
Мне понравился термин «флеймвок», надо взять на вооружение.
Вот находятся же умники… Ещё раз перечитай статью, потом мой комментарий и подумай, что ты спросил не так.
Не туда, сорри.
Ну и что плохого в том, что строка — это набор символов Юникод, а не байтов?
Массив байтов теперь правильно называется, и прекрасно декодируется в Юникод и обратно при указании локали.
Большинство библиотек работающих с пересылкой данных по сети требуют кроме 2to3 ещё и дополнительных правок с encode() и decode() и это здорово.
Теперь мы пересылаем по сети массивы байт, а не строки, как и было задумано.
Наконец-то это древний допотопный анахронизм про то что байт = символ уходит в прошлое. Мне не нужно думать о том что такое символ, не нужно думать о кодировке, у меня есть строка и я всегда уверен что она однозначно определена.
Большое спасибо за перевод, статья интересная, хоть и излишне экспрессивная.
URL это строка байтов или символов?
Байтов. Не ascii преобразовываются пуникодом.
Вообще-то обычная строка, либо Request:
urllib.request.urlopen(url, data=None[, timeout], *, cafile=None, capath=None)
Open the URL url, which can be either a string or a Request object.
docs.python.org/py3k/library/urllib.request.html
И это — логично!
С точки зрения питона да, всё верно.
> И это — логично!

а теперь прикиньте во что превращается аккуратное:
url = "http://%s:%d/" % (host, port)
в p3k.

зы: не троллинга ради — это Армин так писал lucumr.pocoo.org/2010/5/25/wsgi-on-python-3/ :)
Если host — строка, то ни во что криминальное не превращается. Всё как и раньше.
Если host — массив байт, то что мы называем «строкой» в С++ или Python 2.x, то нужно писать так:

url = «%s:%d/» % (host.decode('cp1251'), port)

Вот именно из-за аргумента в методе decode() и нельзя считать массив байт строкой. Поскольку в строке каждый элемент — символ, а в массиве байт — каждый элемент байт. Если нужно массив байт однозначно представить строкой — используйте decode(encoding).

Интерпретация чего бы то ни было строкой должна быть явной, либо вы используете __str__.
См. import this — явное лучше неявного. Не уверен в "%s" % X — не пиши.
Собственно, согласен.

P.S. Кстати, вчера случайно выяснили пренеприятную вещь: urllib2 не знает, что такое пуникод и преобразование надо делать самим. :-(

P.P.S. И ещё момент… Пишите уже современно:
url = "http://{:s}:{:d}/".format(host, port)
Это куда красивее!
А почему не просто {} вместо {:s}?
Как-то автоматически. На самом деле я бы написал просто {}. :-)
В ряде случаем, имхо, симпатичнее выглядит старое форматирование:
'Введите значения поля "%s": ' % field_name
Не нужно писать скобки (для одного аргумента), вызывать метод format (опять же со скобками), и мы сразу же принудительно указываем, что выводим строку.
Хотя я конечно фанатею от конструкции
'{:%Y-%d-%m %H:%M:%S}'.format( datetime.now() )
И всё-таки тут я не соглашусь. Мне всегда эти проценты дикостью казались и я был рад от них избавится, даже ценой нескольких символов.

Андрей Светлов, кажется, писал про возможности расширения этого форматироватья. Пример с датой, это ещё цветочки…
мм… не так. если url это массив байтов, значит надо использовать b"":

url = b"http://{:s}:{:d}/".format(host, port)

(если что, это не работает)
Я просто не сразу уловил твой вопрос.

В общем случае, url это массив байт. Т.е. когда ты делаешь, например, http-запрос, у тебя в нём только байты.
В питоне, конечно же, он представляется массивом символов, что вполне логично и понятно.

Но на самом деле, это всё бред. Думаю, что я не сильно погрешу против истины, если заявлю, что URL, это массив ascii-сиволов. Не ascii в хосте кодируется пуникодом, а в пути — utf-8, представленным в шестнадцатиричном виде с помощью того же ascii. По крайней мере так оно работает в http.
Нет, не так, URL — это по сути своей строка, либо Request. Зачем пихать в неё массив байт?
Если тебе прямо так необходимо сделать из строки массив байт, то используй encode(xxx) с нужной тебе кодировкой.
"http://{:s}:{:d}/".format(host, port).encode('cp1251')
Правда если ты хочешь именно URL, и жаждешь самостоятельно перекодировать и отправлять байты, то тут тебя ждут отличные перспективы велосепеда. Используй строку.
это не мне необходимо, а www.python.org/dev/peps/pep-3333/#unicode-issues :)
хочу сказать, что если в python2 «суть строк» была вполне утино-однотипна, то разработчики p3k, соорудили для нас самостоятельную заморочку. что, например, в стеке wsgi приводит к нескончаемой череде этих самых decode() / encode().
Как раз нет, на уровне протокола уже нужно оперировать массивами байт. Благо методы у них примерно такие же. Зато не происходит подмена понятий байт-символ и нет этой вечной путаницы с кодировками на уровне строк, которые должны представляться однозначно на своём уровне абстракции.
уровни абстракции это компромисс между нужностью и удобством. и чем их меньше приходится создавать, тем лучше. как пишут в букваре, сообщение http представляет собой последовательность октетов. поэтому «массив байт» это тоже — абстракция. так вот, нужна-ли она, такая? ведь очевидно же, что в p3k удобства, в этом плане, стало меньше, а хорошо задокументированных заморочек — больше.
>>> '1' == '1'[0]
True
>>> b'1' == b'1'[0]
False
Как раз это здорово, что понятия символа отделили от понятия байта. То что символ можно сравнивать с односимвольной строкой — это логично, и подобное лексическое сравнение есть везде. А вот второе бред — сравнивать массив байт с байтом. Естественно False. Всё логично, как и всегда в питоне.
Что до уровней абстракции, то они всегда возникают естественным путём. В данном случае строка имеет неизмеримо высший уровень абстракции нежели массив байт. Вы же не задумываетесь о кодировке, когда что-то пишете на бумаге.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории