Python类更换器

时间:2010-11-10 08:54:50

标签: python architecture coding-style metaprogramming

我需要来自数据库的类运行时类声明。

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

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?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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()进行模块名称查找,因为它是字符串而不是模块。

编辑:oops,它应该是globals()

相关问题