Python: 淺淡Python中的屬性(property),pythonproperty

來源:互聯網
上載者:User

Python: 淺淡Python中的屬性(property),pythonproperty

起源:
項目過程中需要研究youtube_dl這個開源組件,翻閱其中對類的使用,對比c#及Delphi中實現,感覺Python屬性機制挺有意思。
區別與進階程式設計語言之單一入口,在類之屬性這一方面,它隨意的太多,以致於習慣了進階語言的嚴謹,對如此隨意心裡倒是有些不安。
也難怪,因為其資料類型弱限制性,往往一個函數返回了一個結果,追溯此傳回值類型,有時需要費上許多工夫!
我不是隨意的人,但隨意起來我還真不是人,用在此處,頗為貼切:b

屬性,是對事物某種特性的抽象,物件導向編程中一個重要概念;區別於欄位,它通常表示為欄位的擴充,加以訪問與設定保護機制。
比如動物,它的顏色、重量,都可以說是它的屬性,此篇以一動物類來做例子,淺探其中屬性機制。

 

1、新式類和經典類(New-style classes)

Python 2.x預設類為經典類,而對屬性支援完全者為新式類,其區別請自行度娘。
Python 3.x預設即為新式類,不必顯式繼承於object類。
如下面代碼類之定義:

#此為經典類class AnimalClassic:    pass#此為新式類,Python 2.2始支援class Animal(object):    pass

雖一object差別,但其內在機制,改變頗多。略一窺之,大體如下:

>>>print dir(AnimalClassic) 

返回:

['__doc__', '__module__']

>>>print dir(Animal)

返回:

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

由此可知,其加入了諸多物件導向的支援;此節屬性知識,亦基於新式類構建。所以諸君用Python 2.x做開發,寫物件導向代碼時,切記要繼承於object類

 

2、隨意的屬性

通常,我們這樣定義屬性:

class Animal(object):    def __init__(self, name, age):        self.name = name        self.age = age

即在執行個體初始化時,__init__函數中賦值,其中值可為執行個體訪問:

a = Animal('black dog', 3)print 'Name:', a.nameprint 'Age:', a.agea.color = 'Black'print 'Color:', a.color

結果為:

Name: black dogAge: 3Color: Black

 

看到了吧?運行期,能動態為執行個體添加屬性,比如Color。但此方法所添加,只能作用於此執行個體,而無影響於類
怎麼限制它?用__slots__這個東西,比如,__slots__ = ['name', 'age'],則類只能添加這兩個屬性,蛋疼,不好用
如果想要在運行期給類添加屬性,要用到MethodType這東西,比如:

def set_color(self, color):    self.color = colorAnimal.set_color = MethodType(set_color, None, Animal)a1 = Animal('yellow dog', 3)a1.set_color('Yellow')print a1.color

……喔,有點淩亂,還是不好用!或者說,心裡沒譜兒。


3、@property

習慣了進階語言的嚴謹,總想對屬性加以存取控制,相對安全些,比如直接在__init__中定義公用屬性,從封裝性來說,它是不好的寫法。
屬性之訪問,它亦有機制,其一便是@propery關鍵字。用此關鍵字,其擷取、設定函數,須與屬性名稱一致。
@property可以把一個執行個體方法變成其同名屬性,以支援.號訪問,它亦可標記設定限制,加以規範,如下代碼:

class Animal(object):    def __init__(self, name, age):        self._name = name        self._age = age        self._color = 'Black'    @property    def name(self):        return self._name    @name.setter    def name(self, value):        if isinstance(value, basestring):            self._name = value        else:            self._name = 'No name'    @property    def age(self):        return self._age    @age.setter    def age(self, value):        if value > 0 and value < 100:            self._age = value        else:            self._age = 0            # print 'invalid age value.'    @property    def color(self):        return self._color    @color.setter    def color(self, value):        self._color = value;    a = Animal('black dog', 3)a.name = 'white dog'a.age = 300print 'Name:', a.nameprint 'Age:', a.age

這樣在設定值時候,總算有個判斷取捨,是不是好一些?
私人變數以_開頭,是種編碼約寫,當然也可以直接存取它。
不過既如此寫,直接存取是不推薦的。
若真要為私人變數,則加雙底線,比如__name,也一樣阻止不了訪問,但讓我們知道,它不想被直接用到,如下代碼:

class Animal(object):    def __init__(self, name):        self.__name = namea = Animal('black dog')print a._Animal__name

這種寫法當真好奇怪!
引廖雪峰言:總的來說就是,Python本身沒有任何機制阻止你幹壞事,一切全靠自覺。

 

4、property函數
它以一個函數形式,定義一個屬性,與@property實現原理類似,或者就是它的的變異用法。
其原型為:

property(fget=None, fset=None, fdel=None, doc=None)

譬如上面Animal類,其可用此改為:

class Animal(object):    def __init__(self, name, age):        self._name = name        self._age = age        self._color = 'Black'    def get_name(self):        return self._name    def set_name(self, value):        if isinstance(value, basestring):            self._name = value        else:            self._name = 'No name'    name = property(fget=get_name, fset=set_name, fdel=None, doc='name of an animal')    def get_age(self):        return self._age    def set_age(self, value):        if value > 0 and value < 100:            self._age = value        else:            self._age = 0            # print 'invalid age value.'    age = property(fget=get_age, fset=set_age, fdel=None, doc='name of an animal')    a = Animal('black dog', 3)a.name = 'white dog'a.age = 3print 'Name:', a.nameprint Animal.name.__doc__print 'Age:', a.age

其輸出結果一樣,看來只是寫法不同。

 

後記:
由此可見,Python作為一種解釋型語言,其簡單易用,但其隨意性也大。如此屬性篇,也只是闡述其中一點,其它方面須在使用中去學習留意。
習慣了文法嚴謹,編碼亦請以Pythonic的風格去編寫,python實在沒有多大限制,只要正確電腦都能夠編譯,代碼風格是給人看的,優雅總比零亂好。

如上面幾種屬性寫法,我尤其喜歡@property方式,相對簡潔一些

 

參考資料:

Built-in Functions
Python基礎:新式類的屬性訪問
Python深入03 對象的屬性

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.