Python 3 vs Python 2 usually comes up when an inherited script, an old tutorial or a server with python2 on it refuses to cooperate, not when you’re picking a language for a new project.
So here’s my rule: use Python 3 for everything you write or run today. Only open Python 2 to read legacy code you’re about to convert, because it reached end of life on January 1, 2020, and the last release, 2.7.18, shipped in April 2020.
In this tutorial, I’ll walk through Python 3 vs Python 2 one difference at a time, with real runs on Python 3.12.5. There’s no Python 2 on my machine, so Python 2 behavior comes from the official docs, not fake output.
Python 3 vs Python 2 at a Glance
| Feature | Python 2 (2.7) | Python 3 |
|---|---|---|
| Status | End of life since 01/01/2020 | Supported, new release every October |
print | Statement: print "hi" | Function: print("hi") |
7 / 2 | 3 (integer division) | 3.5 (true division) |
round(2.5) | 3.0 (half away from zero, float) | 2 (half to even, int) |
| Text type | str = bytes, unicode = text | str = Unicode text, bytes separate |
range() | Returns a list; xrange() is lazy | Lazy range object; no xrange |
dict.keys(), map() | Return lists | Return views / iterators |
| User input | raw_input(); input() evaluates | input() always returns a string |
| Exceptions | except ValueError, err: | except ValueError as err: |
| f-strings, type hints | Not available | Yes (3.6+, 3.5+) |
Every Python 3 example below imports the same sample data from store.py,:
# Sample order data, Austin store, 11/05/2026 (USD)
items = 7
boxes = 2
customer = "José Ramírez"
totals = {"Emily Carter": 42.50, "José Ramírez": 18.99, "Ryan Mitchell": 125.00}
If you aren’t sure which version a machine runs, check your Python version first; on many Linux and macOS boxes python and python3 aren’t the same program.
Why does print “hello” fail in Python 3?
In Python 2, print was a statement, so it didn’t need parentheses. Python 3 made it a normal function. Run the old line on Python 3 and it stops before anything executes:
print "Order total: $42.50"
Output:
File "C:\pyguides\print_statement.py", line 1
print "Order total: $42.50"
^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

The fix is mechanical: print("Order total: $42.50"). As a function it also takes end, which is how you print on the same line in Python.
Integer Division: Why 7 / 2 Gives 3.5 in Python 3
This is the silent one. Same order file: 7 items packed into 2 boxes. In Python 2, 7 / 2 on two integers returned 3. Python 3 returns 3.5 and keeps floor division in //:
from store import items, boxes
print("items / boxes =", items / boxes)
print("items // boxes =", items // boxes)
print("-items // boxes =", -items // boxes)
print("round(2.5) =", round(2.5), "| round(3.5) =", round(3.5))
print("type(7 / 2):", type(items / boxes).__name__)
Output:
items / boxes = 3.5
items // boxes = 3
-items // boxes = -4
round(2.5) = 2 | round(3.5) = 4
type(7 / 2): float

// floors toward minus infinity, so -7 // 2 is -4 in both versions. My guide to normal division vs floor division in Python covers more cases.
Note: round() changed too. Python 2 rounded 2.5 to 3.0; Python 3 rounds halves to the nearest even number and returns an int. That matters for USD totals, so see rounding numbers to 2 decimal places in Python.
Strings vs Bytes: How Python 3 Handles Unicode
A Python 2 str was a string of bytes, and text needed the unicode type with a u"..." prefix. In Python 3, str is always Unicode text and raw bytes live in bytes.
Same store.py, now with the customer name José Ramírez:
from store import customer
data = customer.encode("utf-8")
print(type(customer).__name__, len(customer), customer)
print(type(data).__name__, len(data), data)
try:
print("Customer: " + data)
except TypeError as err:
print("TypeError:", err)
print("Decoded:", data.decode("utf-8"))
Output:
str 12 José Ramírez
bytes 14 b'Jos\xc3\xa9 Ram\xc3\xadrez'
TypeError: can only concatenate str (not "bytes") to str
Decoded: José Ramírez

Python 2 would have counted the name as 14 bytes in a UTF-8 source file, and mixing str with unicode could fail at run time with UnicodeDecodeError.
You’ll hit this with files, sockets and pickle, for example the bytes-like object is required, not str error.
Python 3 range vs Python 2 xrange, dict.keys() and map()
Python 2 built full lists for range(), dict.keys(), map(), filter() and zip(). Python 3 returns lazy objects instead. Here’s the same order data again:
from store import items, totals
print(range(items), type(range(items)).__name__)
print(totals.keys())
print(type(map(round, totals.values())).__name__)
print(list(map(round, totals.values())))
for old in ("xrange", "raw_input", "unicode"):
try:
eval(old)
except NameError as err:
print("NameError:", err)
Output:
range(0, 7) range
dict_keys(['Emily Carter', 'José Ramírez', 'Ryan Mitchell'])
map
[42, 19, 125]
NameError: name 'xrange' is not defined
NameError: name 'raw_input' is not defined
NameError: name 'unicode' is not defined

Wrap the result in list() when you need indexing. Python 3’s range is the old xrange, which I compare in range vs xrange in Python. Notice round(42.5) gave 42, not 43.
For input, Python 3’s input() is Python 2’s raw_input(). Python 2’s input() evaluated whatever was typed as code. Here’s how to ask for user input in Python now.
Python 2 vs Python 3 Exception Syntax
Python 2 accepted a comma before the exception variable. Python 3 only allows as, and the comma form is a syntax error:
try:
int("abc")
except ValueError, err:
print(err)
Output:
File "C:\pyguides\except_comma.py", line 3
except ValueError, err:
^^^^^^^^^^^^^^^
SyntaxError: multiple exception types must be parenthesized
Change it to except ValueError as err:; likewise raise ValueError("msg") replaces the old comma form.
Python 2 or Python 3: Which Should You Use in 2026?
- Writing anything new: Python 3, the newest release your libraries support.
- Maintaining a Python 2 script: convert it to Python 3; it gets no security fixes.
- Following an old tutorial: translate print, division and input as you go.
Need several versions side by side while you migrate? See how to install multiple Python versions.
How to Switch from Python 2 to Python 3
- Get tests running on Python 2.7 first, so you know what correct output looks like.
- Add a version guard (below) and run the code on Python 3 to list the failures.
- Fix print,
except,raise,xrange,raw_inputandunicode. - Check every
/between integers; use//where you meant whole numbers. - Encode and decode at file and network boundaries.
- Run the tests on Python 3, then drop
sixand__future__imports.
Important: the old 2to3 tool was removed in Python 3.13, so run it from Python 3.12 or older if you still want automatic rewrites.
This guard stops a script early on an old interpreter, and uses two Python 3-only features:
import sys
if sys.version_info < (3, 10):
sys.exit("This script needs Python 3.10 or newer.")
total: float = 42.50 + 18.99 + 125.00
print(f"Python {sys.version_info.major}.{sys.version_info.minor}"
f" | 3 orders = ${total:,.2f}")
Output:
Python 3.12 | 3 orders = $186.49
Print, division, text vs bytes and lazy iterators decide it. Fix those four and most Python 2 code runs on Python 3.
Here’s what I’d read after this one:
- What the Python interpreter does
- Python virtual environments explained
- The Python string encode() function
- How map() works in Python
Frequently asked questions
Is Python 2 still supported?
No. Python 2 reached end of life on January 1, 2020, and 2.7.18 in April 2020 was its last release.
Can Python 3 run Python 2 code?
Not directly. Print statements, comma-style except clauses and removed names such as xrange fail on Python 3.
Why does 5 / 2 give 2 in Python 2?
Python 2 used integer division for two ints. Python 3 returns 2.5; use // for a floor result.
What replaced raw_input() in Python 3?
input(). It always returns a string, like raw_input() did.
Should a beginner learn Python 2 first?
No. Learn Python 3; you’ll only need Python 2 knowledge to read or convert legacy code.
Where is the full list of Python 3 changes?
See What’s New In Python 3.0 in the official Python docs.
