原blog链接:如何让classmethod只允许使用用类对象来调用
我们知道在python中使用classmethod可以把一个方法处理为类方法,这样就可以直接使用类对象来调用它了。但是,它也有一个不算问题的问题,就是也可以使用实例来调用,比如:
class A(object):
@classmethod
def p(cls):
print 'call p()'
a = A()
A.p()
a.p()
但是有时,我们可能希望这个方法只能被类对象来调用,而不能使用实例来调用。为什么会有这样的需求?举一个例子,数据库操作中,Model有delete()和remove()方法。其中delete()是用在实例上的,删除一个记录,而remove()是定义为classmethod的,删除整个表的所有记录。但是有时在实例上误写为record.remove(),这样的结果是会将表全部删除,而不是只删除这一条记录。所以这里remove()具有一定的危险性。所以我想有这么一种限制,即类方法只能用类对象来调用。当然,并不是所有的类方法都需要这样,只对有破坏性或危险性的方法这样处理。那么怎么做呢?可以通过写了一个descriptor的类,可以干这件事,同时它可以像classmethod一样作为decorator来使用。代码如下:
class classonlymethod(object):
"""
Use to limit the class method can only be called via class object, but not instance
object
>>> class A(object):
... @classonlymethod
... def p(cls):
... print 'call p()'
>>> A.p()
call p()
>>> a = A()
>>> try:
... a.p()
... except Exception as e:
... print e
Method p can only be called with class object
"""
def __init__(self, func):
self._func = func
def __get__(self, model_instance, model_class):
if model_instance is not None:
raise AttributeError("This method can only be called with class object.")
return super(classonlymethod, self).__get__(model_instance, model_class)
它使用了descriptor的特性,能过定义 __get__ 方法来区分类对象调用还是实例对象调用。
关于descriptor,可以参考:http://docs.python.org/2/howto/descriptor.html