《在路上 …》 写代码也需要一点演技 – python2.6 的 class decorator
写通用的回复类, 原本打算做成一个独立的基类
class ReplyBase(object):
?? ?_REPLY_REALTED_CLS = None ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?? ?_REPLY_CLS = None ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?? ?mc_reply_id_by_rid = McLimitA( ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?? ? ? ?"ReplyIdBy%sId:%%s"%_REPLY_RCLS.Meta.table.title(), ? ? ? ? ? ? ? ? ? ? ? ??
?? ? ? ?128 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?? ?)
?? ?...
写下来以后, 忽然想到 ? ? ? ?
"ReplyIdBy%sId:%%s"%_REPLY_RCLS.Meta.table.title(), ? ? ? ? ? ? ? ? ? ? ? ??
在基类定义的时候就被确定了, 不好搞
这样下去就只有用Meta Class
不过正如 洪教授 所言 ( http://www.infoq.com/cn/interviews/douban-hqn )
Meta Class 是种黑魔法, 正派人士都很畏惧它.
虽然有部YY小说, 标题叫做"魔本是道", 不过这也就是纯属意淫, 估计连本实体书都没有.
正如我昨天说过的 做人需要一点演技( http://www.douban.com/note/101804926/ )
写代码也不能太暴露内心的邪恶念头.
decorator, 正如其名, 装饰器, "装"是核心词, 是我圣教中人, 行走江湖必备的技能.?
好吧, 过去我常常以"张教主"自诩, 不过一晃也有很多年没进行官方的正式声明了.?
江湖儿女江湖老,昏昏灯火忆平生.
言归正传, 先来做一个小实验, 用函数动态添加一个基类
class C(object):
?? ?def x(self):
?? ? ? ?return self.__class__
class B(object):
?? ?pass
class A(B):
?? ?pass
def main():
?? ?print "A.__bases__ before", A.__bases__
?? ?A.__bases__ = tuple(list(A.__bases__)+[C, ])
?? ?print "A.__bases__ after", A.__bases__
?? ?print "A().x()", A().x()
输出是
A.__bases__ before (<class '__main__.B'>,)
A.__bases__ after (<class '__main__.B'>, <class '__main__.C'>)
A().x() <class '__main__.A'>
人体试验很成功, 我很开心
当然, 我这里有些细节懒得交代了, 我是工科生, 不是理科生, 我只追求可以work的solution, 不考究背后theory. 何况我本科文凭中还有"医学"两个字符.
医学是只看结果不问过程的.
不过, 如果你遇到什么问题, 可以从这里开始探索 http://blog.donews.com/limodou/archive/2005/01/06/227676.aspx
说了这么多, 还是直接上代码吧, 代码是很无趣. 就像武功秘籍一样.
找秘籍的人永远很多, 炼成的永远很少.
这还是精简演示版, 很多接口没做.
如果说Meta Class是基因改造, ?class decorator就像是整容手术了. 下面正式开工
=================================================
#!/usr/bin/env python
#coding:utf-8
from init_db import McModel, McCacheA, McCache, Model, mc, cursor_by_table, McLimitA
from const.man import STATE_DEL, STATE_APPLY, STATE_ACTIVE, STATE_BAN
class ReplyMixin(object):
?? ?def new_reply(self, man_id, txt, state=STATE_ACTIVE):
?? ? ? ?rid = self.id
?? ? ? ?self.reply_count += 1
?? ? ? ?self.save()
?? ? ? ?s = self._REPLY_CLS(rid=rid, man_id=man_id, state=state)
?? ? ? ?s.txt = txt
?? ? ? ?s.save()
?? ? ? ?self.mc_reply_id_by_rid.delete(rid)
?? ? ? ?return s
?? ?def reply_list(self, offset, limit):
?? ? ? ?return self._REPLY_CLS.mc_get_list(
?? ? ? ? ? ?self.reply_id_list(offset, limit)
?? ? ? ?)
def mixin_reply(reply_cls):
?? ?"""
@mixin_reply(XxxReply)
class Xxx(McModel):
?? ?pass
?? ?"""
?? ?def _(cls):
?? ? ? ?cls.__bases__ = tuple(list(cls.__bases__)+[ReplyMixin, ])
?? ? ? ?cls.mc_reply_id_by_rid = McLimitA(
?? ? ? ? ? ?"ReplyIdBy%sId#%%s"%cls.Meta.table.title(),
?? ? ? ? ? ?128
?? ? ? ?)
?? ? ? ?cls._REPLY_CLS = reply_cls
?? ? ? ?cls.reply_id_list = cls.mc_reply_id_by_rid("{self.id}")(
?? ? ? ? ? ?reply_id_list
?? ? ? ?)
?? ? ? ?return cls
?? ?return _
def reply_id_list(self, offset, limit):
?? ?c = self._REPLY_CLS.raw_sql(
?? ? ? ?"select id from " +
?? ? ? ?self._REPLY_CLS.Meta.table +
?? ? ? ?" where rid=%s and state>%s order by create_time limit %s offset %s",
?? ? ? ?self.id, STATE_APPLY, limit, offset
?? ?)
?? ?return [i for i, in c.fetchall()]
=============================
同时为了统一管理, 迁移原来的一些reply函数到新代码上, 但是保留原接口
=============================
--- mysite/model/review.py(revision 3071)
+++ mysite/model/review.py(working copy)
+from reply import mixin_reply
?
?
?class ReviewReply(McModel):
?? ? pass
?
+@mixin_reply(ReviewReply)
class Review(McModel):
?? ?txt = review_txt.property
?
?def review_reply_by_review_id(id, offset, limit):
- ? ?return ReviewReply.mc_get_list(
- ? ? ? ?review_reply_id_by_review_id(id, offset, limit)
+ ? ?return Review(id).reply_list(
+ ? ? ? ?offset, limit
?? ? )
?
?def review_reply_new(review_id, man_id, txt, state=STATE_ACTIVE):
?? ? r = Review.mc_get(review_id)
- ? ?if r:
- ? ? ? ?r.reply_count += 1
- ? ? ? ?r.save()
- ? ? ? ?s = ReviewReply(rid=review_id, man_id=man_id, state=state)
- ? ? ? ?s.txt = txt
- ? ? ? ?s.save()
- ? ? ? ?mc_review_reply_id_by_review_id.delete(s.id)
- ? ? ? ?return s
+ ? ?return r.new_reply(man_id,txt,state)