
img.jpg
Python中面向?qū)ο缶幊躺婕暗模?strong>property、classmethod、staticmethod,通常會被認(rèn)為它們是Python中的關(guān)鍵字,其實(shí)不然,它們都是通過裝飾器(decorator)和描述器(descriptor)特性實(shí)現(xiàn)的特殊類,Python中的裝飾器(decorator)與描述器(descriptor)。
@property的實(shí)現(xiàn)
以property為例,以下通過roperty實(shí)現(xiàn)property的功能,通過property可以方便地為一個(gè)屬性定義set和get方法
class roperty(object):
# 裝飾器類的語法和裝飾器方法類似,
# @roperty等價(jià)于roperty(...)
# 入?yún)Ⅲw現(xiàn)在初始化方法中
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一樣定義屬性
# 這里等價(jià)于name = roperty(name)
# 利用裝飾器語法,name被賦值為roperty的實(shí)例
@roperty
def name(self):
print('get name1')
return self.__name
# 由于name被賦值為roperty的實(shí)例
# 為了演示上的區(qū)分,方法名為name1,實(shí)際開發(fā)中用name即可
# 以下等價(jià)于name1 = name.setter(name1)
@name.setter
def name1(self, n):
print('set name')
self.__name = n
a = A()
# 值得注意的是,經(jīng)過裝飾器語法后A.name已經(jīng)是roperty對象(這里roperty對象既是一個(gè)裝飾器又是一個(gè)描述器)
# 根據(jù)描述器的特性,a.name賦值會觸發(fā)描述器的__set__方法,繼而調(diào)用name屬性定義的set方法
a.name = 'name1111'
# 根據(jù)描述器的特性,a.name讀取會觸發(fā)描述器的__get__方法,繼而調(diào)用name屬性定義的get方法
print(a.name)
property屬于數(shù)據(jù)型描述器(data descriptor),同時(shí)也是一個(gè)以class定義裝飾器。
class中函數(shù)的調(diào)用
通常來講,class中支持定義實(shí)例方法、@classmethod修飾的類方法和@staticmethod修飾的靜態(tài)方法,這幾種方法的區(qū)別:
- 普通方法:
不需要修飾符,實(shí)例調(diào)用時(shí)自動傳入第一個(gè)參數(shù)為實(shí)例,類調(diào)用時(shí)不自動傳入第一個(gè)參數(shù) - 類方法:
通過類或者實(shí)例調(diào)用時(shí),自動傳入第一個(gè)參數(shù)為類 - 靜態(tài)方法:
通過類或者實(shí)例調(diào)用時(shí),不自動傳入第一個(gè)參數(shù)
普通方法的調(diào)用行為是Python的默認(rèn)行為,類方法和靜態(tài)方法的調(diào)用行為則是通過classmethod和staticmethod實(shí)現(xiàn)的。
@classmethod和@staticmethod的實(shí)現(xiàn)
以下通過classmethod1和staticmethod1實(shí)現(xiàn)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