標籤:

python的應該一個class放一個文件嗎?

本人python只學了皮毛。

事情是這樣的,用SqlAlchemy定義Model類,官方教程都是寫在一坨里的,我按照其它語言的習慣,一個Model的class分一個文件。比如為area表定義一個Area類,放在Area.py里。然後調用的時候報錯,TypeError: module object is not callable

愣了半天才查出結果,我前面import Area其實只是引入了Area這個module,它不是個class啊!

於是得把代碼改成這樣:from Area import Area

然後就不報錯了。

可是這樣又覺得特傻,難道引入一個類就要把類名寫兩遍?感覺寫兩遍彆扭,可不這樣的話,文件名叫什麼呢?

如果不堅持一個class一個文件,倒是大可把這個文件命名為model.py,然後在這個文件里把所有的模型類都寫進去。什麼class User啊,class Article啊,class Area啊,都塞一起。用的時候,from model import Area就行。但這樣未免不美。

那麼,python設計的初衷到底是希望我們怎麼寫代碼呢?

請大神為我解惑。


如果你糾結from Area import Area

可以加一個xxx/__init__.py,把from Area import Area寫進去,這樣在外面調用的時候可以直接import xxx.Area。

如果你覺得把User等寫到model.py里使用的時候from model import User很醜,可以直接import model,然後使用model.User。

其實這也未必能解決你的困惑,代碼風格本來就是仁者見仁智者見智。

可以從另一個角度設立目標,比如可維護、可擴展、介面方便、使用方便等等。

相對應的,對於可維護,我們一般從某個維度儘可能把功能拆分,一個文件的內容不長。

對於可擴展,需要設計良好的代碼架構,從擴展的角度評價,是不是很容易添加插件,增強功能。

對於介面方便,主要是看最外層暴露的介面,當然實現方式也會影響介面方式。

對於使用方便,如果都寫到一個py里,使用者只下載一個文件,然後執行來完成某個任務會方便很多。

你會看到,面向對象編程已經逐步延伸到,面向同事編程、面向自己編程、面向開發者編程、面向用戶編程了。希望此時的你還關注代碼風格,糾結代碼質量,不僅僅關注代碼的功能,保持內心的小驕傲。


個人經驗,遵循一個原則——高內聚,低耦合。

一個文件(模塊)中的內容盡量是按照某種方式(業務、主題、邏輯等)聚合在一起的。

除非兩個模塊是相互依賴的關係(比如view依賴model或者業務view依賴抽象出來的baseview),否則不應該出現相互引用。


python 按照包和模塊來組織項目的,如果類不多的話,你沒有必要和Java一樣,一個類寫一個文件。相同功能的類完全可以寫在一個模塊中。

6. Modules - Python 3.6.4 documentationdocs.python.org

看看開源軟體是怎麼組織項目的

https://github.com/requests/requestsgithub.com圖標


建議題主 入鄉隨俗 ,既然入了 Python 就別老想著 Java 的寫法了,Python 中有的是規範來指導你如何編寫優美的代碼,畢竟人家 Python 的 PEP 規範 早已破千了。

Python 有一個最大的特點就是對語言風格非常看重,堪稱各語言之最。它的創始人 Guido van Rossum 是一個語言風格強迫症患者,他親自操刀寫的 [PEP8] Python 風格指南 就像我們的《小學生守則》一般,入門必看。另外,同樣著名的還有 [PEP20] Python 之禪 ,堪稱每個 Python 程序猿的八字箴言:

&>&>&> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases arent special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless youre Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, its a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- lets do more of those!

正是這些細緻入微的約束使得 Python 代碼簡潔而優雅的設計得以延續。Python 語言比其他語言更在意代碼風格的統一和美感,甚至連第三方庫的 API 介面都高度統一。舉個例子:

Python 對資料庫的支持非常友好,不管是 MySQL、SQL Server、Mongodb、sqlite 等都有對應的第三方庫可用:mysql-pythonpymssqlpymongosqlite,這些庫對資料庫的操作有著驚人地相似的 API,如:都包含connectcursor等概念,都有executeexecutemanyfetchonefetchmany等函數介面,甚至連函數的名稱、參數、返回值都一模一樣。

怎麼會這麼統一呢?這是因為 PEP249 已經明確說明了只要編寫資料庫引擎就要遵循這套規範。這對庫的作者以及下游開發者都非常有利,庫的作者不必費心巴力地思考 API 應當如何設計,下游開發者也不必因為更換資料庫而學習新的介面,即只需要一套代碼,想換什麼資料庫就換什麼資料庫,你說爽不爽~


好了,開始答題~

首先指出題主一個「入鄉不隨俗」的地方:Python 的模塊名稱推薦採用「蛇形命名法」,即首字母大寫,單詞以下劃線連接:

# bad
Area.py
AreaModel.py

# good
area.py
area_model.py

至於題主的疑問:不同的 class 應不應該放在同一個模塊下?

我的回答是:請隨意,只要保證你的模塊 高內聚、低耦合 即可。也就是說,只要幾個 class 在功能上是有關的,就應該放在同一個模塊里;在功能上無關的 class 可以放在不同的模塊中。

事實上,Python 官方通常都是這麼乾的,把功能相關的多個 class 封裝在同一個模塊中,比如我們所熟知的urllib庫:

它的目錄結構如下。幾個主要模塊request.pyparse.pyerror.py等每一個都負責一塊獨立的功能 :

urllib 庫的目錄結構

而模塊內部呢,N 多個類和函數混在一塊是再正常不過的事兒了,只不過這些類和函數都在為同一個目標而奮鬥:實現一塊獨立的功能

request.py

request.py

parse.py

parse.py

error.py

error.py

如果你想找到更多的例子,可以多看看 Python 官方庫的源碼,就在 Python 安裝目錄下,比如在我電腦上是 C:Program FilesPython36Lib

因此,我覺得把多個 class 放在同一個模塊中並不會破壞美感,反而會使得各個模塊的功能更加聚合,而不是扁平結構的一盤散沙。反過來再想一想,這不就是「模塊」這個概念的本意嗎!如果每個 class 都獨佔一個模塊,那還要模塊幹什麼呢?!


多讀源代碼,有的web框架就一個文件呢


推薦閱讀:

使用Python實現一個文本自動摘要工具
winpython, anaconda 哪個更好?
python里函數作為返回值如何進行比較?
python中BeautifulSoup解析然後select提取到的內容如何用正則來來匹配?
Python3.6正式版要來了,你期待哪些新特性?

TAG:Python |