Python 3 was released in Dec 2008 – almost 10 years and we still found a lot of python 2.7 developers. Python 3 is Not backward compatible with Python 2. Most language features are the same, some detail has changed and many deprecated features have been tided up and removed
The main reason today to work with python 2.7 is to keep maintain a big project written in python 2. If you start a new project you definitely choose python 3.
It is not hard to port python 2 code to python 3 – you can do it manually or use the utility 2to3.py.
The Print Function
The first thing everyone notices about Python 3 is that the print statement is no longer a, um, statement: it is a built-in function. The effect is that we now have to put parentheses around the thing we wish to print.
Most commonly used for displaying a comma separated list (Objects are stringified)
ls=[1,2,3] print('hello',10,ls) # prints: # hello 10 [1, 2, 3]
Has several named arguments
- end= characters to be appended, default is ‘\n’ (newline)
- file= file object to be written to, default is sys.stdout
- sep= separator used between list items, default is a single space
ls=[1,2,3] print('hello',10,ls, sep=' $ ', end=':') print('bye') # prints: # hello $ 10 $ [1, 2, 3]:bye
Also format changed but you can use the old format (using %)
Simple keyboard (stdin) input
raw_input is replaced by input. The input statement reads from stdin, which is usually the keyboard but may have been redirected
num = input("enter number") print( "res", int(num) + 100) # enter number:33 # res: 133
Misc Changes
- The tests <> and cmp are no longer supported – both statements throws errors – use ==, !=
if x <> y: print("ok") if cmp(x,y): print("ok")
- Non Ascii Names are allowed – use magic comment for that
# coding=iso-8859-8 משתנה = 'hello' print(משתנה)
- Backticks are removed – use repr instead
d=10 r='2' print (d+r) #TypeError: unsupported operand type(s) for +: 'int' and 'str' print( `d` + r) # SyntaxError: invalid syntax (was ok in python 2) print( repr(d) + r) # 102
- New format for octal numbers:
num = 0o127
- Trailing L is no longer used – ints and long are the same
- True, False, None are now keywords (In Python 2 they could be redefined)
Strings in python 3
- Multi-byte characters
- \unnnn – two-byte Unicode character
- \Unnnnnnnn – four-byte Unicode character
- \N{name} – a named Unicode character
- The old Python 2 u”…” prefix is no longer supported
euro="\u20ac" print( euro) euro="\N{euro sign}" print (euro) # € # €
bytes() and bytearray()
used for low level interfacing, convert to string using decode:
cb = b"simple single-byte string" print(cb.decode())
Opening a file in binary mode returns a bytes object. Convert from a string using string.encode()
String formatting
Like printf in C, using the format method:
st = "hello {0:15d} hi {1:5.2f} bye {2}".format(10,3.2233,"have fun") print(st) # hello 10 hi 3.22 bye have fun
Collections
- The format when printing a set changed in python 3
s1 = set('hello') print (s1) # {'l', 'e', 'o', 'h'}
- Dictionary methods iterkeys(), itervalues(), iteritems() removed
- Return values from keys(), values(), and items() are view objects
- map and filter return iterators (instead of list in python 2)
in python 2:
>>> ls = [1,2,3,4] >>> ls2=map(lambda x:x*10,ls) >>> ls2 [10, 20, 30, 40]
in python 3:
>>> ls = [1,2,3,4] >>> ls2=map(lambda x:x*10,ls) >>> ls2 <map object at 0x104d21208> >>> next(ls2) 10
Forcing a user to supply named arguments
You can use * to force a user to supply named arguments:
def fn(*, a = 100,b = 200): return a+b*10 print(fn()) # 2100 print(fn(b=30,a= 10)) # 310 print(fn(10,20)) # TypeError fn() takes 0 positional arguments but 2 were given
Function Annotations
You can add documentation to the parameters and the return value:
def add(a:"first number" = 0, b:"second number" = 0) -> "sum of a and b": return a+b for item in add.__annotations__.items(): print(item) # ('a', 'first number') # ('b', 'second number') # ('return', 'sum of a and b')
variables in nested functions:
If we define a variables with the same name in a different scopes it may confuses the interpreter for example:
b = 3 def f1(): b = 10 def f2(): if b < 100: # error here b += 1 f2() print(b, "from f1") f1() print(b, "from main")
This code will fail with the error: UnboundLocalError: local variable ‘b’ referenced before assignment
To fix this you need to declare b as global or nonlocal
nonlocal
b = 3 def f1(): b = 10 def f2(): nonlocal b if b < 100: b += 1 f2() print(b, "from f2") # 11 from f2 f1() print(b, "from main") # 3 from main
global
b = 3 def f1(): b = 10 def f2(): global b if b < 100: b += 1 f2() print(b, "from f2") # 10 from f2 f1() print(b, "from main") # 4 from main
Exceptions
Each exception has an arguments attribute stored in a tuple. The number of elements, and their meaning varies
The raise and except syntax changed and we throw only Exception objects (in python 2 you can throw string)
class CustomException(Exception): pass def fn(*arguments): if not all(arguments): raise CustomException("False argument in fn") try: fn('dev','',42) except CustomException as err: print("Oops:",err)
Properties and decorators
The property() built-in function defines get, set, delete, and docstring methods for a specific attribute
class C(object): def __init__(self): self._x = None @property def x(self): print 'get' """I'm the 'x' property.""" return self._x @x.setter def x(self, value): print 'set' self._x = value @x.deleter def x(self): del self._x
some of the changes are also supported in python 2 and using the back port option you can make the porting process easier