Python中用Descriptor實(shí)現(xiàn)類級(jí)屬性(Property)詳解
上篇文章簡(jiǎn)單介紹了python中描述器(Descriptor)的概念和使用,有心的同學(xué)估計(jì)已經(jīng)Get√了該技能。本篇文章通過一個(gè)Descriptor的使用場(chǎng)景再次給出一個(gè)案例,讓不了解情況的同學(xué)可以更容易理解。
先說說decorator
這兩個(gè)單詞確實(shí)是有些相似,同時(shí)在使用中也是形影不離。這也給人造成了理解上的困難,說裝飾器和描述器到底是怎么回事,為什么非得用一個(gè)@符號(hào)再加上描述器才行。
很多文章也都把這倆結(jié)合著講,我自己看完之后都會(huì)覺得很繞。其實(shí)學(xué)習(xí)一個(gè)知識(shí)點(diǎn),和做項(xiàng)目開發(fā)一個(gè)功能是一樣的。在功能拆分的時(shí)候我們都會(huì)盡量的把任務(wù)拆分的足夠小,然后才分配到開發(fā)者頭上。這樣保證各個(gè)任務(wù)的獨(dú)立性,完整性,并且易于做進(jìn)度管理。在任務(wù)開發(fā)的時(shí)候也不能把你的任務(wù)都放到一個(gè)函數(shù)/接口中去做,以避免各功能間產(chǎn)生高耦合的狀況,導(dǎo)致后期難以維護(hù)。
再說回到學(xué)習(xí)一個(gè)技術(shù)點(diǎn),如果你總是嘗試一下子就要掌握兩個(gè)或多個(gè)技術(shù)點(diǎn),結(jié)果可能是忙活了半天,發(fā)現(xiàn)還是暈頭轉(zhuǎn)向。
擦,好像扯遠(yuǎn)了。
說Descriptor是Descriptor, Decorator是Decorator,遇到不懂的地方,各個(gè)擊破,哪里不懂點(diǎn)哪里。所以先說Decorator, 關(guān)鍵點(diǎn)是你要意識(shí)到這就是一個(gè)語法糖 。所謂語法糖就是讓你可以用簡(jiǎn)單的方式寫代碼。本質(zhì)上裝飾器(Decorator)就是這樣:
def decorator(func):
def wrapper():
print 'in decorator'
func()
return wrapper
def func():
print 'in func'
# 把func裝飾一下
func = decorator(func) # 左邊的func其實(shí)是那個(gè)wrapper, 你執(zhí)行它的時(shí)候會(huì),它會(huì)幫你執(zhí)行func()
# 等同于你在定義func的時(shí)候加上@
@decorator
def func():
print 'in func'
正題:通過Descriptor來做一個(gè)類級(jí)的Property
常見的Property是這樣的:
class Foo(object):
_name = 'the5fire'
@property
def name(self):
return self._name
這中property的使用,是實(shí)例級(jí)的應(yīng)用。因?yàn)橹挥性?foo = Foo() 之后,才可以 foo.name 。
但是如果我需要一個(gè)類級(jí)的屬性應(yīng)該怎么做呢,就像是 classmethod一樣,不需要實(shí)例化類我就可以調(diào)用。對(duì)應(yīng)的需求是這樣的,定義了一個(gè)基類DBManage:
class DBManage(object):
@classmethod
def table_name(cls):
return cls.__name__.lower()
@classmethod
def select_all(cls):
sql = "SELECT * FROM %s""" % cls.table_name()
# 執(zhí)行這個(gè)語句的代碼
return result
這其實(shí)一個(gè)對(duì)應(yīng)著數(shù)據(jù)庫中某張表的基礎(chǔ)模型,我希望其他的Model都來繼承它,然后可以重用這個(gè)table_name的方法(目前還是方法)。
我只需要這么定義User模型即可:
class User(DBManage):
pass
然后這么定義Post模型:
class Post(DBManage):
pass
這樣我如果需要查所有的User數(shù)據(jù),只需要 User.select_all() 即可,同理Post也是如此 Post.select_all() 。但此時(shí)發(fā)現(xiàn)一個(gè)有點(diǎn)不爽的事情。那就是基類中的 cls.table_name() 這個(gè)代碼,table_name看起來就是屬性,卻需要用調(diào)用方法的方式獲取。不妥。
于是自定義了一個(gè)classproperty:
class classproperty(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, klass):
return self.func(klass)
這需要這樣,我在DBManage中的代碼就可以改為:
class DBManage(object):
@classproperty
def table_name(cls):
return cls.__name__.lower()
@classmethod
def select_all(cls):
sql = "SELECT * FROM %s""" % cls.table_name # 多么直觀
這就是Descriptor另外的一個(gè)使用案例了。
可能有人或有一個(gè)小疑問:為毛你不是在sql賦值時(shí)直接 sql = "SELECT * FROM %s" % cls.__name__.lower() 。這個(gè)問題,問的非常好,原因就一個(gè)字:懶。懶得以后每次都得敲那么多代碼。
相關(guān)文章
Python數(shù)據(jù)結(jié)構(gòu)dict常用操作代碼實(shí)例
這篇文章主要介紹了Python數(shù)據(jù)結(jié)構(gòu)dict常用操作代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03超詳細(xì),教你用python語言實(shí)現(xiàn)QQ機(jī)器人制作教程
這篇文章主要介紹了如何python語言實(shí)現(xiàn)QQ機(jī)器人,用圖文詳細(xì)的描述了其中的操作步驟,非常的簡(jiǎn)單易上手,有需要的朋友可以參考下2021-08-08Keras中的兩種模型:Sequential和Model用法
這篇文章主要介紹了Keras中的兩種模型:Sequential和Model用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06用Python selenium實(shí)現(xiàn)淘寶搶單機(jī)器人
今天給大家?guī)淼氖顷P(guān)于Python實(shí)戰(zhàn)的相關(guān)知識(shí),文章圍繞著用Python selenium實(shí)現(xiàn)淘寶搶單機(jī)器人展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06