2010-11-10 34 views
4

我需要从数据库的类运行时类声明。Python类更换器

某些类需要重写字段和重新声明。

models.py

 
class Staff(object): 
    name = StringField(verbose_name = "Full name") 
    age = IntegerField(verbose_name = "Age") 

utils.py

 
def class_changer(class_path, field_key, new_Field): 
    pass 
    ?????? 
>>> class_changer("models.Staff", "gender", BooleanField()) # Add new field to Staff 
>>> class_changer("models.Country", "name", StringField()) # Add new class with name field 
>>> class_changer("models.Staff", "country", ForeignKey("Country")) # Add new field to Staff 

结果是

 
class Staff(object): 
    name = StringField(verbose_name = "Full name") 
    age = IntegerField(verbose_name = "Age") 
    gender = BooleanField() 
    country = ForeignKey("Country") 

class Country(object): 
    name = StringField() 

如何实现class_changer?

+0

'setattr'&'eval'的组合可能对您有所帮助 - 不健壮但易于实现 – shahjapan 2010-11-10 09:05:26

+0

我发现了太多的方法。 http://en.wikipedia.org/wiki/Aspect-oriented_programming eval,setattr,装饰者....但我不知道如何女巫的方法更好?我没有几个经验。 – Ankhaa 2010-11-10 09:21:38

+1

很明显,你正在用django来做这件事,所以你应该知道,考虑到这样做会伤害我的头,因为它们使用的所有元类:所有东西都与其他东西相连。我通常也是一位非常幸运的幸运程序员,但我只是从这个开始走开。我建议你做得好,并考虑更好的架构。你想要实现什么目标? – aaronasterling 2010-11-10 10:04:06

回答

4

你需要为这个更好的结构,但作为一个出发解决方案,你可以试试这个,

In [12]: class a1(object): 
    ...:  pass 

In [13]: def class_changer(cls_path, attr, val): 
    ....:  try: 
    ....:   obj = eval(cls_path) 
    ....:   setattr(obj, attr, val) 
    ....:  except: 
    ....:   raise 
    ....:  
In [14]: def getGender(self): 
    ...:  return True 


In [15]: class_changer('a1','getGender', getGender) 

In [16]: a1().getGender() 
Out[16]: True 
+0

阅读[这个问题](http://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice),尤其是围绕它接受的答案和讨论,以了解一些'eval'的风险和警告。这并不是说解决方案不好,但你应该知道你正在进入什么。 – 2010-11-10 09:23:58

+0

yeah eval是有害的,这是所有人都应该知道的事实,但是确切地说,当用户的输入将被评估时,如果程序员为自己的目的而编写eval - 那么不管其声明是否应该被视为风险 - 它应该被视为灵活性或程序员的选择或功能任何.... – shahjapan 2010-11-10 16:59:03

1

首先增加新的属性的类:

>>> class_changer("models.Staff", "gender", BooleanField()) # Add new field to Staff 
>>> class_changer("models.Staff", "country", ForeignKey("Country")) # Add new field to Staff 

对于这两个,干脆去并设置Staff直接:

models.Staff.gender = BooleanField() 
models.Staff.country = ForeignKey("Country") 

还是要使它通用:

def add_to_class(cls, name, attr): 
    setattr(cls, name, attr) 

add_to_class(models.Staff, "gender", BooleanField()) 
add_to_class(models.Staff, "country", ForeignKey("Country")) 

其次,创建一个新类:

>>> class_changer("models.Country", "name", StringField()) # Add new class with name field 

您可以在函数创建一个类,然后将其分配到一个模块:

def new_class(mod, name): 
    class New(object): pass 
    setattr(mod, name, New) 

new_class(test, "Country") 
add_to_class(test, "Country", StringField()) 

我不知道你我想结合new_classadd_to_class,但我想你可以这样做:

def create_if_needed_and_add_to_class(mod, clsname, attrname, value): 
    if clsname not in dir(mod): 
     new_class(mod, clsname) 
    add_to_class(mod, attrname, value) 

,然后最后你class_changer

def class_changer(mod_clsname_string, attrname, value): 
    modname, clsname = '.'.split(mod_clsname_string) 
    create_if_needed_and_add_to_class(globals()[modname], clsname, attrname, value) 

编辑:固定class_changer使用locals()模块的名称查找,因为它是一个字符串,而不是一个模块。

编辑:哎呀,应该是globals()

+0

这是伟大的。对我和对Python的特殊功能非常有用。 – Ankhaa 2010-11-11 12:12:33