如何让classmethod只允许使用用类对象来调用

原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

你可能感兴趣的:(Python)