This article is part of in the series
Published: Wednesday 9th May 2012
Last Updated: Thursday 12th December 2013
This article is on Unicode with Python 2.x If you want to learn about Unicode for Python 3.x, be sure to checkout our Unicode for Python 3.x article. Also, if you're interested in checking if a Unicode string is a number, be sure to checkout our article on how to check if a Unicode string is a number.

Strings are among the most commonly used data types in Python, and there might be times when you want to (or have to) work with strings containing or entirely made up of characters outside of the standard ASCII set (e.g. characters with accents or other markings).

Python 2.x provides a data type called a Unicode string for working with Unicode data using string encoding and decoding methods. If you want to learn more about Unicode strings, be sure to checkout Wikipedia's article on Unicode.

Note: When executing a Python script that contains Unicode characters, you must put the following line at the top of the script, to tell Python that the code is UTF-8/Unicode formatted.

[python]
# -*- coding: utf-8 -*-
[/python]

Python Unicode: Overview

In order to figure out what โ€œencodingโ€ and โ€œdecodingโ€ is all about, letโ€™s look at an example string:

[python]
>>> s = "Flรผgel"
[/python]

We can see our string s has a non-ASCII character in it, namely โ€œรผโ€ or โ€œumlaut-u.โ€. Assuming weโ€™re in the standard Python 2.x interactive mode, letโ€™s see what happens when we reference the string, and when itโ€™s printed:

[python]
>>> s
'Fl\xfcgel'
>>> print(s)
Flรผgel
[/python]

Printing gave us the value that we assigned to the variable, but something obviously happened along the way that turned it from what we typed into the interpreter to something seemingly incomprehensible. The non-ASCII character รผ was translated into a code phrase, i.e. โ€œ\xfc,โ€œ by a set of rules behind-the-scenes. In other words, it was encoded.

At this point, s is an 8-bit string, which to us basically means it isnโ€™t a Unicode string. Letโ€™s examine how to make a Unicode string with the same data. The simplest way is with a โ€œuโ€ prefix in front of the literal string marking it as a Unicode string:

[python]
u = u"Flรผgel"
[/python]

If we reference and print u like we did with s, weโ€™ll find something similar:

[python]
>>> u
u'Fl\xfcgel'
>>> print(u)
Flรผgel
[/python]

We can see that the code phrase for our โ€œumlaut-uโ€ is still โ€œ\xfcโ€œ and it prints the sameโ€”so does that mean our Unicode string is encoded the same way as our 8-bit string s? To figure that out letโ€™s look at what the encode method does when we try it on u and s:

[python]
>>> u.encode('latin_1')
'Fl\xfcgel'
>>> s.encode('latin_1')
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
s.encode('latin_1')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xfc in position 2: ordinal not in range(128)
[/python]

Now it seems encoding the Unicode string (with the โ€˜latin-1โ€™ encoding) retuned the same value as string s, but the encode method didnโ€™t work on string s. Since we couldnโ€™t encode s, what about decoding it? Will it give us the same value as u? Letโ€™s find out:

[python]
>>> s.decode('latin-1')
u'Fl\xfcgel'
[/python]

Thatโ€™s exactly what it does after all. So then, what difference does it make that s is an 8-bit string and u is a Unicode string? They behave the same way, donโ€™t they? In our โ€œumlaut-uโ€ example, there seemed to be little difference, aside from the โ€œuโ€ hanging out in front of the Unicode string.

Well, the difference is that the Unicode string u was using a code phrase that the Unicode standard defines for the character โ€œumlaut-u,โ€ and the 8-bit string s was using a code phrase that the "latin-1" codec (rule-set) defines for โ€œumlaut-u.โ€

OK, well... thatโ€™s great, but... they were still the same, right? So why does that matter?

To illustrate the difference and why it matters, letโ€™s consider a new 8-bit string:

[python]
new_s = '\xe5\xad\x97'
[/python]

Unlike the first one, our new 8-bit string is only code phrasesโ€”completely incomprehensible.

Why didnโ€™t we just type in (or copy-and-paste) the characters like the last 8-bit string? Well, assuming weโ€™re still using the standard Python 2.x console/IDLE, we couldnโ€™t type or paste this value into the interpreter โ€” as it would not accept the value if we did. Why? Because our new_s is an encoded string for an Asian script character (yes, only one character), and the interactive mode/IDLE is averse to such input (if you have the appropriate input keyboard installed for your system you can try this and find out).

The question now is how can we turn these code phrases into the character theyโ€™re supposed to display? In the first example using a print statement on s worked fine, so it should be the same with new_s, right? Letโ€™s see what our unknown Asian script character is:

[python]
>>>print new_s
รฅยญโ€”
[/python]

Uh-oh... that isnโ€™t right. First of all, that is not an Asian script character. Secondly, itโ€™s more than one character.  Simply referencing new_s would give us the string we assigned to it, and print didnโ€™t seem to work. Letโ€™s see if a Unicode string will help us out.

To create our new Unicode string new_u, we canโ€™t follow the method in our first example โ€” to do that weโ€™d have to input the literal character of our string with a โ€œuโ€ prefix (we havenโ€™t seen our character yet, and anyway the interactive mode/IDLE wouldnโ€™t accept it as input).

However, we did get the value of u by decoding s, so in the same way we should be able to get the value for our new_u by decoding new_s. Letโ€™s try decoding as we did in the first example:

[python]
>>> new_u = new_s.decode('latin_1')
>>> new_u
u'\xe5\xad\x97'
[/python]

Great, now that weโ€™ve stored the decoded new_s string value using the same method as in our first example, letโ€™s print our Unicode string and see what our script character is:

[python]
>>> print(new_u)
รฅ
[/python]

ยญย—Uh... Isnโ€™t that the same thing we got when we tried to print the ยญยญnew_s string?? So then using the Unicode string really isnโ€™t any different?

Not so fastโ€”thereโ€™s one detail that was purposefully glossed-over to prove a point: the encoding we used to decode the string is the same as the first example, the โ€˜latin-1โ€™ codec. However, the 8-bit string new_s was not encoded in โ€˜latin-1,โ€™ it was encoded in โ€˜utf-8.โ€™

Okay, so there was no way for you really to know that unless explicitly told, but this still illustrates the point: the encoding/codec/rule-set makes all the difference when encoding/decoding strings.

With the right encoding, letโ€™s see what happens:

[python]
>>> new_u = new_s.decode('utf_8')
>>> new_u
u'\u5b57'
>>> print(new_u)
ๅญ—
[/python]

FINALLY! Our long-lost script character has been found, and it looks pretty good. Now, try copying-and-pasting the character as inputโ€”youโ€™ll find it doesn't work (weโ€™re still talking about Python 2.x interactive mode/IDLE).

You might also notice something different about the value of new_u, i.e. it appears to consist of only one code phrase (this time in the form โ€˜\uXXXXโ€™). This Unicode standard has a unique code phrase for every character or script character that can possibly be displayed on your screen. With that in mind you can also tell that the first time we tried to decode new_s, the value was wrong (โ€œuโ€™\xe5\xad\x97โ€™โ€ has 3 code phrases, and for the Unicode standard, that means 3 unique characters).

Well, now that those annoying examples are finished, letโ€™s recap the main points of all this hoopla:

  1. Strings are one of the most common data types in Python, and sometimes theyโ€™ll include non-ASCII characters.
  2. When strings contain non-ASCII characters, they can either be 8-bit strings (encoded strings), or they can be Unicode strings (decoded strings).
  3. To print or display some strings properly, they need to be decoded (Unicode strings).
  4. THE ENCODING/CODEC MAKES ALL THE DIFFERENCE WHEN ENCODING/DECODING STRINGS.

The encoding/codec is like the DNA of your stringโ€”even with the same nutrients (input), using the wrong DNA (codec) will give you an orange when you should have had an apple..