V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
kidlj
V2EX  ›  Python

Django models 里的类为什么要用类变量而不是实例变量?

  •  
  •   kidlj ·
    kidlj · 2014-12-14 12:49:29 +08:00 · 4170 次点击
    这是一个创建于 3633 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚刚接触Django,读它的overview 文档,发现在models.py里的类没有定义__init__方法,而是定义了类变量(Class Variable):

    class Reporter(models.Model):
                    full_name = models.CharField(max_length=70)
    

    而后却能正常初始化实例:

    r = Reporter(full_name='John Smith')
    

    我知道这里肯定是用了什么魔法,比如metaclass之类的东西。可是为什么不直接将这些变量定义为在__init__方法之中的实例变量?

    13 条回复    2014-12-15 08:21:21 +08:00
    RIcter
        1
    RIcter  
       2014-12-14 13:00:49 +08:00   ❤️ 1
    看一下 models.Model 的源码_(:з」∠)_
    在 __init__ 里有写..虽然窝看不太懂OAQ
    messense
        2
    messense  
       2014-12-14 13:01:00 +08:00   ❤️ 1
    用了 metaclass 和 descriptor,建议去读一下 model 部分的源码。
    RIcter
        3
    RIcter  
       2014-12-14 13:04:09 +08:00   ❤️ 2
    另外定义成 __init__ 方法中的变量多丑..
    比如:

    def __init__(self, name, title):
    缩缩self.name = name
    缩缩self.title = title
    缩缩super(SampleModel, self).__init__()

    ...麻烦死了辣
    bcxx
        4
    bcxx  
       2014-12-14 13:22:31 +08:00   ❤️ 1
    @RIcter 不是丑不丑的问题,是用类变量才能让这个 model 类的 instance 都具有相同的 mapping。具体实现就是 @messense 提到的用 metaclass 来在 __new__ 的时候进行处理。
    kidlj
        5
    kidlj  
    OP
       2014-12-14 13:30:34 +08:00
    @RIcter @messense Django源码我就先不读了,先把应用写起来吧。只是乍一看到类里面统统使用类变量感觉奇怪,觉得这肯定是有什么目的的。

    @bcxx “用类变量才能让这个 model 类的 instance 都具有相同的 mapping”,虽然目前还看不懂这句话,但是起码知道了这里使用类变量而不是实例变量的必要性,是有其理由的。
    messense
        6
    messense  
       2014-12-14 13:33:14 +08:00   ❤️ 1
    @kidlj Django 的实现比较复杂,可以先看看 peewee 这个小巧的 ORM 框架里的实现方法,挺简单的。
    messense
        7
    messense  
       2014-12-14 13:37:11 +08:00   ❤️ 2
    metaclass 和 descriptor 这些“魔法”可以实现一些很优雅的东西,ORM 是其中之一。我写的 wechatpy 项目用 metaclass 和 descriptor 实现了对微信公众号消息的 mapping 和生成,也比较简单。

    https://github.com/messense/wechatpy/blob/master/wechatpy/messages.py#L29
    kidlj
        8
    kidlj  
    OP
       2014-12-14 13:53:48 +08:00
    找到了这么一条解释:

    “ Django provides a metaclass for Model which scans class attributes and converts them to instance attributes but only if they subclass Field.”

    http://stackoverflow.com/a/22993791

    但比起从类变量到实例变量的转化是怎么实现的,我目前更想知道的是为什么不直接使用实例变量,而非要用类变量的方式呢?这个问题可以等到以后再去考察吧。

    我想现在先认识到这种使用方法就够了。感谢大家。
    messense
        9
    messense  
       2014-12-14 14:00:13 +08:00   ❤️ 1
    @kidlj 使用实例变量的话 Django 不好从 model 生成 SQL 啥的,用类变量通过 metaclass Django 在运行时记录了所有的信息,然后可以做生成 SQL、验证数据啥的。实例变量你再赋值,Field 信息就没了......
    ccdjh
        10
    ccdjh  
       2014-12-14 14:15:10 +08:00
    没想过回复的,不小心,不知道,手一抖,点了感谢 @RIcter -_-
    为了不让你困惑,告诉你,我是不小心点感谢回复你的,没其他意思。

    平时用tornado,自己写一个简单通用于各数据model。只有几行代码。你可以看一下mongodb的例子:

    https://github.com/ccdjh/boxmongodb


    使用StringProperty() 这些是因为,
    1,我是通过def __new__(cls,**arg) 返回一个用于检测数据的列表,并且方便输入初始值
    2,可以接纳一些设定值
    ccdjh
        11
    ccdjh  
       2014-12-14 17:00:50 +08:00
    @messense

    谢谢。虽然只有一个文件,你也统统看完并且修改,这是对代码的一种认真认可。

    就像小学生作业一样,满篇红红的,搞的自己挺不好意思的哈。
    完整的安装文件你可以在这里获取:
    https://pypi.python.org/pypi/boxmongodb

    这本身就是一个demo文件,我并没有释放更新出来。而且有许多错误的地方。
    1,安装的时候出现依赖版本错误
    2,AuthProperty的__new__问题,值的更新
    3,ModelFilter的__new__废除,使用静态函数

    还有很多,包括使用到redis和sqlite等。。

    并没有贬性的意思。代码修改后,有运行过么?出错误了

    就像0 star一样,有人认真我都很开心了。
    但你应该使用后,提出使用问题,提出上面的错误,我会超兴奋和高兴。

    但你没有使用,但你没有提出bug,而是对我屎一样的代码风格提出纠正更改,我羞愧死了哈。

    谢谢!
    virusdefender
        12
    virusdefender  
       2014-12-15 00:21:34 +08:00   ❤️ 1
    kfll
        13
    kfll  
       2014-12-15 08:21:21 +08:00 via Android
    用实例变量的话,继承和覆盖不就显得麻烦了么…
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5596 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 01:36 · PVG 09:36 · LAX 17:36 · JFK 20:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.