近期工作中應用Python的一些經驗總結


本文由Markdown語法編輯器編輯完成。

1. Python

在來新公司前,也間斷地接觸過Python編程,比如醫學影像處理的圖像庫VTK就已經有Python的實現;Paraview也可以開啟Python的監測,將用戶在界面上的操作錄制成Python腳本,供之后再進行重復調用。在人工智能領域,Python更是應用廣泛,各種深度學習的框架,都是用Python語言撰寫。

進入了新公司后,除了前端是用JS實現外,其余模塊的后端語言都是用Python實現。因此,我在近一個月的工作中,也是在邊學邊用Python。雖然說編程語言的思想都基本相同,但有時候還是會由於一些編程思想的疏忽,引起一些問題。這里記錄一下最近這段時間,在代碼review的過程中,發現的一些編碼問題。對於自己在軟件架構,編程思想等方面的提高做一些必要的積累。

2. Python的編碼思想和規范

(1) Python的異常處理
Python的異常處理類似於Java,也是通過try...catch的語法塊來進行異常捕捉。一般在工程項目中,需要在有異常或錯誤的地方記錄相應級別的日志。那么什么時候去記錄日志,什么時候去拋異常,是拋程序自己的異常,還是為了統一格式而拋自己提前定義好的異常,這些都是需要提前定義好編碼規則的。

先說一個原則就是:在函數的調用關系中,當最底層的函數運行有異常時,可以記錄異常的日志,拋異常時需要拋原始的異常,而不應該拋自己定義的異常。 因為如果拋自己定義的異常,這樣在調用該函數時,雖然依然可以捕捉到自己定義的異常,但是會丟失掉原來異常的鏈,也就是無法追蹤到最原始的引起異常的地方。

(2)慎用成員變量
Python雖然是非編譯性語言,但是它也具有面向對象的特性,因此可以用Python創建類,類里可以定義屬性和方法。但是,這里一定要慎用屬性(成員變量)。因為如果將一個屬性定義為成員變量,那么這個屬性值會隨着這個類的對象一直存在。這樣,如果在只創建一個類的對象,而多次用不同的參數來調用這個類的方法時,有可能會因為這個類的成員變量值,由於還保存着上一次調用時的值,而直接作用於下一次的函數調用,從而產生無法預知的錯誤。

之前,我無意識地將一個屬性設置為成員變量后,在調用類的方法時,不管外邊傳入的參數是什么值,輸出始終都是固定不變的。當時百思不得其解,后來通過debug代碼,才發現原來是由於將一個變量設置為了成員變量,而且這個成員變量是一個list. 所以每調用一次函數,都相當於往這個list類型的成員變量里面append一個元素,而最后輸出的值是這個list的第一個元素。因此不管用什么參數來調用這個函數,始終輸出的都是第一次調用時的那個返回值(list的第一個元素)。根本原因,就是每次調用完這個函數后,沒有將這個成員變量清空而導致的。找到問題后,將這個成員變量修改為局部變量。這樣每次調用完函數后,這個局部變量便會被銷毀。之前遇到的問題也就迎刃而解了。

(3)Python多線程引起的問題
之前在實現一個基於python的第三方庫 filesystem的ftp連接,下載文件和關閉ftp連接時,由於沒有意識到多線程的問題,而發生了意想不到的錯誤。
在自己本地開發測試時,由於沒有用多線程來測試,因此只是按照只有一個線程的思維,首先根據ftp的連接參數創建ftp連接,然后再根據傳入的根目錄下載文件,下載完畢后關閉ftp連接。看起來這個流程是沒有問題的。但是,當真正在多線程的環境下開始測試的時候,程序便在“關閉ftp連接時報錯。”出錯的原因是說,不能關閉未連接的ftp。
當時一直沒有想明白是什么原因,既然代碼已經走到了關閉連接的地方,那么必然是之前先連接了ftp,並且已經完成了文件下載的呀,怎么會提示要關閉的ftp是未連接狀態的呢。
后來,在同事的提醒下,知道這個是多線程的。因此,其實是同時有很多的線程在運行,而且由於整個多線程,是共用着一個ftp連接。因此,完全有可能一個線程剛把ftp連接起來,當這個線程完成了下載文件的操作后,准備去關閉這個ftp連接時,卻發現這個ftp連接已經被先於它下載完文件的線程給關閉了ftp連接。因此,才會發生前文中的異常。
了解了問題的根源后,便可以對症下葯了。那就是在每次關閉線程時,不能像原來那樣,直接把成員變量的ftp(當時是將ftp的連接設置為成員變量了)連接給關閉。這個ftp連接,當時除了基本的ip,username, password外,還有一個root_path。而每一個root_path其實是不同的。因此,本質上這個ftp的連接,其實如果加上后面的root_path是不同的。但是如果只以前面的三個參數連接時是相同的。
因此,最終的解決思路是,不降ftp連接作為成員變量,而是每次將在下載文件前建立的ftp連接對象(由: ip, username, password和root_path構成的連接串)返回,關閉ftp連接時,關閉返回來的這個ftp連接。這樣,就能保證每一個線程關閉的ftp連接都是屬於這個線程特有的ftp連接,而不會去關閉大家公用的那個ftp主連接(由: ip, username, password)。這樣多線程之間便不會相互干擾了。

3. 參考鏈接

  1. 《程序設計思想與方法》, 陸朝俊編著, 上海交通大學通識課“計算思維課程”教材
    https://wizardforcel.gitbooks.io/sjtu-cs902-courseware/content/index.html
    未完待續......


免責聲明!

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



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