2008-10-21 78 views
6

我正在研究一個Web應用程序,它將根據用戶輸入返回一組變量模塊。每個模塊都是一個帶有構造函數的Python類,它接受單個參數並且具有包含輸出的「.html」屬性。使用Python全局變量動態類的最佳方法()

從全局命名空間動態拉動類的工作:

result = globals()[classname](param).html 

而且它比肯定更簡潔:

if classname == 'Foo': 
    result = Foo(param).html 
elif classname == 'Bar': 
    ... 

什麼被認爲是寫這篇文章,文體最好的方法是什麼?是否有風險或理由不使用全局命名空間?

回答

6

這種方法的一個缺陷是,它可能會讓用戶能夠超過你想要的。他們只需提供名稱即可在該名稱空間中調用任意單參數函數。你可以用一些檢查來幫助防止這種情況(例如,isinstance(SomeBaseClass,theClass)),但它可能更好地避免這種方法。另一個缺點是它限制了你的班級安排。如果你最終得到幾十個這樣的班級並決定他們組成模塊,您的查找代碼將停止工作

您有幾種備選方案:

  1. 創建一個明確的映射:

    class_lookup = {'Class1' : Class1, ... } 
    ... 
    result = class_lookup[className](param).html 
    

    雖然這樣也有,你有缺點重新列表al l課程。

  2. 將這些類嵌套在封閉範圍內。例如。自己的模塊中定義它們,或外部類中:

    class Namespace(object): 
        class Class1(object): 
         ... 
        class Class2(object): 
         ... 
    ... 
    result = getattr(Namespace, className)(param).html 
    

    你在不經意間暴露了幾個額外類變量的這裏雖然(__bases__來得到,__getattribute__等) - 可能無法利用,但並不完美。

  3. 從子類樹構造一個查找字典。讓所有的類都從一個基類繼承而來。當所有的類都被創建後,檢查所有的基類並從它們中填充一個字典。這樣做的好處是你可以在任何地方定義你的類(例如,在單獨的模塊中),並且只要你在創建完成之後創建註冊表,你就可以找到它們。

    def register_subclasses(base): 
        d={} 
        for cls in base.__subclasses__(): 
         d[cls.__name__] = cls 
         d.update(register_subclasses(cls)) 
        return d 
    
    class_lookup = register_subclasses(MyBaseClass) 
    

    以上更高級的變體是使用自注冊類 - 創建一個元類比在一個字典自動註冊任何創建的類。對於這種情況,這可能是過分的 - 它在一些「用戶插件」場景中很有用。

4

首先,這聽起來像你可能重新發明了一點點......大多數Python Web框架(CherryPy/TurboGears就是我所知道的)已經包含一種方法來根據內容向特定類發送請求的URL或用戶輸入。

沒有什麼錯誤與你這樣做的方式,真的,但根據我的經驗,它往往表明你的程序中的某種「缺少抽象」。你基本上依靠Python解釋器來存儲你可能需要的對象列表,而不是自己存儲它。

因此,作爲第一步,你可能只想讓所有你可能需要調用類的詞典:

dispatch = {'Foo': Foo, 'Bar': Bar, 'Bizbaz': Bizbaz} 

最初,這不會有太大的差別。但隨着您的網絡應用程序的增長,您可能會發現幾個優點:(a)您不會遇到名稱空間衝突,(b)使用globals()您可能存在安全問題,攻擊者本質上可以訪問程序中的任何全局符號(c)如果你想讓classname不是實際的確切類名,那麼使用你自己的字典將會更加靈活,(d)你可以替換dispatch字典與一個更靈活的用戶定義的類,可以訪問數據庫或類似的東西,如果你發現需要。

Web應用程序的安全問題尤其突出。做globals()[variable]其中variable是從網絡表單輸入只是問題

0

另一種方式來建立類名和類之間的映射:

當定義類,添加要放在查找表中任一類別的屬性,如:

class Foo: 
    lookup = True 
    def __init__(self, params): 
     # and so on 

完成此操作後,構建查找圖爲:

class_lookup = zip([(c, globals()[c]) for c in dir() if hasattr(globals()[c], "lookup")]) 
相關問題