Same as unicode(str(1)).
>>> class thing(object):
...     def __str__(self):
...         print "__str__ called on " + repr(self)
...         return repr(self)
...
>>> a = thing()
>>> a
<__main__.thing object at 0x7f2f972795d0>
>>> unicode(a)
__str__ called on <__main__.thing object at 0x7f2f972795d0>
u'<__main__.thing object at 0x7f2f972795d0>'
If you really want to see the gritty bits underneath, open up the Python interpreter source code.
Objects/unicodeobject.c#PyUnicode_Type defines the unicode type, with constructor .tp_new=unicode_new.
Since the optional arguments encoding or errors are not given, and a unicode object is being constructed (as opposed to a unicode subclass), Objects/unicodeobject.c#unicode_new calls PyObject_Unicode.
Objects/object.c#PyObject_Unicode calls the __unicode__ method if it exists.  If not, it falls back to PY_Type(v)->tp_str (a.k.a. __str__) or PY_Type(v)->tp_repr (a.k.a. __repr__).  It then passes the result to PyUnicode_FromEncodedObject.
Objects/unicodeobject.c#PyUnicode_FromEncodedObject finds that it was given a string, and passes it on to PyUnicode_Decode, which returns a unicode object.
Finally, PyObject_Unicode returns to unicode_new, which returns this unicode object.
In short, unicode() will automatically stringify your object if it needs to.  This is Python working as expected.