143 lines
4.1 KiB
Plaintext
143 lines
4.1 KiB
Plaintext
======================
|
||
Python 3 compatibility
|
||
======================
|
||
|
||
Django 1.5 is the first version of Django to support Python 3. The same code
|
||
runs both on Python 2 (≥ 2.6.5) and Python 3 (≥ 3.2), thanks to the six_
|
||
compatibility layer and ``unicode_literals``.
|
||
|
||
.. _six: http://packages.python.org/six/
|
||
|
||
This document is not meant as a Python 2 to Python 3 migration guide. There
|
||
are many existing resources, including `Python's official porting guide`_.
|
||
Rather, it describes guidelines that apply to Django's code and are
|
||
recommended for pluggable apps that run with both Python 2 and 3.
|
||
|
||
.. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html
|
||
|
||
Syntax requirements
|
||
===================
|
||
|
||
Unicode
|
||
-------
|
||
|
||
In Python 3, all strings are considered Unicode by default. The ``unicode``
|
||
type from Python 2 is called ``str`` in Python 3, and ``str`` becomes
|
||
``bytes``.
|
||
|
||
You mustn't use the ``u`` prefix before a unicode string literal because it's
|
||
a syntax error in Python 3.2. You must prefix byte strings with ``b``.
|
||
|
||
In order to enable the same behavior in Python 2, every module must import
|
||
``unicode_literals`` from ``__future__``::
|
||
|
||
from __future__ import unicode_literals
|
||
|
||
my_string = "This is an unicode literal"
|
||
my_bytestring = b"This is a bytestring"
|
||
|
||
If you need a byte string under Python 2 and a unicode string under Python 3,
|
||
use the :func:`str` builtin::
|
||
|
||
str('my string')
|
||
|
||
Be cautious if you have to `slice bytestrings`_.
|
||
|
||
.. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals
|
||
|
||
Exceptions
|
||
----------
|
||
|
||
When you capture exceptions, use the ``as`` keyword::
|
||
|
||
try:
|
||
...
|
||
except MyException as exc:
|
||
...
|
||
|
||
This older syntax was removed in Python 3::
|
||
|
||
try:
|
||
...
|
||
except MyException, exc:
|
||
...
|
||
|
||
The syntax to reraise an exception with a different traceback also changed.
|
||
Use :func:`six.reraise`.
|
||
|
||
|
||
.. module: django.utils.six
|
||
|
||
Writing compatible code with six
|
||
================================
|
||
|
||
six_ is the canonical compatibility library for supporting Python 2 and 3 in
|
||
a single codebase. Read its documentation!
|
||
|
||
:mod:`six` is bundled with Django: you can import it as :mod:`django.utils.six`.
|
||
|
||
Here are the most common changes required to write compatible code.
|
||
|
||
String types
|
||
------------
|
||
|
||
The ``basestring`` and ``unicode`` types were removed in Python 3, and the
|
||
meaning of ``str`` changed. To test these types, use the following idioms::
|
||
|
||
isinstance(myvalue, six.string_types) # replacement for basestring
|
||
isinstance(myvalue, six.text_type) # replacement for unicode
|
||
isinstance(myvalue, bytes) # replacement for str
|
||
|
||
Python ≥ 2.6 provides ``bytes`` as an alias for ``str``, so you don't need
|
||
:attr:`six.binary_type`.
|
||
|
||
``long``
|
||
--------
|
||
|
||
The ``long`` type no longer exists in Python 3. ``1L`` is a syntax error. Use
|
||
:data:`six.integer_types` check if a value is an integer or a long::
|
||
|
||
isinstance(myvalue, six.integer_types) # replacement for (int, long)
|
||
|
||
``xrange``
|
||
----------
|
||
|
||
Import :func:`six.moves.xrange` wherever you use ``xrange``.
|
||
|
||
Moved modules
|
||
-------------
|
||
|
||
Some modules were renamed in Python 3. The :mod:`django.utils.six.moves
|
||
<six.moves>` module provides a compatible location to import them.
|
||
|
||
In addition to six' defaults, Django's version provides ``dummy_thread`` as
|
||
``_dummy_thread``.
|
||
|
||
PY3
|
||
---
|
||
|
||
If you need different code in Python 2 and Python 3, check :data:`six.PY3`::
|
||
|
||
if six.PY3:
|
||
# do stuff Python 3-wise
|
||
else:
|
||
# do stuff Python 2-wise
|
||
|
||
This is a last resort solution when :mod:`six` doesn't provide an appropriate
|
||
function.
|
||
|
||
.. module:: django.utils.six
|
||
|
||
Customizations of six
|
||
=====================
|
||
|
||
The version of six bundled with Django includes a few additional tools:
|
||
|
||
.. function:: iterlists(MultiValueDict)
|
||
|
||
Returns an iterator over the lists of values of a
|
||
:class:`~django.utils.datastructures.MultiValueDict`. This replaces
|
||
:meth:`~django.utils.datastructures.MultiValueDict.iterlists()` on Python
|
||
2 and :meth:`~django.utils.datastructures.MultiValueDict.lists()` on
|
||
Python 3.
|