PEP: Generalised String Coercion

  • Thread starter Neil Schemenauer
  • Start date
N

Neil Schemenauer

The title is perhaps a little too grandiose but it's the best I
could think of. The change is really not large. Personally, I
would be happy enough if only %s was changed and the built-in was
not added. Please comment.

Neil


PEP: 349
Title: Generalised String Coercion
Version: $Revision: 1.2 $
Last-Modified: $Date: 2005/08/06 04:05:48 $
Author: Neil Schemenauer <[email protected]>
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 02-Aug-2005
Post-History: 06-Aug-2005
Python-Version: 2.5


Abstract

This PEP proposes the introduction of a new built-in function,
text(), that provides a way of generating a string representation
of an object without forcing the result to be a particular string
type. In addition, the behavior %s format specifier would be
changed to call text() on the argument. These two changes would
make it easier to write library code that can be used by
applications that use only the str type and by others that also
use the unicode type.


Rationale

Python has had a Unicode string type for some time now but use of
it is not yet widespread. There is a large amount of Python code
that assumes that string data is represented as str instances.
The long term plan for Python is to phase out the str type and use
unicode for all string data. Clearly, a smooth migration path
must be provided.

We need to upgrade existing libraries, written for str instances,
to be made capable of operating in an all-unicode string world.
We can't change to an all-unicode world until all essential
libraries are made capable for it. Upgrading the libraries in one
shot does not seem feasible. A more realistic strategy is to
individually make the libraries capable of operating on unicode
strings while preserving their current all-str environment
behaviour.

First, we need to be able to write code that can accept unicode
instances without attempting to coerce them to str instances. Let
us label such code as Unicode-safe. Unicode-safe libraries can be
used in an all-unicode world.

Second, we need to be able to write code that, when provided only
str instances, will not create unicode results. Let us label such
code as str-stable. Libraries that are str-stable can be used by
libraries and applications that are not yet Unicode-safe.

Sometimes it is simple to write code that is both str-stable and
Unicode-safe. For example, the following function just works:

def appendx(s):
return s + 'x'

That's not too surprising since the unicode type is designed to
make the task easier. The principle is that when str and unicode
instances meet, the result is a unicode instance. One notable
difficulty arises when code requires a string representation of an
object; an operation traditionally accomplished by using the str()
built-in function.

Using str() makes the code not Unicode-safe. Replacing a str()
call with a unicode() call makes the code not str-stable. Using a
string format almost accomplishes the goal but not quite.
Consider the following code:

def text(obj):
return '%s' % obj

It behaves as desired except if 'obj' is not a basestring instance
and needs to return a Unicode representation of itself. In that
case, the string format will attempt to coerce the result of
__str__ to a str instance. Defining a __unicode__ method does not
help since it will only be called if the right-hand operand is a
unicode instance. Using a unicode instance for the right-hand
operand does not work because the function is no longer str-stable
(i.e. it will coerce everything to unicode).


Specification

A Python implementation of the text() built-in follows:

def text(s):
"""Return a nice string representation of the object. The
return value is a basestring instance.
"""
if isinstance(s, basestring):
return s
r = s.__str__()
if not isinstance(r, basestring):
raise TypeError('__str__ returned non-string')
return r

Note that it is currently possible, although not very useful, to
write __str__ methods that return unicode instances.

The %s format specifier for str objects would be changed to call
text() on the argument. Currently it calls str() unless the
argument is a unicode instance (in which case the object is
substituted as is and the % operation returns a unicode instance).

The following function would be added to the C API and would be the
equivalent of the text() function:

PyObject *PyObject_Text(PyObject *o);

A reference implementation is available on Sourceforge [1] as a
patch.


Backwards Compatibility

The change to the %s format specifier would result in some %
operations returning a unicode instance rather than raising a
UnicodeDecodeError exception. It seems unlikely that the change
would break currently working code.


Alternative Solutions

Rather than adding the text() built-in, if PEP 246 were
implemented then adapt(s, basestring) could be equivalent to
text(s). The advantage would be one less built-in function. The
problem is that PEP 246 is not implemented.

Fredrik Lundh has suggested [2] that perhaps a new slot should be
added (e.g. __text__), that could return any kind of string that's
compatible with Python's text model. That seems like an
attractive idea but many details would still need to be worked
out.

Instead of providing the text() built-in, the %s format specifier
could be changed and a string format could be used instead of
calling text(). However, it seems like the operation is important
enough to justify a built-in.

Instead of providing the text() built-in, the basestring type
could be changed to provide the same functionality. That would
possibly be confusing behaviour for an abstract base type.

Some people have suggested [3] that an easier migration path would
be to change the default encoding to be UTF-8. Code that is not
Unicode safe would then encode Unicode strings as UTF-8 and
operate on them as str instances, rather than raising a
UnicodeDecodeError exception. Other code would assume that str
instances were encoded using UTF-8 and decode them if necessary.
While that solution may work for some applications, it seems
unsuitable as a general solution. For example, some applications
get string data from many different sources and assuming that all
str instances were encoded using UTF-8 could easily introduce
subtle bugs.


References

[1] http://www.python.org/sf/1159501
[2] http://mail.python.org/pipermail/python-dev/2004-September/048755.html
[3] http://blog.ianbicking.org/illusive-setdefaultencoding.html


Copyright

This document has been placed in the public domain.



Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
 
W

wolf

hi,

i guess that anyone reading this pep will agree that
*something* must be done to the state of unicode affairs
in python. there are zillions of modules out there that
have str() scattered all over the place, and they all
*break* on the first mention of düsseldorf...

i'm not quite sure myself how to evolve python to make
it grow from unicode-enabled to unicode-perfect, so for
me some discussion would be a good thing. only two
micro-remarks to the pep as it stands:

1) i dislike the naming of the function ``text()`` --
i´ve been using the word 'text' for a long time to mean
'some appropriate representation of character data',
i.e. mostly something that would pass ::

assert isinstance(x,basestring)

i feel this is a fairly common way of defining the term,
so to me a function `` text(x)`` should really

* return its argument unaltered if it passes
``isinstance(x,basestring)``,

* try to return spefically a unicode object (by using
the ``x.__unicode__()`` method, where available)

* or return an 8bit-string (from ``x.__repr__()`` or
``x.__str__()``)

as discussed later on in the pep, it is conceivable to
assign the functionality of the ``text()`` function of
the pep to ``basestring`` -- that would make perfect
sense to me (not sure whether that stands scrutiny in
the big picture, tho).


2) really minor: somewhere near the beginning it says ::

def text(obj): return '%s' % obj

and the claim is that this "behaves as desired" except
for unicode-issues, which is incorrect. the second line
must read ::

return '%s' % ( obj, )

or else it will fail if ``obj`` is a tuple that is not
of length one.


cheers,



_wolf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top