Videos
There is official documentation suggesting ways to do this. That documentation has changed over time as the situation has changed, so it's worth going directly to the source (especially if you're reading this answer a year or two after it was written).
It's also worth reading the Conservative Python 3 Porting Guide and skimming Nick Coghlan's Python 3 Q&A, especially this section.
Going back in time from the early 2018:
futurize
The current official suggestions are:
- Only worry about supporting Python 2.7
- Make sure you have good test coverage (coverage.py can help;
pip install coverage) - Learn the differences between Python 2 & 3
- Use Futurize (or Modernize) to update your code (e.g.
pip install future) - Use Pylint to help make sure you don’t regress on your Python 3 support (
pip install pylint) - Use caniusepython3 to find out which of your dependencies are blocking your use of Python 3 (
pip install caniusepython3) - Once your dependencies are no longer blocking you, use continuous integration to make sure you stay compatible with Python 2 & 3 (tox can help test against multiple versions of Python;
pip install tox) - Consider using optional static type checking to make sure your type usage works in both Python 2 & 3 (e.g. use mypy to check your typing under both Python 2 & Python 3).
Notice the last suggestion. Guido and another of the core devs have both been heavily involved in leading large teams to port large 2.7 codebases to 3.x, and found mypy to be very helpful (especially in dealing with bytes-vs.-unicode issues). In fact, that's a large part of the reason gradual static typing is now an official part of the language.
You also almost certainly want to use all of the future statements available in 2.7. This is so obvious that they seem to have forgotten to leave it out of the docs, but, besides making your life easier (e.g., you can write print function calls), futurize and modernize (and six and sixer) require it.
six
The documentation is aimed at people making an irreversible transition to Python 3 in the near future. If you're planning to stick with dual-version code for a long time, you might be better off following the previous recommendations, which largely revolved around using six instead of futurize. Six covers more of the differences between the two languages, and also makes you write code that's explicit about being dual-version instead of being as close to Python 3 as possible while still running in 2.7. But the downside is that you're effectively doing two ports—one from 2.7 to six-based dual-version code, and then, later, from 3.x-only six code to 3.x-only "native" code.
2to3
The original recommended answer was to use 2to3, a tool that can automatically convert Python 2 code to Python 3 code, or guide you in doing so. If you want your code to work in both, you need to deliver Python 2 code, then run 2to3 at installation time to port it to Python 3. Which means you need to test your code both ways, and usually modify it so that it still works in 2.7 but also works in 3.x after 2to3, which isn't always easy to work out. This turns out to not be feasible for most non-trivial projects, so it's no longer recommended by the core devs—but it is still built in with Python 2.7 and 3.x, and getting updates.
There are also two variations on 2to3: sixer auto-ports your Python 2.7 code to dual-version code that uses six, and 3to2 lets you write your code for Python 3 and auto-port back to 2.7 at install time. Both of these were popular for a time, but don't seem to be used much anymore; modernize and futurize, respectively, are their main successors.
For your specific question,
kwargs.items()will work on both, if you don't mind a minor performance cost in 2.7.- 2to3 can automatically change that
iteritemstoitemsat install time on 3.x. - futurize can be used to do either of the above.
- six will allow you to write
six.iteritems(kwargs), which will doiteritemsin 2.7 anditemsin 3.x. - six will also allow you to write
six.viewitems(kwargs), which will doviewitemsin 2.7 (which is identical to whatitemsdoes in 3.x, rather than just similar). - modernize and sixer will automatically change that
kwargs.iteritems()tosix.iteritems(kwargs). - 3to2 will let you write
kwargs.items()and autmatically convert it toviewitemsat install time on 2.x. - mypy can verify that you're just using the result as a general iterable (rather than specifically as an iterator), so changing to
viewitemsoritemsleaves your code still correctly typed.
you can import the future package
from future import ....
nested_scopes 2.1.0b1 2.2 PEP 227: Statically Nested Scopes
generators 2.2.0a1 2.3 PEP 255: Simple Generators
division 2.2.0a2 3.0 PEP 238: Changing the Division Operator
absolute_import 2.5.0a1 3.0 PEP 328: Imports: Multi-Line and Absolute/Relative
with_statement 2.5.0a1 2.6 PEP 343: The “with” Statement
print_function 2.6.0a2 3.0 PEP 3105: Make print a function
unicode_literals 2.6.0a2 3.0 PEP 3112: Bytes literals in Python 3000