2013-08-20 91 views
2

我正在使用聲明性基礎使用SQLAlchemy創建後端應用程序。 ORM需要大約15個表,每個表映射到SQLAlchemy中的類對象。因爲這些類對象都是完全相同的,所以我認爲工廠模式可以更簡潔地生成類。但是,這些類不僅必須定義,而且必須分配給唯一的變量名稱,以便可以通過項目導入和使用它們。SQLAlchemy中的動態Python類定義

(很抱歉,如果這個問題是有點長,我更新了它,因爲我更好地理解這個問題。)

因爲我們有這麼多列(〜1000),我們定義在外部文本文件到自己的名字和類型保持可讀性。做完這一個方式去宣佈我們的模型是這樣的:

class Foo1(Base): 
    __tablename___ = 'foo1' 

class Foo2(Base): 
    __tablename___ = 'foo2' 

... etc 

,然後我可以通過循環在外部文本文件的內容,並使用每個類定義的setattr()添加列。

這是好的,但它感覺太重複了,因爲我們有大約15張桌子。所以我反而試圖編寫一個可以動態定義類的工廠函數。

def orm_factory(class_name): 
    class NewClass(Base): 
     __tablename__ = class_name.lower() 
    NewClass.__name__ = class_name.upper() 
    return NewClass 

我再次可以遍歷列並使用setattr()。當我把它在一起,它看起來像這樣:

for class_name in class_name_list: 
    ORMClass = orm_factory(class_name) 
    header_keyword_list = get_header_keyword_list(class_name) 
    define_columns(ORMClass, header_keyword_list) 

get_header_keyword_list獲取列信息和define_columns執行setattr()分配。當我使用它並運行Base.metadata.create_all()時,SQL模式就會生成得很好。

但是,當我再嘗試將這些類定義導入到另一個模型,我得到這樣的錯誤:

SAWarning: The classname 'NewClass' is already in the registry of this declarative base, mapped to <class 'ql_database_interface.IR_FLT_0'> 

這一點,我現在意識到使得基於總的意義是什麼我昨天獲悉:Python class variable name vs __name__

您可以在工廠函數中使用type作爲類生成器來解決此問題(以下是兩個答案)。但是,這並不能解決導入類的問題,因爲雖然類在工廠函數中動態構建,但該函數的輸出分配給的變量是靜態的。即使它是動態的,如字典鍵,它也必須位於模塊名稱空間中才能從其他模塊導入。查看我的答案瞭解更多詳情。

回答

1

[注,這是樓主]

所以經過一番思考和說話的人,我已經決定,這種能力動態以這種方式創建和分配全局名稱空間中的類對象的變量,這不僅僅是Python支持的(可能有很好的理由)。儘管我認爲我的用例不是太瘋狂(抽出預定義的相同結構類的列表),但它不被支持。

在這種情況下,有很多問題指向使用字典,例如:https://stackoverflow.com/a/10963883/1216837。我想過這樣的事情,但問題是我需要模塊名稱空間中的這些類,以便我可以將它們導入到其他模塊中。不過,像globals()['MyClass'] = class_dict['MyClass']這樣的globals()加上它們看起來好像很不錯,而且我的印象是人們對這樣使用globals()而皺眉。

有一些黑客,如patjenk建議的黑客,但在某個時候,混淆和複雜性的重點是靜態聲明每個類對象的清晰度的好處。所以雖然看起來重複,但我只是寫出所有的類定義。真的,這最終會被很簡潔/可維護性:

Class1 = class_factory('class1') 
Class2 = class_factory('class2') 
... 
+0

爲什麼你需要,如果你添加的構造類的外範圍容器(list_of_classes.append或字典)修改全局?容器本身可以跨模塊導入,因爲容器將在模塊範圍內。 – cowbert

1

這聽起來像一個粗略的想法。但解決這個問題很有趣,所以這裏是你如何使它工作。

據我所知,你的問題是你想動態創建的類添加到模塊。我使用模塊和init .py文件創建了一個hack。

dynamicModule/__ init__.py:

import dynamic 

class_names = ["One", "Two", "Three"] 

for new_name in class_names: 
    dynamic.__dict__['Class%s' % new_name] = type("Class%s" % (new_name), (object,), {'attribute_one': 'blah'}) 

dynamicModule/dynamic.py:

"""Empty file""" 

測試。潘岳:

import dynamicModule 
from dynamicModule import dynamic 
from dynamicModule.dynamic import ClassOne 

dynamic.ClassOne 
"""This all seems evil but it works for me on python 2.6.5""" 

__init__.py:

"""Empty file"""