談談python2與python3

1. __future__:

python每次更新時,引入了一些新的模塊或功能,那麼版本之間會可能會出現版本不兼容問題。

__future__ 模塊就是爲了解決這個問題,它把新功能添加到了這個模塊中,可以使用這個模塊,進行新功能的測試與使用。

例:

python2在沒有導入包的情況下:

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

print('2019','12','6',sep='-',end='')

"""
運行結果:
  File "D:/python/ƽʱ����/test_future.py", line 17
    print('2019','12','6',sep='-',end='')
                             ^
SyntaxError: invalid syntax
"""

那麼把導入包__future__取消註釋:

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

print('2019','12','6',sep='-',end='')

"""
運行結果:

當前版本Python 2.7.14
2019-12-6
"""

python3下運行:

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

print('2019','12','6',sep='-',end='')

"""
運行結果:

當前版本Python 3.6.1
2019-12-6
"""

 

除了print_function外,還有其它功能如 division、absolute_import、with_statement等python3新功能,具體可以看官方文檔:https://docs.python.org/2.7/library/__future__.html

 

2. 2to3

2to3是與當前Python版本發行的命令工具,該工具用於將Python2代碼轉換成Python3代碼。

文件目錄在:C:\mysoftware\Python\Python36\Tools\scripts  目錄以自己安裝而定

使用方式:

2to3 文件.py:用來說明文件中代碼更變的說明信息。

2to3 -w 文件.py:將python2代碼改爲python3代碼。

案例:

用python2寫一個打印hello world! ,文件名爲 py2to3_test.py

用python3執行並說明如下:

使用2to3 -w py2to3_test.py時,代碼會發生改變:代碼由python2變成了python3!!!

官方建議:只有在編寫Python2代碼並將其轉換爲Python3代碼部署時才使用2to3。

其實想想,在實際,大多數項目中是不可以行的,畢竟項目中代碼量大,使用2to3可能會增加負擔。

 

3. six

是Python2與Python3之間兼容性庫,提供了一些實用函數,消除Python版本之間的差異,而且在Python2與Python3兩個版本中都能執行。

相比2to3,它只需要維護一份代碼,同樣的代碼可以在兩個版本中運行。

six從根本上完成的工作是爲Python2與Python3之間變更的元素提供唯一接口。

案例:

在Python2中 str 表示字節型字符串,unicode 表示文本型字符串。而在Python中,bytes表示字節型字符串,str 表示文本型字符串。

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

print(type('hccfm'))
print(type(u'hccfm'))
print(type(b'hccfm'))
print(type(six.text_type('hccfm')))


"""
當前版本Python 2.7.14
<type 'str'>    # 字節型
<type 'unicode'>    #文本型
<type 'str'>    # 字節型
<type 'unicode'>    #文本型
"""

"""
當前版本Python 3.6.1
<class 'str'>   #文本型
<class 'str'>   #文本型
<class 'bytes'> # 字節型
<class 'str'>   #文本型
"""

通過上面例子可以看出,通過six.text_type() 不管在那個版本中,都是定義爲文本型字符串,與之相反的爲six.binary_type。

除了text_type外,還有其它好用的功能。具體去官網或看源碼。直接拿來用就行了!!!

 

4. Python2與Python3的變更

4.1 字符串與unicode

同3案例說到,在Python2中 str 表示字節型字符串,unicode 表示文本型字符串。而在Python中,bytes表示字節型字符串,str 表示文本型字符串。

Python2:

在代碼中,直接沒任何聲明的是字節型字符串,而文本型則需要在字符串前加上u

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


s = 'hccfm'
s1 = u'hccfm'

print(type(s))
print(type(s1))

"""
當前版本Python 2.7.14
<type 'str'>
<type 'unicode'>
"""

Python3:

在代碼中,直接沒任何聲明的是文本型字符串,而字節型則需要在字符串前加上b

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


s = 'hccfm'
s1 = b'hccfm'

print(type(s))
print(type(s1))

"""
當前版本Python 3.6.1
<class 'str'>
<class 'bytes'>
"""

4.2 除法

在python2中,除法(/),在作用於兩個整型數時,它是一個取整除法,會導致數據在混淆。如5/2=2 ,而不是5/2=2.5,它了避免這一點,在python2中,要想得到正確的結果,則使除數或者被除數爲float類型。如5.0/2=2.5

在python3中,則解決這個問題,新添加了取整除法(//)功能。

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


print(4/2)
print(5/2)
print(5.0/2)

"""
當前版本Python 2.7.14
2
2
2.5
"""

4.3 模塊的導入

在python2中,在導入模塊時,是先相對導入再絕對導入。也就是說,當代碼出現模塊導入時,它會先在同一個目錄中尋找,如果找到,則完成。如果沒有找到,則從sys.path中所有的目錄中查找一個匹配的模塊,正常情況下,會包含所有已經安裝的Python包。

該行爲可能導致問題,例如,僅僅是在一個目錄中添加重複命名的模塊會導致該目錄中的其他模塊失效,因爲突然開始執行相對導入而不是絕對導入。

在python3中,所有導入都是絕對導入,如果想要相對導入,則使用特殊的語法,使用英文句號(.)作爲開頭,如 import .foo

一個英文句號(.)表示同一級目錄下,兩個英文句號(..)表示上級目錄。

由於兩個版本不一,爲了解決這個問題可以使用 __future__模塊下在absolute_import

from __future__ import absolute_import

4.4 “老式風格” 類的移除

看例子說明:

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform



import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


class foo:
    pass

class foo1(object):
    pass

print(type(foo))
print(type(foo1))


"""
當前版本Python 2.7.14
<type 'classobj'>
<type 'type'>
"""

"""
當前版本Python 3.6.1
<class 'type'>
<class 'type'>
"""

Python2中,在創建一個類時,沒有顯示的說明繼承,則會使用老式風格的類。

Python3中,則移除了老式風格類的繼承。

如果想在python2與python3中都能執行,那個顯示的繼承object這個類就行。

 

4.5 元類

python2中,創建一個元類,則給屬性 __metaclass__ 賦值無類即可。

class foo:
    __metaclass__ = 元類

python3中,創建一個無類,則需要在類中進行聲明。

class foo1(object,metaclass=元類):
    pass

 

4.6 異常語法

  • 異常處理:
# python2
try:
    raise ValueError('...')
except ValueError , e:
    print(e)

# python3
try:
    raise ValueError('...')
except ValueError as e:
    print(e)

python3把python2中的英文逗號(,) 改爲as 

 

  • 異常鏈:

在python代碼中,在解釋器處理一個異常時(在except子句中),引發了另一個異常。python2中,所有關於原始異常的信息會丟失,不這利於異常的處理。而在python3中,當觸發第二次異常時,將會把原始異常賦給__context__屬性。此外,python3還可以顯示的指定別一個異常,通過語法: raise  from 指定。

案例1:python2運行原始異常丟失!!!

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


try:
    3/0
except ZeroDivisionError as e:
    raise ValueError('此處觸發一個ValueError')


"""
當前版本Python 2.7.14
Traceback (most recent call last):
  File "D:/python/ƽʱ����/test_future.py", line 24, in <module>
    raise ValueError('此處觸發一個ValueError')
ValueError: 此處觸發一個ValueError
"""

案例2:python3運行原始異常保留。

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


try:
    3/0
except ZeroDivisionError as e:
    raise ValueError('此處觸發一個ValueError')


"""
當前版本Python 3.6.1
Traceback (most recent call last):
  File "D:/python/平時代碼/test_future.py", line 19, in <module>
    3/0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:/python/平時代碼/test_future.py", line 21, in <module>
    raise ValueError('此處觸發一個ValueError')
ValueError: 此處觸發一個ValueError
"""

案例3:python3顯示指定異常

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


try:
    3/0
except ZeroDivisionError as e:
    raise ValueError('此處觸發一個ValueError') from e


"""
當前版本Python 3.6.1
Traceback (most recent call last):
  File "D:/python/平時代碼/test_future.py", line 19, in <module>
    3/0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "D:/python/平時代碼/test_future.py", line 21, in <module>
    raise ValueError('此處觸發一個ValueError') from e
ValueError: 此處觸發一個ValueError
"""

案例4:python3中,禁止異常關聯,使用None

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))


try:
    3/0
except ZeroDivisionError as e:
    raise ValueError('此處觸發一個ValueError') from None


"""
當前版本Python 3.6.1
Traceback (most recent call last):
  File "D:/python/平時代碼/test_future.py", line 21, in <module>
    raise ValueError('此處觸發一個ValueError') from None
ValueError: 此處觸發一個ValueError
"""

 

6.7 其它說明

從python2到python3,代碼和性能都得到的優化,有的簡化了代碼,如:字典方法、函數方法。有的簡化了性能,如迭代器,range函數等。

案例1:函數方法

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

def foo(a=3):
    pass

print(dir(foo))

"""
當前版本Python 2.7.14
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
"""

"""
當前版本Python 3.6.1
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
"""

案例2:字典方法

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

d = {'foo':123}

print(dir(d))

"""
當前版本Python 2.7.14
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']
"""

"""
當前版本Python 3.6.1
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
"""

案例3:range函數,在python2中,有range與xrange函數,range產生就是一個list對象,xrange則是生成器對象,在python3中,只有range函數,xrange函數已經取消,同樣它也是一個生成器對象。

# -*- coding: utf-8 -*-

# @Time    : 2019/12/6 0:36
# @Author  : hccfm
# @File    : test_future.py
# @Software: PyCharm

from __future__ import print_function
import platform

import six
if six.PY2:
    print('當前版本Python',format(platform.python_version()))
else:
    print("當前版本Python",format(platform.python_version()))

# ran1 = xrange(10)
ran2 = range(10)

# print(type(ran1))
print(type(ran2))

"""
當前版本Python 2.7.14
<type 'xrange'>
<type 'list'>
"""

"""
當前版本Python 3.6.1
<class 'range'>
"""

 

5. 常見函數與版本對應的函數

Python3 Python2 six.moves
Configparser ConfigParser Configparser
filter Itertools.ifilter filter
input raw_input input
range xrange range
functools.reduce reduce reduce
socketserver SocketServer socketserver
map itertools.imap map
zip itertools.izip zip

 

此文章,來源《Python高級編程》,網絡博客,官方文檔及個人見解而成,如有錯誤,謝謝留言,不勝感激!!!。

 

END!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章