Попробуйте использовать свободно доступный класс ImageInfo, я использовал его для этой же цели:
http://linux.softpedia.com/get/Multimedia/Graphics/ImageInfo-19792 .shtml
Здесь задействованы два разных персонажа. Один из них - MICRO SIGN , который находится на клавиатуре, а другой - GREEK SMALL LETTER MU .
Чтобы понять, что происходит, мы должны посмотреть, как Python определяет идентификаторы в справочнике языка :
identifier ::= xid_start xid_continue*
id_start ::= <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property>
id_continue ::= <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property>
xid_start ::= <all characters in id_start whose NFKC normalization is in "id_start xid_continue*">
xid_continue ::= <all characters in id_continue whose NFKC normalization is in "id_continue*">
Оба наших символа, MICRO SIGN и GREEK SMALL LETTER MU являются частью Ll
unicode group (строчные буквы), поэтому оба они могут использоваться в любой позиции в идентификаторе. Теперь обратите внимание, что определение identifier
на самом деле относится к xid_start
и xid_continue
, и они определены как все символы в соответствующем не-х определении, чья нормализация NFKC приводит к допустимой последовательности символов для идентификатора.
Очевидно, что Python заботится только о нормализованной форме идентификаторов . Это подтверждается немного ниже:
Все идентификаторы преобразуются в обычную форму NFKC во время разбора; сравнение идентификаторов основано на NFKC.
blockquote>NFKC - это нормализация Юникода , которая разлагает символы на отдельные части. MICRO SIGN распадается на GREEK SMALL LETTER MU, и это именно то, что происходит там.
На эту нормализацию также влияет множество других символов. Другим примером является OHM SIGN , который распадается на GREEK CAPITAL LETTER OMEGA . Использование этого в качестве идентификатора дает аналогичный результат, здесь показано с использованием locals:
>>> Ω = 'bar' >>> locals()['Ω'] Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> locals()['Ω'] KeyError: 'Ω' >>> [k for k, v in locals().items() if v == 'bar'][0].encode() b'\xce\xa9' >>> 'Ω'.encode() b'\xe2\x84\xa6'
Итак, в конце концов, это именно то, что делает Python. К сожалению, на самом деле нет хорошего способа обнаружить это поведение, вызывая ошибки, такие как показанные. Обычно, когда идентификатор упоминается только как идентификатор, то есть он используется как реальная переменная или атрибут, тогда все будет нормально: нормализация выполняется каждый раз, и идентификатор найден.
Единственный проблема связана со строковым доступом. Строки - это просто строки, конечно, нормализации не происходит (это будет просто плохая идея). И два способа, показанные здесь,
getattr
иlocals
, оба действуют на словари.getattr()
получает доступ к атрибуту объекта через__dict__
объекта, аlocals()
возвращает словарь. И в словарях клавишами может быть любая строка, поэтому вполне нормально иметь MICRO SIGN или OHM SIGN там.В этих случаях вам нужно помнить о том, чтобы выполнить нормализацию самостоятельно. Для этого мы можем использовать
unicodedata.normalize
, что также позволяет нам правильно получить наше значение изнутриlocals()
(или используяgetattr
):>>> normalized_ohm = unicodedata.normalize('NFKC', 'Ω') >>> locals()[normalized_ohm] 'bar'
Что здесь делает Python на основе Стандартное приложение Unicode № 31 :
Реализации, которые принимают нормализацию и учитывают случай, имеют два выбор: рассматривать варианты как эквивалентные или запрещать варианты.
blockquote>Остальная часть этого раздела дает более подробную информацию, но в основном это означает, что если язык позволяет вам иметь идентификатор с именем
µ
, он должен обрабатывать два символаµ
MICRO SIGN и GREEK SMALL LETTER MU, и он должен делать это, рассматривая их как GREEK SMALL LETTER MU.
Most другие языки, которые допускают не-ASCII-идентификаторы, следуют одному и тому же стандарту: 1 только несколько языков придумали свои собственные2. Таким образом, это правило имеет то преимущество, что оно одинаково на самых разных языках (и, возможно, оно поддерживается IDE и другими инструментами ).
Можно было бы сделать вывод, что он действительно не работает на языке, как отраженный, как Python, где строки могут использоваться как идентификатор так же легко, как писать
getattr(Test, 'µ')
. Но если вы можете прочитать обсуждение рассылки python-3000 , вокруг PEP 3131 ; единственное, что серьезно рассматривалось, - это придерживаться ASCII, UAX-31 или незначительных вариаций Java на UAX-31; никто не хотел изобретать новый стандарт только для Python.Другим способом решения этой проблемы было бы добавить тип
< hr>collections.identifierdict
, который документирован для применения тех же правил поиска, которые компилятор применяет для идентификаторов в источнике, и использовать этот тип в сопоставлениях, предназначенных для использования в качестве пространств имен (например, объект, модуль, локали, определения классов). Я смутно помню, что кто-то предлагал это, но не имел хороших мотивирующих примеров. Если кто-то считает, что это хороший пример для оживления идеи, они могут опубликовать ее на bugs.python.org или списке идей python .1. Некоторые языки, такие как ECMAScript и C #, вместо этого используют «стандарт Java», который основан на ранней форме UAX-31 и добавляет некоторые незначительные расширения, такие как игнорирование управляющих кодов RTL, но это достаточно близко.
2. Например, Julia позволяет использовать символы Unicode и математические символы, а также имеет правила для сопоставления между идентификаторами LaTeX и Unicode, но они явно добавили правила для нормализации
ɛ
иµ
к греческим ...
class Test: mu = 'foo'
– Galax 4 December 2015 в 22:02