Python如何实现property、classmethod和staticmethod

img.jpg

Python中面向对象编程涉及的:propertyclassmethodstaticmethod,通常会被认为它们是Python中的关键字,其实不然,它们都是通过装饰器(decorator)和描述器(descriptor)特性实现的特殊类,Python中的装饰器(decorator)与描述器(descriptor)。

@property的实现

property为例,以下通过roperty实现property的功能,通过property可以方便地为一个属性定义set和get方法

class roperty(object):

    # 装饰器类的语法和装饰器方法类似,
    # @roperty等价于roperty(...)
    # 入参体现在初始化方法中
    def __init__(self, func):
        self.__name__ = func.__name__
        self.getF = func
        self.setF = None
        pass

    def setter(self, func):
        self.setF = func
        return self

    def __set__(self, instance, value):
        self.setF(instance, value)
        pass

    def __get__(self, instance, owner):
        return self.getF(instance)

class A(object):
    
    # 利用roperty像property一样定义属性
    # 这里等价于name = roperty(name)
    # 利用装饰器语法,name被赋值为roperty的实例
    @roperty
    def name(self):
        print('get name1')
        return self.__name
        
    # 由于name被赋值为roperty的实例
    # 为了演示上的区分,方法名为name1,实际开发中用name即可
    # 以下等价于name1 = name.setter(name1)
    @name.setter
    def name1(self, n):
        print('set name')
        self.__name = n

a = A()

# 值得注意的是,经过装饰器语法后A.name已经是roperty对象(这里roperty对象既是一个装饰器又是一个描述器)
# 根据描述器的特性,a.name赋值会触发描述器的__set__方法,继而调用name属性定义的set方法
a.name = 'name1111'

# 根据描述器的特性,a.name读取会触发描述器的__get__方法,继而调用name属性定义的get方法
print(a.name)

property属于数据型描述器(data descriptor),同时也是一个以class定义装饰器。

class中函数的调用

通常来讲,class中支持定义实例方法、@classmethod修饰的类方法和@staticmethod修饰的静态方法,这几种方法的区别:

  • 普通方法:
    不需要修饰符,实例调用时自动传入第一个参数为实例,类调用时不自动传入第一个参数
  • 类方法:
    通过类或者实例调用时,自动传入第一个参数为类
  • 静态方法:
    通过类或者实例调用时,不自动传入第一个参数

普通方法的调用行为是Python的默认行为,类方法和静态方法的调用行为则是通过classmethodstaticmethod实现的。

@classmethod和@staticmethod的实现

以下通过classmethod1staticmethod1实现classmethodstaticmethod的功能

class classmethod1(object):

    def __init__(self, func):
        self.sf = func

    def __get__(self, instance, owner):
        return lambda *args, **kwargs: self.sf(owner, *args, **kwargs)

class staticmethod1(object):

    def __init__(self, func):
        self.sf = func

    def __get__(self, instance, owner):
        return lambda *args, **kwargs: self.sf(*args, **kwargs)

class A(object):

    def name(self):
        print('instance.name')

    @classmethod1
    def className(cls):
        print('{}.name'.format(cls))

    @staticmethod1
    def staticName(ipt):
        print('{}.name'.format(ipt))

a = A()
a.name()
A.className()
a.className()
A.staticName('static')
a.staticName('static')

>>> instance.name
>>> A.name
>>> A.name
>>> static.name
>>> static.name

你可能感兴趣的:(Python如何实现property、classmethod和staticmethod)