python裡的屬性和方法
關於本書
解釋新式類pythond物件的物件屬性訪問機制:
- 函式如何變成方法
- properties和描述符的工作機制
- 確定方法解析順序
新式意味著了Python2.2及以上版本幷包括了3.x。在這些版本中已經有一些行為上的變化但這裡介紹的所有概念都是有效的。
內容索引
在你開始前
1.新屬性訪問
建立描述符
兩種描述符
屬性搜尋的總結
2.方法解析順序
“誰是下一個”列表
一個超級解法
計算MRO
3.用法說明
特殊方法
子類化內建型別
相關文件
圖片索引
2.1.四邊形圖
2.2.一個簡單的層級
2.3.繩珠模型-未解決
2.4.繩珠模型-已解決
2.5.多種解法
示例索引
1.1.簡單屬性訪問
1.3.一個簡單的描述符
1.4.使用描述符
1.5.無資料描述符
1.6.隱藏一個方法
1.7.內建描述符
1.8.更多關於properties
2.3.建立一個“誰是下一個”索引
2.4.呼叫下一個方法技巧
2.5.一個super技巧
2.6.配合一個類方法來使用super
2.7.其他的super技巧
3.1.只在type上有用的特殊方法
3.2.把特殊方法用在例項上
3.3.子類化<type 'list'>
3.4.為了優化而使用__slots__
3.5.自定義子類的建立
在你開始前
值得你注意的一些事情:
- 本文覆蓋了新式物件(早在python2.2.中就已出現)。所有例子都能在python2.5到python3.x中使用
- 本文不是為完全初學者寫的. 而是針對已經對Python有所瞭解 (稍稍瞭解即可) 並希望對它瞭解更多的人.
Happy pythoneering!
第一節1.新屬性訪問
動態__dict__
屬性是什麼?很簡單,一個屬性是從一個物件中獲得另一個物件的方式。使用全能的點—objectname.attributename—瞧!你現在有另一個物件的控制代碼了。你也可以創造一個屬性,通過賦值:objectname.attributename = notherobject。
但是,訪問屬性會返回什麼樣的物件?物件在哪裡被設定成為一個屬性?之後本章節將會回答這些的問題。
例1.1.簡單屬性訪問
>>> class C(object):
... classattr = "attr on class"1
...
>>> cobj = C()
>>> cobj.instattr = "attr oninstance" 2
>>>
>>> cobj.instattr 3
'attr on instance'
>>> cobj.classattr 4
'attr on class'
>>> C.__dict__['classattr'] 5
'attr on class'
>>> cobj.__dict__['instattr'] 6
'attr on instance'
>>>
>>> cobj.__dict__ 7
{'instattr': 'attr on instance'}
>>> C.__dict__ 8
{'classattr': 'attr on class', '__module__':'__main__', '__doc__': None}
1 |
可以再類中設定屬性。 |
2 |
亦或是在類的例項上 |
3,4 |
類和例項的屬性都可以通過例項來訪問 |
5,6 |
屬性實際上被儲存在物件的一個類似字典的 __dict__ 中。 |
7,8 |
__dict__ 只儲存那些使用者提供的屬性。 |
OK,我承認‘使用者提供的屬性’是我的自創詞,但是我認為這樣說有助於瞭解究竟發生了什麼。該注意到的是,__dict__本身就是個屬性。我們並沒有設定它,但是Python提供了。我們的老朋友__class__和__bases__(它們都沒出現在__dict__裡)看起來也是類似。讓我們把它們稱作Python提供的屬性(Python-provided)。一個屬性是Python提供的與否取決於物件所處的問題。
然而,我們更在意的是使用者定義的屬性。這些是由使用者提供的屬性,並且它們常常出現在其被設定在的物件的__dict__裡(並不總是)。
當被訪問時(比如print objectname.attributename),python將會按照順序搜尋以下物件的屬性:
1. 該物件自身(objectname.__dict__或者是objectname的任何Python提供的屬性)
2. 物件的型別(objectname.__class__.__dict__)。觀察到只有__dict__被搜尋了,這意味著只有類裡使用者提供的屬性。換句話說,objectname.__bases__ 可能不會返回任何東西即使objectname.__class__.__bases__存在。
3. 物件的類的基類,基類的基類,諸如此類。(每個objectname.__class__.__bases__的__dict__屬性)。多餘一個基類並不會讓Python覺得困擾,我們現在也暫時不關心。該注意到的是所有基類都會被搜尋直到找到相應屬性。
如果沒找到對應的屬性,Python會丟擲一個AttributeError異常。在對一個物件的屬性訪問所進行的查詢時不會搜尋其型別的型別(objectname.__class__.__class__)(比如例子中的objectname)
內建方法dir()返回由該物件所有屬性組成的一個列表。需要更多的檢查物件(inspectobject)可以檢視標準庫的inspect module。
上一部分解釋了所有物件的一般機制。即使對類(比如訪問classname.attrname)來說,有一個小小的改變:類的基類在類的類之前被訪問(也就是classname.__class__,對大部分型別來說結果是 <type 'type'>)。
一些物件,比如內建型別和它們的例項(列表,元組等)沒有__dict__。這也使得使用者提供型別不適用於它們。
我們還沒結束哦!這只是全篇的一個簡述。當設定和獲得一個屬性的時候還會發生更多的事情。這在之後的章節會做介紹。
從函式到方法
繼續我們的Python實驗:
Example 1.2. Afunction is more
>>> class C(object):
... classattr = "attr on class"
... def f(self):
... return "function f"
...
>>> C.__dict__ 1
{'classattr': 'attr on class', '__module__':'__main__',
'__doc__': None, 'f': <function f at0x008F6B70>}
>>> cobj = C()
>>> cobj.classattr isC.__dict__['classattr']2
True
>>> cobj.f is C.__dict__['f'] 3
False
>>> cobj.f 4
<bound method C.f of <__main__.Cinstance at 0x008F9850>>
>>> C.__dict__['f'].__get__(cobj, C)5
<bound method C.f of <__main__.Cinstance at 0x008F9850>>
1 |
訪問該字串的確和預期一樣從類的 __dict__中獲得了它。 |
2 |
但是函式卻不是如此,為什麼? |
3 |
嗯,它看起來是一個不一樣的物件。 (一個繫結方法是一個可呼叫物件,這個物件呼叫一個函式(例子中的C.f ),該函式傳遞一個例項作為第一引數並傳遞了它被呼叫的所有引數。這就是方法的生成機制。) |
4 |
劇透—這就是Python在建立繫結方法時做的事情。當為例項查詢一個屬性時,如果Python用類的 __dict__中的__get__() 方法找到一個物件,而不是返回一個物件,它就會呼叫__get__() 方法並返回結果。注意到__get__() 方法被呼叫時將例項和類分別作為第一引數和第二引數。 |
由於 __get__()方法的存在才將一個普通函式轉變成了一個繫結方法。一個函式物件並沒有什麼特殊的。任何人都能成功地將一些物件和一個__get__()方法放入類的__dict__。這種物件被稱為描述符,並且有很大的用處。(It is only the presence of the__get__()method that transforms an ordinary function into a bound method. There is nothing really special about afunction object. Anyone can put objects with a__get__()method inside the class__dict__and get away with it. Such objects are called descriptors and have many uses.)
建立描述符
所有帶有一個__get__()方法的物件,和可選擇的__set__()和__delete__()方法,接受特定的引數都被稱作遵循描述符協議。一個這樣的物件就是一個描述符並且能被放置在一個類的__dict__來在一個屬性被獲得、設定或者刪除時完成特定的事情。下面是一個空描述符。
例 1.3.一個簡單的描述符
class Desc(object):
"A descriptor example that just demonstrates the protocol"
def__get__(self, obj, cls=None):1
pass
def__set__(self, obj, val): 2
pass
def__delete__(self, obj): 3
pass
1 |
當一個屬性被讀取的時候會被呼叫。這裡 obj是被訪問屬性所在的物件(也許是None,當這個屬性在類層面上被直接訪問時,比如print classname.attrname)。另外cls是物件的類(當訪問類本身的時候就是類。這樣的話,obj是空)。 |
2 |
當在例項上設定屬性時被呼叫(比如objectname.attrname = 12)。這裡obj是正在被設定屬性的物件,而val是被當做值傳入的物件。 |
3 |
當屬性從一個例項中被刪除時呼叫(比如del objectname.attrname)。這裡obj是屬性正在被刪除的物件。 |
我們上面定義的是一個能被初始化來建立一個描述符的類。現在讓我們看看我們如何建立一個描述符,將這個描述符繫結到一個類並且讓它工作。
例 1.4.使用描述符
class C(object):
"A class with a single descriptor"
d =Desc() 1
cobj = C()
x = cobj.d 2
cobj.d = "setting a value" 3
cobj.__dict__['d'] = "try to force avalue"4
x = cobj.d 5
del cobj.d 6
x = C.d 7
C.d = "setting a value on class" 8
1 |
現在叫做d的屬性就是一個描述符了。(這裡用到了前個例子的Desc 。) |
2 |
呼叫 d.__get__(cobj, C)。返回值繫結到了x上。這裡d意味著中定義的Desc的例項。它可以在 C.__dict__['d']被找到。 |
3 |
呼叫d.__set__(cobj, "setting a value") |
4 |
直接通過給例項的__dict__賦值不會報錯,但是... |
5 |
這是沒意義的。這裡仍然呼叫了d.__get__(cobj, C). |
6 |
呼叫 d.__delete__(cobj). |
7 |
呼叫 d.__get__(None, C). |
8 |
並沒有呼叫任何東西。這裡用一個新的字串物件替換了描述符。之後訪問cobj.d 或者 C.d將會返回字串"setting a value on class"。描述符已經從C的__dict__中被踢出去了。 |
注意到當從類本身訪問時,只涉及到了__get__()方法,設定屬性或者刪除屬性將會被替換或者移除描述符。
只有當賦給類後描述符才會工作。將一個描述符賦給一個不是類的物件是無效的。
兩種描述符
在上一節中我們使用一個帶有__get__()和__set__()方法的描述符。順便這樣的描述符被稱為資料描述符(data descriptors)。只帶有__get__()方法的描述符的作用要弱於其表親,這類描述符被稱為無資料描述符(non-datadescriptors)。
例 1.5. 無資料描述符
class GetonlyDesc(object):
"Another useless descriptor"
def__get__(self, obj, typ=None):
pass
class C(object):
"A class with a single descriptor"
d =GetonlyDesc()
cobj = C()
x = cobj.d 1
cobj.d = "setting a value" 2
x = cobj.d 3
del cobj.d 4
x = C.d 5
C.d = "setting a value on class" 6
1 |
呼叫 d.__get__(cobj, C) (和之前的一樣). |
2 |
把 "setting a value" 放到例項自身裡 (準確來說是 cobj.__dict__). |
3 |
Surprise! 現在返回了 "setting a value", 這是從 cobj.__dict__裡面取出的. 回憶下對於一個數據描述符來說例項的__dict__被忽略了。 |
4 |
將屬性 d 從例項中刪除 (準確來說是 cobj.__dict__)。 |
5,6 |
這些作用等同於資料描述符。 |
有趣的是,沒有__set__()方法不僅僅影響屬性設定,也影響了獲取。Python在想什麼?如果在設定上,描述符被“解僱”並把資料被放在某處,那麼它應該遵從描述符只知道如何獲取。為什麼還打擾例項的 __dict__?
資料描述符對於一個屬性的完全操作是十分有用的。這正是當我們對於能夠儲存資料的屬性所期望的。比如一個屬性在設定時被轉換並儲存了,常常可以在讀取的時候被逆轉並返回。當你有一個數據描述符,它控制所有在例項上訪問屬性的許可權。當然,你仍然可以直接到類中去替換描述符,的那是你不能在一個類的例項上做這種事情。
無資料描述符則相反,只在例項本身沒有值的時候提供一個值。所以在例項上設定屬性會隱藏描述符。這一點在函式上是很有用的,因為這樣我們就能通過將函式附加給一個例項而達到在類中隱藏一個函式的定義。
例1.6. 隱藏一個方法
class C(object):
def f(self):
return "f defined in class"
cobj = C()
cobj.f() 1
def another_f():
return "another f"
cobj.f = another_f
cobj.f() 2
1 |
通過 f.__get__(cobj, C)呼叫繫結方法。實際上最終呼叫 C.__dict__['f'](cobj)。 |
2 |
呼叫 another_f()。C中函式 f()的定義被隱藏. |
屬性搜尋的總結
這是屬性訪問這篇故事的長版本,為了完整起見而寫。
當從物件中獲取一個屬性時(print objectname.attrname),Python執行以下流程:
1. 如果attrname對於objectname來說是一個特殊的屬性(i.e. Python-provided),則返回它。
2. 在objectname.__class__.__dict__查詢attrname。如果存在並且是一個數據描述符,返回描述符的結果。對於所有objectname.__class__的基類也做同樣的事情。
3. 在objectname.__dict__中查詢attrname,如果找到則返回它。如果objectname是一個類,則也查詢其全部基類。如果他是一個類並且有它或者它的基類有一個描述符,返回描述符的結果。
4. 在objectname.__class__.__dict__中檢查attrname。如果它存在並且是一個非資料描述符,返回描述符的結果。如果其存在並且不是一個描述符,直接返回它。如果它存在並且是一個數據描述符,我們不應該在這裡而應該返回到2.中進行相應操作。對objectname.__class__所有的基類做同樣的搜尋。
5. 丟擲AttributeError異常
值得注意的是Python首先在類中(及其基類中)檢查一個數據描述符,然後再檢查這個物件的__dict__中是否存在該屬性,然後才是在類(及其基類中)查詢一個非資料描述符。即上面的2,3和4。
上面的描述符結果意味著用適當的引數呼叫描述符中的__get__()方法。當然,檢查attrname的__dict__意味著檢查__dict__["attrname"]是否存在。
現在,當設定一個使用者定義的屬性是Python做了以下的事情:
1. 在objectname.__class__.__dict__中查詢attrname。如果存在並且是一個描述符協議,使用描述符來設定這個值。對objectname.__class__的所有基類也做相同的操作。
2. 對objectname.__dict__中鍵"attrname"插入值something。
3. 簡單多了不是麼!
當設定一個python提供的屬性時所發生的事情取決於被設定的屬性。Python甚至可能根本不允許某些屬性被設定。所有屬性的刪除和上面類似。
Descriptors In The Box
當你急於去“市場”弄到你自己的昂貴的描述符前,請注意Python已經在box中提供了一些十分有用的描述符。
例 1.7. Built-indescriptors內建描述符
class HidesA(object):
defget_a(self):
return self.b - 1
defset_a(self, val):
self.b = val + 1
defdel_a(self):
del self.b
a =property(get_a, set_a, del_a, "docstring")1
defcls_method(cls):
return "You called class %s" % cls
clsMethod = classmethod(cls_method) 2
defstc_method():
return "Unbindable!"
stcMethod = staticmethod(stc_method)3
1 |
一個property 提供了一個簡單的方法來呼叫函式用來隨時地在例項上獲取、設定或者刪除一個屬性。當從類中獲取到屬性後,不會呼叫getter方法而是返回property物件本身。文件字串也可以提供作為 HidesA.a.__doc__訪問。 |
2 |
一個classmethod 類似於一個普通的方法,把類(不是例項)作為第一引數傳入到函式裡。其他引數則正常傳入。它能在類層面上被直接呼叫並且也作為類方法運作。第一個引數被命名為cls而不是傳統的self來避免混淆其真正指代的意義。 |
3 |
一個staticmethod 類似於定義在類之外的函式。它絕不會被繫結,這意味著不論你怎麼訪問它(不論是在類還是在例項上),它都會被你傳入的引數所呼叫。它沒有內建的第一引數。 |
正如我們早先所見的那樣,Python函式也是描述符!他們不是早期Python中的描述符(因為那些版本中根本沒有描述符),但現在他們能很好地符合一個更通用的機制。
一個property始終是一個數據描述符,但是當定義的時候並不要求傳入所有引數。
例 1.8. 更多關於properties
class VariousProperties(object):
defget_p(self):
pass
defset_p(self, val):
pass
defdel_p(self):
pass
allOk = property(get_p, set_p, del_p) 1
unDeletable = property(get_p, set_p)2
readOnly = property(get_p) 3
1 |
可以被設定,獲取和刪除。 |
2 |
嘗試在例項上刪除這個屬性會丟擲一個 AttributeError異常。 |
3 |
嘗試在例項上設定或者刪除這個屬性會丟擲一個 AttributeError異常。 |
getter和setter函式不能在類本身中被定義,可以使用任何函式。在任何情況下,這些函式將會被在呼叫把例項作為第一引數。注意到上面例子中函式們被傳遞到property構造器的地方,它們都不是繫結函式。
另一個十分有用地結論是:注意到子類化這個類並重載了getter(或者是setter)函式並不會改變property。property物件始終堅持實際被提供的函式們。當被剔除時,它會說“嘿,我始終堅持這個被傳給我的函式,我只會呼叫它並返回響應結果。”,而不是“嗯,讓我看看現在的類中叫做'get_a'的方法然後使用它”。如果某個人想這麼做,那就得重新定義一個有效的描述符。它為什麼會成功?我們說它是通過一個字串(也就是說方法要呼叫的名字)來完成初始化的。啟用後,它在類層面上為方法名執行一個getattr(),然後使用找到的方法。很簡單!
類方法和靜態方法(Classmethods and staticmethods)是非資料描述符,因此當一個相同名字的屬性在例項層面上被直接設定的時候會被隱藏。如果你使用自己的描述符(而不是使用property),你可以通過傳入一個__set__()方法並在方法內部丟擲一個AttributeError異常來設定其為只讀。這正是property在沒有一個setter函式時的工作方式。
章節 2. 方法解析順序問題 (方法解析混亂)
我們為什麼需要方法解析順序?因為:
1. 我們樂於面向物件程式設計和建立一個類層次結構。
2. 一般的實現do_your_stuff()方法的技巧是在基類上呼叫do_your_stuff(),然後再開始著手我們的事情。
例 2.1. 一般的基類呼叫技巧(Usual base calltechnique)
class A(object):
defdo_your_stuff(self):
# do stuff with self for A
return
class B(A):
defdo_your_stuff(self):
A.do_your_stuff(self)
# do stuff with self for B
return
class C(A):
defdo_your_stuff(self):
A.do_your_stuff(self)
# do stuff with self for C
return
3. 我們從兩個類中子類化出一個新類,這樣能通過兩種路徑訪問相同的超類。
例2.2.一般的基類呼叫技巧失敗了( Base call technique fails)
class D(B,C):
defdo_your_stuff(self):
B.do_your_stuff(self)
C.do_your_stuff(self)
# do stuff with self for D
return
圖 2.1. 四邊形圖
4. 現在當我們想要執行do_your_stuff()時遇到困難了。使用我們平常的技術,如果我們想要呼叫B和C,我們就會重複呼叫A.do_your_stuff()。眾所周知當A只應該被執行一次時卻讓它執行兩次是很危險的。而其他的辦法則會讓B或者C的任務不會被執行,這也不是我們想要的。
對這個問題有一個混亂的解決辦法和一個乾淨的解決辦法。顯然Python應該執行乾淨的那個,接下來讓我們看看應該怎麼做。
“誰是下一個”列表
讓我們說:
1. 對每個類,我們安排所有的超類到一個有序不重複的列表中,並且把這個類本身放入列表的頭部。我們把這個列表放入一個類裡叫做next_class_list的屬性中以便稍後使用。
例2.3. 建立一個“誰是下一個”索引
B.next_class_list = [B,A]
C.next_class_list = [C,A]
D.next_class_list = [D,B,C,A]
2. 我們使用一個與上面不同的技巧來執行我們類裡的do_your_stuff()
例 2.4. 呼叫下一個方法技巧
class B(A):
defdo_your_stuff(self):
next_class = self.find_out_whos_next()
next_class.do_your_stuff(self)
# do stuff with self for B
deffind_out_whos_next(self):
l = self.next_class_list # l depends on the actual instance
mypos = l.index(B) 1 # Find this class in the list
return l[mypos+1] # Return the next one
有意思的是我們如何執行find_out_whos_next(),這取決於我們正在處理的例項。注意到:
· 取決於我們是否傳入了一個例項D或者B,上面的next_class將會決定是或C者A。
· 我們得先為每個類都執行find_out_whos_next(),因為它必須把類名硬編碼到裡面去(參照上面的1)。我們不能在這裡用self.__class__。如果我們在D的例項上呼叫了do_your_stuff(),並且這個呼叫正在穿越層級,之後self.__class__將會變為這裡的D。
使用這個技巧,每個方法都被呼叫一次。這看起來很乾淨,但是工作量太大了。幸運的是,我們不用給每個類都執行一次find_out_whos_next()或者設定next_class_list,因為Python會為我們完成這些工作。
一個超級解法
Python為每個類都提供了一個類方法__mro__,和一個叫super的型別。__mro__屬性是包含了這個類自身和其所有超類的一個不重複的有序元組,其順序是可以預測的。一個super物件起到了find_out_whos_next()上面方法的作用。
例 2.5. One super technique一個超級解法
class B(A): 1
defdo_your_stuff(self):
super(B, self).do_your_stuff()2
# do stuff with self for B
2 |
呼叫 super() 時建立了一個super物件。它在self.__class__.__mro__中找到B 的下一個類。在super物件上訪問的屬性會在下一個類中被搜尋並返回。描述符被解析了(Descriptors are resolved)。這意味著訪問一個方法(比如上面)返回一個繫結方法(注意到super(B, self).do_your_stuff()呼叫並沒傳遞self引數)。當使用super()時第一引數應始終是相同的,它是正在被使用的類(1)。 |
如果我們正在使用一個類方法,我們不用傳遞例項self到super呼叫裡。從上面的例子中可以看出,super使用self只是為了達到self.__class__.__mro__。因此這個類本身可以被直接傳遞給super,正如下面所演示的:
例2.6.配合一個類方法來使用super
class A(object):
@classmethod 1
defsay_hello(cls):
print 'A says hello'
class B(A):
@classmethod
defsay_hello(cls):
super(B, cls).say_hello()2
print 'B says hello'
class C(A):
@classmethod
defsay_hello(cls):
super(C, cls).say_hello()
print 'C says hello'
class D(B, C):
@classmethod
defsay_hello(cls):
super(D, cls).say_hello()
print 'D says hello'
B.say_hello() 3
D.say_hello() 4
1 |
這是一個使用類方法的例子 (而非例項方法)。 |
2 |
注意到我們傳入super()的是cls (是類而不是例項) 。 |
3 |
這裡會輸出: A says hello |
4 |
這裡會輸出 (注意到每個方法只被呼叫了一次): A says hello |
然而還有另一種使用super的方法:
例 2.7. Another super technique其他的super技巧
class B(A):
defdo_your_stuff(self):
self.__super.do_your_stuff()
# do stuff with self for B
B._B__super = super(B) 1
當只用一個型別建立的時候,super例項則表現的像一個描述符。這意味著(當d是D的例項時)super(B).__get__(d)能和super(B,d)一樣返回相同的結果。
在上面的1中,我們munge屬性名稱,類似於Python對類內由雙下劃線的名字所做的事情。。所以這樣就像self.__super是在類的內部一樣變成可訪問的了。如果我們不使用一個類特定的屬性名,通過例項self訪問這個屬性則可能會返回子類中定義的一個物件。
當使用super我們通常只在一個方法內用一個super呼叫即使這個類有多個基類。另外,使用super而不是直接呼叫一個基類,是個很好的程式設計習慣。
當do_your_stuff()為C和A接受不同的引數時可能會出現一個圈套。這是因為當我們在B中使用super來在下一個類的層面上呼叫do_your_stuff(),我們不知道它會在A還是C上呼叫。如果這個方案是不可避免的,那我們就需要特別的解決方案了。
計算MRO
一個還沒被回答的問題是Python如何決定一個型別的__mro__?本章節將會介紹這個演算法背後的基本的思路。如果你只是想使用super,或者閱讀之後的章節的話,你可以跳過這個章節。Python利用使用者指定的兩種條件來決定型別們的優先順序:
1. 如果A是B的子類,那麼B的優先順序高於A。或者說B應該在所有__mro__(A和B都在裡面)裡都比A先出現。簡而言之讓我們先把這個記為B > A。
2. 在一個類宣告的基類列表中,如果C出現在D之前(比如class Z(C,D):),那麼C > D。
另外,為了避免產生歧義,Python遵守以下原則:
3. 在一個情況下如果E > F(或者一個__mro__裡),那麼在任何情況下E > F(或者所有__mro__裡)。
如果我們為每一個新的類C都建立我們介紹的__mro__,那我們就滿足了上面的條件,比如:
1. C的所有超類都出現在C.__mro__(還有C本身,在起始位置),並且
2. 對於C.__bases__中的每個B來說,C.__mro__裡的型別優先順序並不會和B.__mro__裡的優先順序起衝突
在這裡我們把上面的問題變成一個遊戲。考慮一個類的層級如下:
圖 2.2.一個簡單的層級
import types
class Dog(object):
__slots__ = ("name", "color", "info")
#定義__slots__
#coding=utf8
'''
複數是由一個實數和一個虛數組合構成,表示為:x+yj
一個負數時一對有序浮點數(x,y),其中x是實數部分,y是虛數部分。
Python語言中有關負數的概念:
1、虛
關於本書
解釋新式類pythond物件的物件屬性訪問機制:
函式如何變成方法properties和描述符的工作機制確定方法解析順序新式意味著了Python2.2及以上版本幷包括了3.x。在這些版本中已經有一些行為上的變化但這裡介紹的所有概念都是有效的。
內容索引
在你開始 python一、類的屬性總結(類的屬性定義在方法外,對象的屬性定義在方法內)理解:類的(靜態)屬性:(人類的五官,理解為變量)類的(動態)方法:(人類吃穿住行,理解為一個函數,至少帶一個參數self,指向類本身)對象:類的實例化,之後才能有屬性和方法1)類的屬性,也是公有屬性;類的私有屬性2)對象的公有屬性; bject order 直接 rsyslogd cep com except pri and python的文件處理和相關輸入輸出能力。介紹文件對象(它的內建函數,內建方法和屬性),標準文件,同時討論文件系統的訪問方法,文件執行,以及相關文件模塊。
一、內建函數open Python一、給實例對象綁定屬性和方法:1、給實例綁定屬性:先定義一個Student類
#!/usr/bin/python
class Student(object):
pass
然後綁定屬性:
s = Student()
s.name = ‘AAA‘ # 動態給實例綁定一個屬性
print( confirm 報錯 方式 系列 dep 是個 應用 all icm 屬性:
公有屬性 (屬於類,每個類一份)
普通屬性 (屬於對象,每個對象一份)
私有屬性 (屬於對象,跟普通屬性相似,只是不能通過對象直接訪問)
方法:(按作用)
構造方法
for roc -- don 操作 windows main 周期 僵屍 一、開啟進程的兩種方式
方式一:
from multiprocessing import Processimport timedef task(name): print(‘%s is run class Person():
Country='CN'
def __init__(self,nm)
self.nm=nm
動態新增例項屬性及例項方法:
p=Person()
p.age=18 #直接賦值,動態新增例項屬性
def set_age(self,age) #定義帶se
import types
如果一個類已經寫好 要想動態的新增一新的方法 那麼需要用下面方法:
p1.eat = types.MethodType(eat,p1) //即把eat函式動態繫結到了p1物件上
類屬性和類方法
目標
類的結構
類屬性和例項屬性
類方法和靜態方法
01. 類的結構
1.1 術語 —— 例項
使用面相物件開發,第 1 步 是設計 類
使用 類名() 建立物件,建立物件 的動作有兩步:
在記憶 1.面向物件介紹
類和物件:是面向物件中兩個重要概念
類:是物件對事物的抽象,比如人類\球類
物件:是類的一個例項,比如足球\籃球
例項說明:
球類可以對球的特徵和行為進行抽象,然後可以例項化一個真實的球體出來
為什麼面向物件?
面向物件的主要思想是
封裝
一、新增物件屬性:
>>> class student(object):
pass
>>> stu=student()
>>> stu.name="zhang jie" #新增物件屬性
>>> stu.name
'zh
類的屬性
類屬性(公有屬性) 類的私有屬性 物件的公有屬性 物件的私有屬性 內建屬性 函式的區域性變數 全域性變數
#!/usr/bin/python
# -*- coding:utf-8 -*-
class MyClass(object):
var1 = '類屬性,類的公有
今天遇到一個Python內部類中如何訪問外部類的屬性和方法的問題,在網上查了一下,推薦以下兩種:
1. 傳入外部類的例項
#傳遞外部類的例項
class OuterClassA(object):
def __init__(self):
sel
私有屬性和私有方法 應用場景及定義方式 應用場景 在實際開發中,物件的某些屬性或方法可能只希望在物件的內部使用,而不希望在外部被訪問到 私有屬性 就是 物件 不希望公開的 屬性 私有方法 就是 方法 不希望公開的 方法 定義方法 在定義屬性或方法時,在屬性名或者方法名前增加兩個下劃線,定義的
類是一個特殊的物件 Python中一切皆物件 class AAA: 定義的類屬性屬於類物件 obj1 =AAA: 屬於例項物件 在執行程式時,類 同樣會被載入到記憶體 在python中,類 是一個特殊的物件–類物件 在程式執行時,類物件(模板) 在記憶體中之有一份,使用一個類(模板)可以創建 一、動態語言相關概念
1.1 動態語言
在執行時程式碼可以根據某些條件改變自身結構
可以在執行時引進新的函式、物件、甚至程式碼,可以刪除已有的函式等其他結構上的變化
常見的動態語言:Object-C、C#、JavaScript、PHP、Python、Erlang
1.2 動態型別語言
在執行期間檢查資料
# -*- coding: utf-8 -*-
# @File : 類的例項動態增加屬性和方法.py
# @Date : 2018-05-31
# @Author : Peng Shiy
一. 類的私有變數和私有方法
1》 在python 中可以通過在屬性變數名前,加上雙下劃線定義屬性為私有屬性
2》特殊變數命名
a. _xx 以單下劃線開頭的表示的是protected(受保護的) 型別的變數,即保護型別只能靠允許其本身與子類進行訪問。若內部 相關推薦
Python 類屬性和方法
Python複數屬性和方法操作例項
python裡的屬性和方法
python—類的屬性和方法總結
Python 學習之文件對象的屬性和方法簡介
Python的實例定屬性和方法或類綁定方法
python學習筆記8--面向對象--屬性和方法詳解
python全棧脫產第34天------開啟進程的兩種方式、join方法、進程對象其他相關的屬性和方法、僵屍進程、孤兒進程、守護進程、互斥鎖
Python-動態新增屬性和方法
python的動態新增屬性和方法
Python 類屬性和類方法
Python中面向對向介紹及類的屬性和方法
python基礎之動態新增屬性和方法
python自動化運維學習第十四天--類的屬性和方法總結
Python內部類中如何訪問外部類中的屬性和方法
python - 私有屬性和私有方法
python - 類屬性和類方法
我的Python學習筆記(四):動態新增屬性和方法
Python程式設計:類的例項動態增加屬性和方法
python 私有屬性和私有方法