2010-10-05 52 views
5

我相信可讀性和KISS原則是編程中最重要的事情。這就是爲什麼我使用Python :)
這裏是確切的情況,這是我遇到的很多時候:從小腳本過渡到更大的應用程序並不容易

說,我有一個非常乾淨的腳本,這是數據庫處理的包裝:

import database_schema as schema 
loader = schema.Loader("sqlite:///var/database.db") 
session = loader.session 

def addUser(name, full_name, password): 
    user = schema.User(name, full_name, password) 
    session.add(user) 
    session.commit() 

def listUsers(): 
    all_users = session.query(schema.User).all() 
    return all_users 

這是用這樣的:

import database 
database.addUser("mike", "Mike Driscoll", "password") 
database.listUsers() 

在某些時候,我想重寫模塊,使之能與不同的路徑上的數據庫工作(單元測試,例如)。

那麼,我有什麼選擇?

  1. 最直觀的是增加database_path == ""變量,然後......什麼?使用setPath(new_path)函數進行設置,然後將異常(if database_path == "": raise SomeException)添加到每個函數中,這都很醜,不應該由任何人完成。

  2. 全功能的類,在初始化時設置self._database_path

然後其被這樣使用:

from database import Database 
database = Database("sqlite:///var/database.db") 
database.addUser("mike", "Mike Driscoll", "password") 
database.listUsers() 

這已經是多行的代碼比在第一示例中,與另外的命名問題的:模塊database在具有稱爲Database一個類有點笨,不是嗎?

對不起,長時間閱讀,在這裏我最後的問題:

  1. 爲什麼沒有這樣的東西作爲__init__功能模塊,在Python?
  2. 我是否缺少一些東西(靜態類變量等),它可以做我想做的事(在導入時設置一個常量)簡單而乾淨的方式,這仍然離一個簡單的模塊不遠處最初的功能?

P.S.對不起我的英語不好。

編輯:

因此,要明確這一點,此代碼看起來怎麼樣在我的想象力Python的宇宙:

import database_schema as schema 

def __init__(database_path): 
    loader = schema.Loader(database_path) 
    global session 
    session = loader.session 

def addUser(name, full_name, password): 
    user = schema.User(name, full_name, password) 
    session.add(user) 
    session.commit() 

def listUsers(): 
    all_users = session.query(schema.User).all() 
    return all_users 

而像這樣使用:

import database("sqlite:///var/database.db") 

database.addUser("mike", "Mike Driscoll", "password") 
database.listUsers() 

回答

2

模塊是一個具有任意命名屬性的Python對象,您可以將其綁定和引用。一個名爲mod的模塊的Python代碼通常駐留在一個名爲mod.py的文件中。當您嘗試導入它時,會創建一個新的名稱空間,其中包含該模塊的所有屬性。

雖然都說了,但它不同於該類的對象實例的類和創建。 這些是不同的抽象,應該這樣使用。

,而不是測試

if database_path == "": 
    .... 

做Python的方式

if database_path: 
    .... 

而且,而不是提高例外,你可以使用斷言

assert database_path != "", 'database path empty' 

模塊做不存在於像類的對象實例那樣的風味中。每次導入模塊時,導入模塊都會創建一個具有相同屬性的命名空間。 在這種情況下,init可能沒有多大意義。

您提供的第二種代碼形式沒有任何問題。 和你,如果你不想這樣做,他們一些上述成語可以減輕你的痛苦:)

+0

感謝您的提示,但沒有足夠的聲望upvote雖然。仍然不明白爲什麼不能在導入模塊後運行一個函數(請參閱更新到原始文章)。並且仍然認爲,必須記住手動執行此操作(調用setPath),以及將「斷言數據庫路徑」,「數據庫路徑爲空」等重複放置到使用該變量的每個函數中是不好的。 – kolobos 2010-10-05 10:21:45

+0

@kolobos我現在在前面沒有解釋器,但是當模塊被導入時,不是模塊中的代碼_executed_?也就是說,讓你的'__init__'例程的內部語句是全局的。 – mlvljr 2010-10-05 11:02:46

+0

@mlvljr您是對的,當導入模塊時,「全局級」的所有內容都會執行。這裏的問題是如何告訴模塊的數據庫路徑,以及如何做到最「恰當」和優雅的方式。正如你在我的回答中看到的那樣,升級到課程似乎只能走。 – kolobos 2010-10-05 11:36:07

0

,我發現的唯一的解決辦法是從文件加載配置:

import ConfigParser 
config = ConfigParser.RawConfigParser() 
config.read('config.ini') 

def getSession(): 
    loader = schema.Loader(config.get('Global', 'database')) 
    return(loader.session) 
... 

哪個不完美:文件本身的名稱是硬編碼的,如果你想在不同的(例如空的)數據庫上進行單元測試,你必須重新分配配置,然後在完成時恢復它,不是很優雅。

1

對於這種情況,我使用可選參數。

def addUser(name, full_name, password, _loader=None): 
    user = schema.User(name, full_name, password) 
    if (_loader is None): 
     # Use global values. 
     session.add(user) 
     session.commit() 
    else: 
     _session = _loader.session 
     # ... 

我,我自己,遠離初始化這樣的東西在模塊加載。想象一下你想用epydoc這樣的工具創建文檔。僅僅因爲epydoc加載模塊,在這種情況下創建連接是沒有意義的。我肯定會採用班級方式。

+0

提及與此相關的文檔問題。是的,上課似乎只是正確的做事方式,只是想知道爲什麼「模塊與一堆功能」和「全功能課堂」之間沒有任何關係。我剛剛發現自己在導入時加載數據庫引擎時,對SQLAlchemy使用declarative_base擴展,但這是另一個問題。 – kolobos 2010-11-18 14:11:22

相關問題