大概刚学python的时候就知道了classmethod和staticmethod的用法,后来看到描述器才知道描述器与他们之间千丝万缕的关系,是否能动手实现下这俩货嘞?这边先从bound和unbound method说起
bound unbound
看下面的例子
class Cla():
    def __init__(self,a):
        self.a = a
    def f(self):
        print self,self.a
        
print Cla.f
# <unbound method Cla.f>
print Cla(1).f
# <bound method Cla.f of <__main__.Cla instance at 0x103f3fb00>>
这个非常好理解,bound指的是是否和具体实例绑定,我们知道,调用实例的方法,第一个参数是self,需要给第一个参数传入一个对象。
print Cla(1).f()
print Cla.f()
print Cla.f(Cla(2))
第一个和第三个能成功执行,第二个会报错。报错为unbound method f() must be called with Cla instance as first argument (got nothing instead)
原因如下:
Cla.f 相当于Cla.__dict__['f'].__get__(None,Cla),返回的是unbound method
Cla(1).f 相当于Cla.__dict__['f'].__get__(Cla(1),Cla),返回的是bound method
两者都会返回一个函数,不同的是,bound method会把Cla(1)绑定到f的第一个参数上,但是unbound method不会,不过可以传入一个参数(这个参数必须是Cla的实例)
大致相当于下面,但并不准确,只是大概实现。需要注意的是,下边全部都是新式类,经典类会表现的不太一样。(不太想研究经典类这种过时的东西了…)
class UnboundMethod(object):
    def __init__(self, f, own):
        self.f = f
        self.own = own
    def __call__(self, *args, **kwargs):
        return self.f(*args, **kwargs)
    def __str__(self):
        return '<unbound method %s.%s>' % (self.own.__name__, self.f.__name__)
class BoundMethod(object):
    def __init__(self, f, obj, own):
        self.f = f
        self.obj = obj
        self.own = own
    def __call__(self, *args, **kwargs):
        return self.f(self.obj, *args, **kwargs)
    def __str__(self):
        return '<bound method %s.%s of %s>' % (self.own.__name__, self.f.__name__, self.obj)
class instance_method():
    def __init__(self, function):
        self.function = function
    def __get__(self, instance, owner):
        if instance:
            return BoundMethod(self.function, instance, owner)
        else:
            return UnboundMethod(self.function, owner)
staticmethod classmethod
已经理解了上面的bound和unbound的描述器实现,那么staticmethod和classmethod就很好理解了
class my_classmethod(object):
    def __get__(self, obj, type=None):
        return partial(self.f, type)
    def __init__(self, f):
        self.f = f
class my_staticmethod(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, instance, owner):
        return self.f