python __future__ package的幾個特性


我學習python過程, 和學習其它編程知識一樣, 不是先讀大部頭書系統學習, 而是看博客和直接實踐, 慢慢將這些知識點連成線, 再擴展到面. 這個過程缺點和優點都很明顯. 缺點是, 有些知識點可能因為一直沒有機會碰到, 就一直是盲點, 另外從點到面過程較長. 好在我自學能力很強, 基本碰到的問題都能搞得定.

近期研究github開源項目有幾個發現, 代碼多帶有:

1. from __future__ import absolute_import
2. from __future__ import unicode_literals
3. 在根package的 __init__.py, 加上版本號和作者等信息,
__version__ = '0.0.2'  
__author__ = 'somebody'
4. 如果源碼保存為utf-8格式, 文件頭加上如下注釋,   
# -*- coding: utf-8 -*- 


==============================
__future__的absolute_import
==============================
from __future__ import absolute_import, 字面理解好像是僅僅允許絕對引用, 其實不然, 真實意思是禁用 implicit relative import, 但並不會禁掉 explicit relative import.

舉個例子, 目錄結構如下,

src
    -my_app
        -__init__.py 
        -cake      
            |- __init__.py      
            |- icing.py      
            |- sponge.py   
        -drink      
            |- __init__.py      
            |- water.py      
 

要在 sponge.py 引用 icing , 有多種方法:
1. import icing # implicit relative import, py2已強烈不推薦使用, py3已經不可用了.
2. from . import icing # explicit relative import, python.org 官方不推薦.
3. from cake import icing # absolute import, python 官方推薦.

 

總結一下, 最好的做法應該是:
(1) 將 src 目錄加到 PYTHONPATH 中
(2) 在 src 目錄下家里一個 root package, 比如名稱就叫 my_app
(3) import 時候都用 my_app.subpackage 或 my_app.module 這樣絕對路徑的寫法,
比如 import my_app.module 或 from my_app import module




--------------------------
使用absolute_import, 常碰到的一個問題
--------------------------
使用__future__ absolute_import 之后, 常遇到的如下這一問題, 示例:   
-PackageA
 |- module1.py  
 |- module2.py  
 |- __init__.py  

module1.py 的代碼示例:

from __future__ import absolute_impact  
from . import module2 #引入同包下的另一個module  
if __name__=="__main__":      
    print("module2 was imported in module1.")  

運行 module1.py 會報錯, 報錯信息: ValueError: Attempted relative import in non-package.
原因分析: from . import module2 這樣的寫法是顯式相對引用, 這種引用方式只能用於 package 中, 而不能用於主模塊中. 因為[主module]的name總是為 __main__, 並沒有層次結構, 也就無從談起相對引用了.
換句話, if __name__=="__main__": 和相對引用是不能並存的.

解決方法:
方法1: 在 module1 中使用絕對引用, 這個最簡單了, 但相對引用的好處也沒了.
方法2: 使用 python -m 來啟動你的 module1.py, 這個也不推薦.
方法3(推薦): 在 module1 中, 加個main()函數, 然后再新建一個 PackageA/entry.py 做為主程序, 在 entry.py 中使用絕對引用來導入 module1 , 並調用 module1.main(), 這一辦法雖不完美, 但我覺得是最好的方法了.


==============================
unicode_literals
==============================
from __future__ import unicode_literals 在python 2.x中, 對於字符串, 默認還不是采用 unicode 編碼的, 除非在字符串前加上前綴u. 比如:

>>>x='中國'  
>>>x  
'\xd6\xd0\xb9\xfa'  
>>>print(x)  
中國  
>>>
>>>x=u'中國'  
>>>x  
u'\u4e2d\u56fd'  
>>>print(x)  
中國  

在python3中默認的編碼采用了unicode, 並取消了前綴u. 如果代碼要兼容python2/3, 就很麻煩了.

通常有如下3種做法, 其中前兩個做法都不推薦:
1. 不管是漢字還是英文, 字符串前面統一不加u. 這種處理方式多數情況下沒有問題, 比如print輸出, 但字符串如果需要做encode/decode, 就很麻煩.
2. 加python版本判斷, 如果 sys.version >3 的話, 字符串不加前綴u, 如果是py2, 加上前綴u. 可以想象, 業務邏輯中再加上這樣的判斷, 代碼會變得很難看.
3. 現在有第3種, 即引入unicode_literals, from __future__ import unicode_literals, 這樣在py2下, '中國'這樣的字符串不用家前綴u, 也是unicode編碼.


==============================
引申閱讀
==============================
http://blog.ludovf.net/python-str-unicode/
http://blogs.skicelab.com/maurizio/unicode-common-pitfalls.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM