如何讓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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章