簡體   English   中英

在Python中使用元類填充Factory

[英]Populating Factory using Metaclasses in Python

顯然,在Python中注冊類是元類的主要用例。 在這種情況下,我有一個序列化模塊,該模塊當前使用動態導入來創建類,我更喜歡將其替換為工廠模式。

因此,基本上,它是這樣做的:

data = #(Generic class based on serial data)
moduleName = data.getModule()
className = data.getClass()
aModule = __import__(moduleName)
aClass = getattr(aModule, className)

但我希望它這樣做:

data = #(Generic class based on serial data)
classKey = data.getFactoryKey()
aClass = factory.getClass(classKey)

但是,有一個障礙:如果我讓工廠依賴元類,則工廠僅在導入模塊后才知道類的存在(例如,它們是在模塊導入時注冊的)。 因此,要填充工廠,我必須:

  1. 手動導入所有相關模塊(這實際上會破壞讓元類自動注冊事物的目的……)或
  2. 自動導入整個項目中的所有內容(這讓我感到難以置信且笨拙)。

在這些選項中,將類直接注冊到工廠似乎是最好的選擇。 有沒有人找到我沒有看到的更好的解決方案? 一種選擇可能是通過遍歷項目文件來自動生成工廠模塊中所需的導入,但是除非您使用提交鈎子來執行此操作,否則可能會導致工廠過時的風險。

更新:

我發布了一個自我解答,以結束此問題。 如果有人知道一種很好的方式來遍歷嵌套子包中的所有Python模塊,而且這種方式永遠不會發生循環,那么我將很樂意接受該答案,而不是這個答案。 我看到發生的主要問題是:

\A.py (import Sub.S2)
\Sub\S1.py (import A)
\Sub\S2.py
\Sub\S3.py (import Sub.S2)

當您嘗試導入S3時,它首先需要導入Main(否則將不知道Sub是什么)。 此時,它嘗試導入A。在那里,將調用__init__.py ,並嘗試注冊A。這時,A嘗試導入S1。 由於Sub中的__init__.py被命中,因此它將嘗試導入S1,S2和S3。 但是,S1想要導入A(它尚不存在,因為它正在導入中)! 因此導入失敗。 您可以切換遍歷的方式(即深度優先而不是廣度優先),但是遇到相同的問題。 對此有很好的遍歷方法的任何見解都將非常有幫助。 兩階段方法可能可以解決該問題(即遍歷以獲取所有模塊引用,然后作為統一批處理導入)。 但是,我不太確定處理最后階段的最佳方法(即知道何時完成遍歷然后再導入所有內容)。 我的最大限制是我不想擁有一個超級包來處理(即Sub和A下的一個額外目錄)。 如果我這樣做了,它可能會開始遍歷,但是所有的導入都沒有充分的理由(例如,所有的導入都需要一個額外的目錄)。 到目前為止,向sitecustomize.py添加一個特殊的函數調用似乎是我唯一的選擇(無論如何,我還是在該文件中為軟件包開發設置了根目錄)。

我發現的解決方案是基於特定的基本目錄對軟件包進行所有導入,並對所有可能具有要注冊的類的模塊具有特殊的__init__.py函數。 因此,基本上,如果您導入任何模塊,則它首先必須導入基本目錄,然后繼續遍歷每個具有類似__init__.py文件的軟件包(即文件夾)。

這種方法的缺點是有時會多次導入相同的模塊,如果有人在模塊導入中留下帶有副作用的代碼,這將很煩人。 但是,這兩種方法都不好。 不幸的是,如果您這樣做,某些主要軟件包(咳嗽,咳嗽:燒瓶)會對IDLE造成嚴重的投訴(IDLE只是重新啟動,而不是做任何事情)。 另一個缺點是,由於模塊彼此導入,因此有時它會嘗試導入已經在導入過程中的模塊(一個容易捕獲的錯誤,但我仍在嘗試淘汰)。 這並不理想,但是確實可以完成工作。 附件中附有有關更具體問題的其他詳細信息,如果有人可以提供更好的答案,我將很樂意接受。

暫無
暫無

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

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