QCString — simple strings in PyQt
Both Python and Qt have two types of
strings: simple strings, which are sequences of bytes where
every byte represents one character, and complex string objects,
which contain characters in the Unicode encoding. Unicode is a
complex topic that is treated in the next section; this section
deals with simple strings.
QCString is the PyQt
equivalent of the Python simple string. The Qt documentation
describes QCString as a weak class, which
is accurate. The implementation does not feature all the
intelligence and care that has gone into
QString, and as a consequence it scales
poorly to large strings.
As an abstraction of the standard C++
null-terminated string, QCString cannot
contain any null bytes ('\0'). In this respect,
QCString differs from the simple Python
string object. The simple Python string is often used as a
container for binary data, and the string object doesn't care
whether it contains null bytes. Feeding a Python string that
contains null bytes to a QCString provides interesting results:
Example 8-3. empty.py - feeding zero bytes to a QCString
#
# empty.py - feeding zero bytes to a QCString
#
from qt import *
pystring='abc\0def'
print "Python string:", pystring
print "Length:", len(pystring)
qcstring=QCString(pystring)
print "QCString:", qcstring
print "Length:", qcstring.length()
Running the previous example produces the following
output:
boudewijn@maldar:~/doc/opendoc/ch4 > python empty.py
Python string: abcdef
Length: 7
QCString: abc
Length: 3
Except for this proviso, both
QCString and the Python string object are
equivalent, and you can use the Python string object wherever a
QCString is needed as a parameter in a
function. You can convert the QCString
back to a python string with the str()
function. If the QCString is
empty, i.e., it contains only one byte with
the value zero ('\0'), an empty Python
string is returned, not a Python string
that contains one zero byte.
The issue of null versus empty strings is an
interesting one. A null QCString is
constructed as follows:
nullstring=QCString()
This string is conceptually equivalent to
the Python None object, except that the
null QCString has a type. There is no way
to construct a null Python string: a Python
string without contents is always empty,
i.e. the equivalent of a QCString that
contains one byte with the value zero. The
following script attempts a few combinations, using Python's
built-in assert function.
Assert: The assert statement
is one of the more useful tools in the Python developers
toolchest. You can use assert to check
any statement for truth — and if it fails, an
AssertionException is thrown. If you compile your Python
scripts to optimized bytecode (.pyo files), then the assertion
statements are removed, making assert
ideal for checking your code for invalid entry conditions in
method calls during development. The use of
assert in the following script is more of
a hack: this little script wouldn't do anything if run with
python -O null.py; only the line print message, "TRUE" would
be executed in the assertTrue
function.
Example 8-4. null.py - empty and null QCStrings and Python
strings
#
# null.py - empty and null QCStrings and Python strings
#
from qt import QCString
# this string is empty
emptypystring=""
# this string contains one byte, zero
nullpystring="\0"
# this string is empty: it contains the empty string, terminated with \0
emptyqcstring=QCString("")
# this string is null: it doesn't contain data
nullqcstring=QCString()
def assertTrue(assertion, message):
try:
assert(assertion)
print message, "TRUE"
except AssertionError:
print message, "FALSE"
assertTrue(emptypystring==emptyqcstring,
"Empty Python string equals empty QCString")
assertTrue(emptypystring==str(emptyqcstring),
"Empty Python string equals str(empty QCString)")
assertTrue(emptypystring==str(nullqcstring),
"Empty python string equals str(null QCString)")
assertTrue(nullpystring==emptyqcstring,
"Python string containing 0 byte equals empty QCString")
assertTrue(nullpystring==str(emptyqcstring),
"Python string containing 0 byte equals str(empty QCSTRING)")
assertTrue(nullqcstring is None,
"Null QCString equals None object")
Running this gives the following output:
boudewijn@maldar:~/doc/opendoc/ch4 > python null.py
Empty Python string equals empty QCString FALSE
Empty Python string equals str(empty QCString) TRUE
Empty python string equals str(null QCString) TRUE
Python string containing 0 byte equals empty QCString FALSE
Python string containing 0 byte equals str(empty QCSTRING) FALSE
Null QCString equals None object FALSE
Of course, some of these concerns hold for
QString, too. It is equally possible to
have an empty QString or a null
QString. Note that embedding a zero byte
in a Python string and then feeding it to a
QString shows the same behavior as with
QCString, even though
QString isn't a null-terminated string
class:
Example 8-5. emptyqstring.py - feeding zero bytes to a
QString
#
# emptyqstring.py - feeding zero bytes to a QString
#
from qt import *
pystring='abc\0def'
print "Python string:", pystring
print "Length:", len(pystring)
qstring=QString(pystring)
print "QString:", qstring
print "Length:", qstring.length()
Look at the output:
boudewijn@maldar:~/doc/opendoc/ch4 > python emptyqstring.py
Python string: abcdef
Length: 7
QString: abc
Length: 3
The unavoidable conclusion is that you
shouldn't try to use Python strings as containers for binary
data and then convert them to Qt string objects. Of course,
there's a solution: you can use
QByteArray to store binary data.