img.jpg
Python中面向对象编程涉及的:property、classmethod、staticmethod,通常会被认为它们是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的默认行为,类方法和静态方法的调用行为则是通过classmethod
和staticmethod
实现的。
@classmethod和@staticmethod的实现
以下通过classmethod1
和staticmethod1
实现classmethod
和staticmethod
的功能
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