Tabla de contenido
- 1 Understanding the Differences between Python 2 and Python 3
- 2 Using Python 3 Specific Libraries
- 3 Change in Exception Syntax
- 4 The map() Function
- 5 Dealing with Division in Python
- 6 The Importance of __future__
- 7 List Comprehensions and Variable Scope
- 8 Dictionary Keys are Views in Python 3
- 9 Goodbye to xrange()
- 10 Escape Codes in Strings
- 11 The input() Function
- 12 The round() Function
- 13 Changes in Comparison Operators
- 14 Using next()
- 15 Default Encoding
- 16 __eq__() or __cmp__()?
- 17 Changes in Class Variables
- 18 Adding *args and **kwargs in Class Methods
- 19 Iterators in Python 3
Hello! Are you interested in transitioning your Python 2.7 code to Python 3.7 or higher? Well, you’ve come to the right place. Throughout this article, I’m going to show you different tricks that will make this seemingly daunting task easier for you. Don’t worry, we’ll go step-by-step. And most importantly, you’ll learn to do it in a simple and efficient way. Let’s dive in!
Understanding the Differences between Python 2 and Python 3
Before we get fully into the tricks to transition from Python 2 to Python 3, it’s essential that you understand the key differences between these two versions. Python 3 introduces changes in the language that are not backward compatible. This is the main reason why the migration process can be tricky.
For example, in Python 2, the print command is used without parentheses, while in Python 3, parentheses are required. In Python 2.7 you could use:
print "Hello, world!"
In Python 3.7 or higher, you should write it like this:
print("Hello, world!")
Using Python 3 Specific Libraries
Python 3 brings with it a series of new libraries that are not available in Python 2.7. Therefore, you will need to change your imports to match the Python 3 libraries. For instance, if you used urlib2 before, now you will have to import urllib.request, urllib.parse, and urllib.error.
Here’s an example of how your code should look:
# Python 2.7 import urllib2 response = urllib2.urlopen('http://python.org/') html = response.read() # Python 3.7 import urllib.request response = urllib.request.urlopen('http://python.org/') html = response.read()
Change in Exception Syntax
One of the most noticeable changes between Python 2 and Python 3 is how exceptions are handled. In Python 2, the syntax except Exception, e: was used. But in Python 3, you should change it to except Exception as e:. Here’s an example of how to do it:
# Python 2.7 try: ... except Exception, e: print e # Python 3.7 try: ... except Exception as e: print(e)
The map() Function
The map() function in Python 2 returns a list, while in Python 3 it returns an iterable object. So, if you want to get a list as a result, you must explicitly convert the result to a list using the list() function. Here’s an example:
# Python 2.7 result = map(func, values) # Python 3.7 result = list(map(func, values))
Dealing with Division in Python
In Python 2, the division of two integers results in another integer. In Python 3, however, the result is a floating-point number. If you want to keep the Python 2 behavior, you can use the // operator for integer division. Check out this example:
# Python 2.7 result = 7 / 2 # This results in 3 # Python 3.7 result = 7 / 2 # This results in 3.5 result = 7 // 2 # This results in 3
The Importance of __future__
The futurelibrary can be your best friend during migration. It allows you to use Python 3 features in your Python 2.7 code, making your migration task a whole lot easier. For example, you can use the Python 3print()` function in your Python 2.7 code like this:
from __future__ import print_function print("Hello, world!")
List Comprehensions and Variable Scope
Another important change in Python 3 is how it handles variable scope in list comprehensions. In Python 2, the variables used in list comprehensions leak into the main scope. Python 3 fixed this issue by encapsulating the variable scope within the list comprehension. Here’s an example:
# Python 2.7 x = 1 print [x for x in range(5)] print x # This prints 4, not 1 # Python 3.7 x = 1 print([x for x in range(5)]) print(x) # This prints 1
Dictionary Keys are Views in Python 3
In Python 3, dictionary.keys(), dictionary.values(), and dictionary.items() return view objects rather than lists. If you need to get a list, you need to convert the result to a list explicitly. Check out the following example:
# Python 2.7 dictionary = {'one': 1, 'two': 2} keys = dictionary.keys() # This is a list # Python 3.7 dictionary = {'one': 1, 'two': 2} keys = list(dictionary.keys()) # Now this is a list
Goodbye to xrange()
In Python 3, the xrange() function has been replaced by range(), which now returns an iterable object. In Python 2.7, if you want to get a list from range(), you need to convert it explicitly to a list:
# Python 2.7 x = xrange(10) # This is an iterable # Python 3.7 x = list(range(10)) # This is a list
Escape Codes in Strings
Python 2 allows the use of escape codes in non-formatted strings, while Python 3 does not allow it. If you want to use escape codes in Python 3, you need to use formatted strings. Here’s how to do it:
# Python 2.7 x = '\100' # Python 3.7 x = r'\100'
The input() Function
In Python 2, input() evaluates the user input, which can be a security issue. In Python 3, input() just reads the user input as a string. If you are migrating from Python 2 to Python 3, you should be careful with this change. Here’s an example of how to use input() in Python 3:
# Python 2.7 x = input("Enter a number: ") # This evaluates the user input # Python 3.7 x = input("Enter a number: ") # This takes the user input as a string
The round() Function
Another difference between Python 2 and Python 3 is how they handle the round() function. In Python 2, round(0.5) rounds to the nearest even number. In Python 3, it rounds to the nearest integer. Here’s an example:
# Python 2.7 print(round(0.5)) # This prints 0 # Python 3.7 print(round(0.5)) # This prints 1
Changes in Comparison Operators
In Python 2, you could compare unorderable objects. Python 3 will throw an exception in these cases. Therefore, you should review your code to ensure you are not trying to compare unorderable objects. For example:
# Python 2.7 print(1 < '1') # This is True # Python 3.7 print(1 < '1') # This throws a TypeError exception
Using next()
The next() function is used to get the next item from an iterator. In Python 2, you could use the iterator.next() method. In Python 3, you should use the next(iterator) function. Here’s an example:
# Python 2.7 iterator = iter([1, 2, 3]) print iterator.next() # This prints 1 # Python 3.7 iterator = iter([1, 2, 3]) print(next(iterator)) # This prints 1
Default Encoding
Python 2 uses ASCII as the default encoding, while Python 3 uses UTF-8. This can cause problems if your Python 2 code handles strings that are not ASCII. Here’s how you can handle this in Python 3:
# Python 2.7 string = '¡Hola, mundo!' # Python 3.7 string = '¡Hola, mundo!'
__eq__() or __cmp__()?
In Python 2, you could implement the __cmp__() method in your classes to perform comparisons between objects. Python 3 eliminates this method and instead, you should implement the __eq__() and __lt__() methods for equality and comparison respectively. Here’s an example:
# Python 2.7 class Test(object): def __cmp__(self, other): return self.value - other.value # Python 3.7 class Test(object): def __eq__(self, other): return self.value == other.value def __lt__(self, other): return self.value < other.value
Changes in Class Variables
In Python 2, class variables are accessible through the class instance. In Python 3, you can’t change class variables through the instance. Therefore, when migrating your Python 2 code to Python 3, you should keep this in mind. Here’s an example:
# Python 2.7 class Test(object): value = "Hello, world!" def change_value(self, new_value): self.value = new_value test = Test() test.change_value("Goodbye, world!") print(test.value) # Prints: Goodbye, world! # Python 3.7 class Test(object): value = "Hello, world!" def change_value(self, new_value): self.value = new_value test = Test() test.change_value("Goodbye, world!") print(test.value) # Prints: Hello, world! print(Test.value) # Prints: Goodbye, world!
Adding *args and **kwargs in Class Methods
Python 2 allows class methods to accept an arbitrary number of positional and keyword arguments, even if they are not defined in the method. Python 3 does not allow this, so you should make sure to include *args and **kwargs in the method definition if you want it to accept an arbitrary number of arguments. Here’s an example:
# Python 2.7 class Test(object): def method(self, x): print(x) test = Test() test.method(1, 2, 3) # This is valid # Python 3.7 class Test(object): def method(self, x, *args, **kwargs): print(x, args, kwargs) test = Test() test.method(1, 2, 3) # This is valid
Iterators in Python 3
In Python 2, the methods dict.iterkeys(), dict.itervalues(), and dict.iteritems() return iterators. Python 3 replaces them with dict.keys(), dict.values(), and dict.items(), which return dictionary views. But don’t worry, because these are also iterable and you can convert them to lists if needed.
# Python 2.7 dictionary = {'one': 1, 'two': 2} for key in dictionary.iterkeys(): print(key) # Python 3.7 dictionary = {'one': 1, 'two': 2} for key in dictionary.keys(): print(key)
With all these tricks, I’m sure your migration from Python 2.7 to Python 3.7 will be smoother. Don’t forget that migrating your code to Python 3 is not only important because of the improvements it offers, but also because Python 2 is no longer officially maintained. Good luck on your journey towards Python 3!