如何自定义子类化行为或以特定方式要求子类化?

时间:2012-02-18 03:54:40

标签: python

假设我正在建立一个名为ModelController的班级。我希望这个类有一堆方法可以包装一个单独的Model类,这是我的数据库抽象。

我希望能够在ModelController上定义类方法,如下所示:

ModelController():
  @classmethod
  def list(cls):
    cls.model.list()
  @classmethod
  def byName(cls, name):
    return cls.model(name)

让Model类像这样:

ArticleModel(Model):
    pass

然后做这样的事情:

ArticleModelController(ModelController):
  # ??? maybe:
  # model = ArticleModel

我想我可以将我的Model类继承为控制器,然后使用某种mixin模式,但我希望模型成为控制器的类属性的原因是我真的不想冒险当我在一个cherrypy方法调度程序或类似的东西中挂载这个类时,通过HTTP公开它的一些方法。

也许我正在做一些从根本上说不是pythonic或犯下某种谬误的事情。我想做'魔术'吗?

编辑:我只记得我过去的Django及其ModelForms。他们的工作方式如下:

class ArticleForm(ModelForm):
    class Meta:
        model = Article

也许这就是我应该关注的内容。是否有可能验证此“模型”属性是否已定义,如果某些内容未被定义,则会抛出错误?

2 个答案:

答案 0 :(得分:2)

是元类:

class ModelControllerMetaclass(type):
  def __init__(cls, name, bases, dct):
    if 'options' not in dct or not hasattr(dct['options'], 'model'):
      raise RuntimeError('You accidentally the model!')
    dct['_model'] = dct['options'].model
    # Some more manipulation of dct['options']
    del dct['options']
    type.__init__(cls, name, bases, dct)

class ModelController(object):
  __metaclass__ = ModelControllerMetaclass
  class options:
    model = None

class ArticleModelController(ModelController):
  class options:
    model = 'Some model goes here'

class InvalidModelController(ModelController):
  pass

跑步时:

$ python t.py
Traceback (most recent call last):
  File "t.py", line 19, in <module>
    class InvalidModelController(ModelController):
  File "t.py", line 4, in __init__
    raise RuntimeError('You accidentally the model!')
RuntimeError: You accidentally the model!

答案 1 :(得分:0)

我想我已经弄明白了。我认为元类可能是解决方案,但我读了很多东西说你可能做错了,除非你肯定知道你需要一个元类。不过,它给出了我想要的确切行为。这是我的ModelController课程:

class ModelController():
  @classmethod
  def list(cls):
    return cls.meta.model.list()

  def __init__(self):
    self.model = self.__class__.meta.model

然后我可以有一个模型:

class ArticleModel():
  @classmethod
  def list(cls):
    # logic to retrieve the list of things fitting this class

最后,在我的实际Controller中,我将在cherrypy中安装:

class ArticleController():
  class meta:
    model = ArticleModel

  def index(self):
    article_list = self.model.list()
    return render(article_list)

  index.exposed = True

这是邪恶吗?它是魔术还是不够明确?我的Ruby根源显示了吗?从这一点开始,我需要做的就是定义新的模型和控制器,如果我忘记在我的控制器的元类中定义model属性,当我的挂载方法尝试调用东西时会抛出错误模特。