Q:

Unicode and overriding '__str__'

I'm getting a unicode error only when overriding my class' __str__ method.   What's going on? 
In Test.py:
class Obj(object):

    def __init__(self):
        self.title = u'\u2018'

    def __str__(self):
        return self.title

print "1: ", Obj().title
print "2: ", str(Obj())

Running this I get:
$ python Test.py
1:  ‘
2: 
Traceback (most recent call last):
  File "Test.py", line 11, in <module>
    print "2: ", str(Obj())
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2018' in position 0: ordinal not in range(128)

EDIT: Please don't just say that str(u'\u2018') also raises an Error! ( while that may be related).   This circumvents the entire purpose of built-in method overloading --- at no point should this code call str(u'\u2018')!! 

A:

You're using Python 2.x.  str() calls __str__ and expects you to return a string—that is, a str.  But you're not; you're returning a unicode object.  So str() helpfully tries to convert that to a str since it's what str() is supposed to return.  
Now, in Python 2.x strings are sequences of bytes, not codepoints, so Python is trying to convert your Unicode object to a sequence of bytes.  Since you didn't (and can't, in this scenario) specify what encoding to use when making the string, Python uses the default encoding of ASCII.  This fails because ASCII can't represent the character. 
Possible solutions:

Use Python 3, where all strings are Unicode.  This will provide you with an entertainingly different set of things to wrap your head around, but this won't be one of them. 
Override __unicode__() instead of __str__() and use unicode() instead of str() when converting your object to a string.  You still have the problem (shared with Python 3) of how to get that converted into a sequence of bytes that will output correctly. 
Figure out what encoding your terminal is using (i.e. sys.stdout.encoding) and have __str__() convert the Unicode object to that encoding before returning it.  Note that there's still no guarantee that the character is representable in that encoding; you can't convert your example string to the default Windows terminal encoding, for example.  In this case you could fall back to e.g. unicode-escape encoding if you get an exception trying to convert to the output encoding.