簡體   English   中英

使用Python全局變量的動態類的最佳方法()

[英]Best approach with dynamic classes using Python globals()

我正在開發一個Web應用程序,它將根據用戶輸入返回一組可變模塊。 每個模塊都是一個Python類,其構造函數接受單個參數,並具有包含輸出的“.html”屬性。

從全局命名空間動態提取類的工作原理如下:

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

而且它肯定比以下更簡潔:

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

什么被認為是風格上寫這個的最佳方式? 是否存在不使用全局命名空間的風險或原因?

這種方法的一個缺陷是它可能使用戶能夠比你想要的更多。 他們可以通過提供名稱來調用該命名空間中的任何單參數函數。 您可以通過一些檢查來幫助防范這種情況(例如isinstance(SomeBaseClass,theClass),但它可能更好地避免這種方法。另一個缺點是它限制了您的類位置。如果您最終得到了幾十個這樣的類並決定要將它們分組到模塊中,您的查找代碼將停止工作。

您有幾種備選方案:

  1. 創建顯式映射:

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

    雖然這樣做的缺點是你必須重新列出所有的類。

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

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

    你在這里無意中暴露了一些額外的類變量(__bases __,__ getattribute__等) - 可能無法利用,但並不完美。

  3. 從子類樹構造一個查找字典。 使所有類繼承自單個基類。 創建所有類后,檢查所有基類並從中填充dict。 這樣做的好處是您可以在任何地方定義您的類(例如,在單獨的模塊中),並且只要您在創建完成后創建注冊表,您就會找到它們。

     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) 

    上面的一個更高級的變體是使用自注冊類 - 創建一個元類,而不是自動在dict中注冊任何創建的類。 對於這種情況,這可能有點過頭了 - 但它在一些“用戶插件”場景中很有用。

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

你這樣做的方式沒有任何問題 ,實際上,但根據我的經驗,它往往表明你的程序中存在某種“缺失的抽象”。 您基本上依賴Python解釋器來存儲您可能需要的對象列表,而不是自己存儲它。

因此,作為第一步,您可能只想創建一個您可能想要調用的所有類的字典:

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

最初,這不會產生太大的影響。 但隨着您的Web應用程序的增長,您可能會發現以下幾個優點:(a)您不會遇到命名空間沖突,(b)使用globals()您可能遇到安全問題,攻擊者實際上可以訪問任何全局符號你的程序,如果他們可以找到一種方法將任意classname注入你的程序,(c)如果你想讓classname不是實際的確切類名,使用你自己的字典會更靈活,(d)你可以使用更靈活的用戶定義類來替換dispatch字典,該類可以在需要時進行數據庫訪問或類似的操作。

對於Web應用程序,安全問題特別突出。 執行globals()[variable]從web表單輸入variable只是在尋找麻煩

在類名和類之間構建映射的另一種方法:

定義類時,將屬性添加到要放入查找表的任何類中,例如:

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")])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM