Проблемът е, че извиквате encode
на str
обект.
A str
е байтов низ, обикновено представляващ текст, кодиран по някакъв начин като UTF-8. Когато извикате encode
при това първо трябва да се декодира обратно в текст, така че текстът да може да бъде повторно кодиран. По подразбиране Python прави това, като извиква s.decode(sys.getgetdefaultencoding())
и getdefaultencoding()
обикновено връща 'ascii'
.
И така, вие говорите UTF-8 кодиран текст, декодирате го сякаш е ASCII, след което го прекодирате в UTF-8.
Общото решение е изрично да се извика decode
с правилното кодиране, вместо да позволи на Python да използва стандартното и след това encode
резултатът.
Но когато правилното кодиране вече е това, което искате, по-лесното решение е просто да пропуснете .decode('utf-8').encode('utf-8')
и просто използвайте UTF-8 str
като UTF-8 str
че вече е.
Или, алтернативно, ако вашата MySQL обвивка има функция, която ви позволява да посочите кодиране и да върнете unicode
стойности за CHAR
/VARCHAR
/TEXT
колони вместо str
стойности (напр. в MySQLdb предавате use_unicode=True
към connect
повикване или charset='UTF-8'
ако вашата база данни е твърде стара, за да я откриете автоматично), просто направете това. Тогава ще имате unicode
обекти и можете да извикате .encode('utf-8')
върху тях.
Като цяло най-добрият начин за справяне с проблемите с Unicode е последният – декодирайте всичко възможно най-рано, направете цялата обработка в Unicode и след това кодирайте възможно най-късно. Но така или иначе, трябва да сте последователни. Не извиквайте str
върху нещо, което може да е unicode
; не свързвайте str
литерал към unicode
или предайте един към неговия replace
метод; и т.н. Всеки път, когато смесвате и съчетавате, Python ще преобразува имплицитно вместо вас, използвайки вашето кодиране по подразбиране, което почти никога не е това, което искате.
Като странична бележка, това е едно от многото неща, с които промените в Unicode на Python 3.x помагат. Първо, str
вече е Unicode текст, а не кодирани байтове. По-важното е, че имате кодирани байтове, например в bytes
обект, извикващ encode
ще ви даде AttributeError
вместо да се опитва да декодира тихо, за да може да кодира отново. И по подобен начин, опитвайки се да смесите и съчетаете Unicode и байтове, ще получите очевидна TypeError
, вместо имплицитно преобразуване, което успява в някои случаи и дава загадъчно съобщение за кодиране или декодиране, което не сте поискали в други.