Classes of Python(Version 2.7.13)
全文主要內(nèi)容翻譯自
Python 2.7.13
的官方文檔,示例代碼及講解皆為本人撰寫裁奇,轉(zhuǎn)載請先聯(lián)系
A First Look at Classes
Classes introduce a little bit of new syntax, three new object types, and some new semantics
類引入了一些新的語法桐猬,三個新的對象類型,和一些新的語義刽肠。(下文一一講解)
Class Definition Syntax
class ClassName:
<statement-1>
.
.
.
<statement-N>
類的定義溃肪,就像函數(shù)定義(def
)一樣,必須在他們作用之前被執(zhí)行音五”棺可能會將函數(shù)
定義放入 if
分支中,這時候就要記住上一句話了躺涝。
if 1:
def f():
print "calling f()"
f() # calling f()
'''
# 這時候因為上面的 if 分支是肯定被執(zhí)行的
# f() 函數(shù)是被加到上下文的 namespaces中
'''
f() # calling f()
'''
# 可是如果 if 分支不一定執(zhí)行的時候呢厨钻? 比如肯定不執(zhí)行的 if 0:
# 這時候就會發(fā)生 `undefined name f` 錯誤了!
# 將定義放入分支的時候坚嗜,切記先讓函數(shù)定義被執(zhí)行之后夯膀,再引用
'''
Class Objects
Class
對象支持兩種操作:屬性引用、實例化惶傻。
屬性引用( Attribute references ) 用 obj.name
形式的語法棍郎,
在 class
被創(chuàng)建后,他命名空間內(nèi)的所有 name
都是有效的屬性 name
(即可以被 obj.name
引用到)银室。[靜態(tài)變量可以不創(chuàng)建 class
也能引用]
類實例化使用函數(shù)符號(foo()
)涂佃,假使 class
對象是一個無參函數(shù),返回值是
class
的新的實例蜈敢。
x = MyClass()
實例化操作創(chuàng)建了一個空對象辜荠,大多數(shù)時候我們希望自定義地創(chuàng)建一個實例,這個實例有
他特殊的初始狀態(tài)抓狭。例如伯病,新建一個 people
對象,我們希望他是個10歲的孩子,即
people.age
是10午笛,這是在創(chuàng)建好對象的時候就已經(jīng)初始化的狀態(tài)惭蟋。因此我們定義了
一個特殊的方法 __init__
,
def __init__(self):
self.age = 10
當(dāng)一個 class
(類) 定義了 __init__()
方法药磺,類的實例化操作會自動調(diào)用該方法
去實例化新的類實例告组。當(dāng)然,為了更好的靈活性癌佩,__init__()
方法可以有參數(shù)木缝。這樣我們可以在創(chuàng)建 people
的時候就顯式的初始化他的年紀。
class People:
def __init__(self,age=1):
self.age = age
baby = People() # default age is 1
young = People(20) # age 20
old = People(60) # age 60
靜態(tài)變量和實例變量
class Clazz:
static_var = 0
def __init__(self):
self.i = 1
def f():
print "f()"
# 靜態(tài)變量可以不用創(chuàng)建對象也能引用围辙,所有實例共享同一個變量
print Clazz.static_var # 0
# 實例化 class
c = Clazz()
# Attribute references 屬性引用
print c.i # 1
print c.f
print c.f() # f()
Instance Objects
實例對象(instance objects) 只接受 屬性引用(attribute references) 操作我碟。
這有兩種有效的屬性名( attribute names ),數(shù)據(jù)屬性和方法(data attributes and methods)姚建。
數(shù)據(jù)屬性對應(yīng)著 Smalltalk
中的“實例變量”矫俺,以及 C++
中的“數(shù)據(jù)成員”。數(shù)據(jù)屬性不需要被直接聲明掸冤;就像 local variables
(局域變量)恳守,在她們第一次被賦值的時候就開始存在了。
class Clazz:
def foo():
print "foo()"
c = Clazz()
'''
# 可以發(fā)現(xiàn)贩虾,在實例對象中引用一個不存在的變量并賦值催烘,該變量就存在在實力對象中了
# 而不需要在定義的時候顯式的聲明該變量
# 這里我們也可以給變量賦值一個函數(shù)對象(function object)
'''
c.i = 1 # i = 1
'''
# 刪除實例中的數(shù)據(jù)屬性
'''
del c.i
另一種實例屬性引用是 方法(method)。方法是一個屬于對象的函數(shù)( A method is a function that “belongs to” an object.)缎罢。(在 Python
中伊群,(術(shù)語)方法并不是只有類實例才有:其他對象類型也可以有方法。比如說策精,list
對象有很多方法叫做 append
,insert
,remove
之類的舰始。不過,在下面的討論中咽袜,我們只用(術(shù)語)方法表示類實例對象的方法丸卷,除非另有明確聲明)
一個實例對象中有效的函數(shù)名取決于他的類。在定義中询刹,一個類中定義的所有函數(shù)對象屬性對應(yīng)著類實例的方法谜嫉。(類中的 functions
對應(yīng)著 實例中的 methods
)。這段有點繞凹联,看不懂的看原文
Method Objects
這里只講兩點吧:
- 第一點:
class Clazz:
def f(self):
print 'Hello World'
c = Clazz()
c.f() # Hello World
# right way
# reusable
cf = c.f
cf() # Hello World
- 第二點:
我們看到了在定義方法 f(self)
的時候傳入了一個參數(shù) self
沐兰,而在調(diào)用的時候 c.f()
并沒有傳入任何參數(shù)。這里我們實際上調(diào)用方法的時候是追尋到類定義的方法蔽挠。在我們的例子中住闯,c.f()
和 Clazz.f(x)
是完全等價的。
# 接上一點的 Clazz
Clazz.f(c) # Hello World
Class and Instance Variables
通常來說,實例變量(instance variables
)是為了保持每個實例的數(shù)據(jù)唯一性比原,而類變量(class variables
)是為了在所有類的實例之間共享屬性(attributes
)和方法(method
)插佛。
class Dog:
kind = 'canine' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind # shared by all dogs
'canine'
>>> e.kind # shared by all dogs
'canine'
>>> d.name # unique to d
'Fido'
>>> e.name # unique to e
'Buddy'
'''
既然 class variables 作為共享的數(shù)據(jù)源,
任何一個實例更改了變量值量窘,全部實例都會"看到"
'''
d.king = 'Dtime'
print e.kind # Dtime
Random Remarks
如果名稱一樣的話朗涩,數(shù)據(jù)屬性會覆蓋( override ) 方法屬性;為了避免偶然發(fā)生的绑改、在大型程序中難以發(fā)現(xiàn)的命名沖突,用一些公約(慣例)來最小化沖突發(fā)生的可能是非常明智的兄一。
Data attributes may be referenced by methods as well as by ordinary users (“clients”) of an object. In other words, classes are not usable to implement pure abstract data types. In fact, nothing in Python makes it possible to enforce data hiding — it is all based upon convention. (On the other hand, the Python implementation, written in C, can completely hide implementation details and control access to an object if necessary; this can be used by extensions to Python written in C.)
沒有嚴格地定義函數(shù)定義必須要在類定義中function
厘线,也可以將函數(shù)賦值給類中的一個局部變量。(不建議這么使用)
# Function defined outside the class
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
方法可以通過 self
的方法屬性調(diào)用其他方法:
class Bag:
def __init__(self):
self.data = []
def add(self, x):
self.data.append(x)
def addtwice(self, x):
self.add(x)
self.add(x)
Methods may reference global names in the same way as ordinary functions. The global scope associated with a method is the module containing its definition. (A class is never used as a global scope.) While one rarely encounters a good reason for using global data in a method, there are many legitimate uses of the global scope: for one thing, functions and modules imported into the global scope can be used by methods, as well as functions and classes defined in it. Usually, the class containing the method is itself defined in this global scope, and in the next section we’ll find some good reasons why a method would want to reference its own class.[這部分我也蒙圈... 不大清楚說啥出革,以后再來填吧]
每個值都是一個對象造壮,因此有一個類(也成為他的類型)。他存儲為 object.__class__
骂束。
Inheritance
派生類的定義語法如下:
class DerivedClassName(BaseClassName):
<statement ...>
父類 BaseClassName
必須定義在包含派生類 DerivedClassName
的作用域中耳璧。也可以使用其他任意表達式代替基類名稱。比如展箱,當(dāng)基類定義在其他模塊中時:
class DerivedClassName(modulename.BaseClassName):
父類和派生類名詞解釋
基類: 下面的程序中旨枯,Base
就是基類,也稱父類混驰。
派生類: Derive
繼承了 Base
類攀隔,他就是 Base
類的派生類,也稱 Base
類的子類栖榨。
class Base:
pass # 定義一個空類
class Derive(Base):
pass
派生類定義的執(zhí)行與基類的執(zhí)行相同。當(dāng)類對象被構(gòu)造(創(chuàng)建)時,基類被記住(remembered)启绰。這用于解析屬性引用:如果在類中找不到請求的屬性爱谁,則搜索繼續(xù)查找基類。如果基類本身是從某個其他類派生的愚争,則此規(guī)則將遞歸應(yīng)用映皆。
對派生類的實例化沒有什么特別的:DerivedClassName()創(chuàng)建一個新的類實例。方法引用解析如下:如果需要轰枝,搜索相應(yīng)的類屬性劫扒,如果有必要,則降序排列基類鏈狸膏,如果這產(chǎn)生一個函數(shù)對象沟饥,方法引用是有效的。
'''
可以發(fā)現(xiàn) Derive 類打印了 num 屬性,但是 Derive 類并沒有定義 num 屬性贤旷,
所以這時候在解析屬性的時候广料,會去父類 Base 類中尋找,這就是根據(jù)降序排列基類鏈去搜索屬性幼驶。
'''
class Base:
num = 10
class Derive(Base):
def p(self):
print self.num
派生類可以覆蓋其基類的方法艾杏。因為方法在調(diào)用同一對象的其他方法時沒有特殊的權(quán)限,
所以一個基類中的方法再調(diào)用定義在同個基類中其他方法的時候盅藻,最終可能會調(diào)用派生類的同名方法來覆蓋它购桑。(對于C ++程序員:Python中的所有方法都是虛擬的。)
派生類中的重寫方法實際上可能希望擴展而不是簡單地替換同名的基類方法氏淑。有一種簡單的方法來直接調(diào)用基類方法:只需調(diào)用 BaseClassName.methodname(self勃蜘,arguments)
。這有時對客戶有用假残。 (請注意缭贡,這只有在基類可以作為 BaseClassName
在全局范圍內(nèi)訪問時才有效。)
Python有兩個內(nèi)置的函數(shù)作用在繼承上:
- 使用
isinstance()
來檢查實例的類型:isinstance(obj,int)
將只有當(dāng)obj .__ class__
是int
或從int
派生的類時才為True
辉懒。 - 使用
issubclass()
檢查類繼承:issubclass(bool阳惹,int)
是True
,因為bool
是int
的子類眶俩。但是莹汤,issubclass(unicode,str)
是False
颠印,因為unicode
不是str
的子類(它們只共享一個共同的祖先体啰,basestring
)。
Multiple Inheritance
Python也支持有限形式的多重繼承嗽仪。具有多個基類的類定義如下所示:
class DerivedClassName(Base1, Base2, Base3):
<statement ...>
對于舊式(old-style)類荒勇,唯一的規(guī)則是深度優(yōu)先,從左到右闻坚。因此沽翔,如果在 DerivedClassName
中找不到屬性,則在 Base1
中搜索窿凤,然后(遞歸地)在 Base1
的基類中搜索仅偎,并且僅當(dāng)在那里找不到時,才會在 Base2
中搜索雳殊,以此類推橘沥。
對于新式(new-style)類, 方法解析順序(MRO
)會動態(tài)更改,以支持對 super()
的協(xié)作調(diào)用夯秃。這種方法在一些其他多繼承語言中稱為 call-next-method
座咆,比單繼承語言中的 super
調(diào)用更強大痢艺。[多重繼承下的方法解析不了解,谷歌了一下 Python 的多重繼承
介陶,新式類的方法解析順序]
'''
以 object 作為基類堤舒,這就是新式(new-style)類。
因為 Base 類是以 object 為基類哺呜,所以 Derive 類也是新式類了舌缤。
'''
class Base(object):
pass
class Derive(Base):
pass
'''
# Python3 之后就默認的是新式類了,不需要專門的去繼承 object 了某残。
# 這篇例子是講新式類的繼承順序
# Python 3.5
'''
class A:
def __new__(cls, *argv, **kwargs):
print('nA')
return super().__new__(cls)
def __init__(self, a):
print('A')
self.a = a
def comeon(self):
print('A.comeon')
class B(A):
def __new__(cls, *argv, **kwargs):
print('nB')
return super().__new__(cls)
def __init__(self, b):
super().__init__(b)
print('B')
self.b = b
def comeon(self):
print('B.comeon')
class C(A):
def __new__(cls, *argv, **kwargs):
print('nC')
return super().__new__(cls)
def __init__(self, c):
super().__init__(c)
print('C')
self.c = c
def comeon(self):
print('C.comeon')
class D(B, C):
def __new__(cls, *argv, **kwargs):
print('nD')
return super().__new__(cls)
def __init__(self, d):
super().__init__(d)
print('D')
self.d = d
d = D('d')
d.comeon()
'''
# output
nD
nB
nC
nA
A
C
B
D
B.comeon
'''
最后執(zhí)行 d.comeon()
實際上調(diào)用的方法是從左自右得來的左邊的那個 B 的 comeon()
方法 国撵。那么如何實現(xiàn)這樣的效果呢?很簡單玻墅,讓 B 的 __init__()
最后一個執(zhí)行介牙,就能覆蓋掉 C 和 D 寫入的 comeon()
方法。
所以實際調(diào)用new的順序就是 D--B--C--A椭豫,之后遞歸棧回過頭來初始化旨指,調(diào)用 __init__()
的順序就是 A--C--B--D赏酥,只有這樣才能保證 B 里的 comeon()
方法能夠覆蓋掉 A 和 C 創(chuàng)建的 comeon()
方法,同樣保證如果你的 D 里有 comeon()
谆构,它是最后一個被初始化的裸扶,將最后寫入而覆蓋掉其它的。
栗子來源于偶然看見的 Coldwings 的知乎回答搬素。不過很明顯這里是講的新式類的呵晨,舊式類與此不同(參上)。
Private Variables and Class-local References
除了在對象內(nèi)部不能訪問的“私有”實例變量在Python中不存在熬尺。然而摸屠,大多數(shù) Python code
遵守著這樣一個約定:如果前綴為一個下劃線(比如 "_attr
")的命名,應(yīng)該被當(dāng)作是 API
的非公有部分(不論它是一個函數(shù)粱哼,方法亦或是數(shù)據(jù)成員)季二。 它應(yīng)被視為細節(jié)的實現(xiàn),如有更改揭措,恕不另行通知胯舷。
(It should be considered an implementation detail and subject to change without notice.
)
class Base:
class_var = 1 # 可以被子類 "看到"
__private_var = 0 # 不可以被子類 '看到',這就是Python實現(xiàn)私有(private) 變量的方式
class Derive(Base):
def p(self):
print self.class_var
print self.__private_var
# instantiation
Derive().p()
# output:
1
Traceback (most recent call last):
File "D:/workspace_py/python-doc/classdefinition/demonstrate.py", line 10, in <module>
Derive().p()
File "D:/workspace_py/python-doc/classdefinition/demonstrate.py", line 8, in p
print self.__private_var
AttributeError: Derive instance has no attribute '_Derive__private_var'
因為類私有(class-private
)成員有一個有效的用例(即避免名稱與子類定義的名稱沖突)绊含,所以對這種機制的有限的支持桑嘶,稱為名稱調(diào)整(name mangling
)。任何標識符 __spam
(至少兩個前導(dǎo)下劃線躬充,最多一個尾部下劃線)在文本上替換為 _classname__spam
逃顶,其中 classname
是帶有前導(dǎo)下劃線的當(dāng)前類名讨便。這種調(diào)整是在不考慮標識符的句法位置的情況下完成的,只要它出現(xiàn)在類的定義內(nèi)即可口蝠。
名稱調(diào)整(name mangling
)有助于讓子類重寫方法器钟,而不會打斷類內(nèi)方法調(diào)用。例如:
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
注意妙蔗,傳遞給 exec
傲霸,eval()
或 execfile()
的代碼不會將調(diào)用類的類名視為當(dāng)前類;這類似于全局語句global statement
的效果,其效果同樣限于字節(jié)編譯在一起的代碼眉反。同樣的限制適用于 getattr()
昙啄,setattr()
和 delattr()
,以及直接引用 __dict__
時寸五。 [持續(xù)懵逼... 沒用過 exec
之類的梳凛,不知道咋回事,以后用過再來補]
Odds and Ends
有時梳杏,使用類似于 Pascal的"record"或C的"struct"
的數(shù)據(jù)類型韧拒,捆綁幾個命名的數(shù)據(jù)項,這樣的結(jié)構(gòu)是有用的十性。一個空類定義可以很好的做到這點:
class People:
pass
me = People() # create an empty class People
me.name = "Chan"
me.age = 16
me.weight = 1000
一段需要特定抽象數(shù)據(jù)類型的 Python
代碼叛溢,通常可以通過一個類來模擬該數(shù)據(jù)類型的方法劲适。例如楷掉,如果你有一個函數(shù)來格式化一個文件對象的一些數(shù)據(jù),你可以定義一個類方法 read()
和 readline()
從字符串緩沖區(qū)獲取數(shù)據(jù)霞势,并傳遞它作為參數(shù)烹植。
實例方法對象也有屬性:m.im_self
是擁有方法m()
的實例對象,m.im_func
是對應(yīng)于方法的函數(shù)對象愕贡。
class Clazz:
def f(self):
pass
c = Clazz()
print c.f.im_self # <__main__.Clazz instance at 0x0000000002915BC8>
print c.f.im_func # <function f at 0x0000000002A9E9E8>
Exceptions Are Classes Too
我們還可以使用類來標識 (創(chuàng)建) 用戶定義的異常( exception
)草雕。用這種機制的話,在擴展異常的層次結(jié)構(gòu)上將更加便捷固以。 raise
語句添加了兩種有效的語義形式:
raise Class, instance
raise instance
第一種形式促绵,instance
必須是 Class
的或者是 Class
的派生類的實例。
第二種形式是一個簡寫形式嘴纺,實際上是這樣的:
raise instance.__class__, instance
在 except
子句( clause
)中败晴,捕捉的異常類會兼容其派生類,也就是說一個捕捉類似 IOException
的基類栽渴,所有的繼承自 IOException
的派生類都會被捕捉到尖坤。
舉個栗子:
class B:
pass
class C(B):
pass
class D(C):
pass
for c in [B, C, D]:
try:
raise c()
except D:
print "D"
except C:
print "C"
except B:
print "B"
'''
# output
> B
> C
> D
'''
如果將上面代碼中的 except
子句的順序改變?yōu)?BCD 的順序,會發(fā)現(xiàn)輸出是 "BBB" 闲擦,因為 except B
把其所有的派生類都給捕捉了慢味。
如果出現(xiàn)了沒有處理的異常场梆,會打印錯誤信息,格式是這樣子的:
異常類名纯路,后跟一個冒號再一個空格或油,最后跟上用內(nèi)建方法 `str()` 將實例轉(zhuǎn)換成字符串輸出
__main__.B: <__main__.B instance at 0x00000000024EB0C8>
Iterators
你可能已經(jīng)發(fā)現(xiàn)大多數(shù)容器對象可以使用 for
語句來循環(huán)了。
for element in [1, 2, 3]:
print element
for element in (1, 2, 3):
print element
for key in {'one':1, 'two':2}:
print key
for char in "123":
print char
for line in open("myfile.txt"):
print line,
這種操作方式非常的清晰明確且便捷驰唬,統(tǒng)一使用迭代器的操作方式已經(jīng)滲入 Python顶岸。在這便捷之下,for
語句調(diào)用了 iter()
方法作用在容器對象上叫编。該函數(shù)返回了一個迭代器對象辖佣,在迭代器對象內(nèi)定義了 next()
方法,next()
方法一次一個地訪問容器中的元素搓逾。當(dāng)沒有了可訪問元素時卷谈, next()
方法拋出了一個 StopIteration
異常,這個異常會終止 for
循環(huán)霞篡。這有一個栗子世蔗,展示這是怎么工作的:
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> it.next()
'a'
>>> it.next()
'b'
>>> it.next()
'c'
>>> it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
it.next()
StopIteration
在看完了迭代器協(xié)議背后的機制后,可以開始將迭代器行為到你的類中了朗兵。定義一個 __iter__()
方法污淋,該方法返回一個有 next()
方法的對象。如果類中定義了 next()
方法的話矛市,可以在 __iter__()
方法中直接返回 self
诲祸。
class Dict:
"""fool dict"""
def __init__(self, key, data):
self.key = key
self.data = data
self.index = -1
def __iter__(self):
return self
def next(self):
self.index += 1
if self.index > len(self.key)-1:
raise StopIteration
return self.key[self.index],self.data[self.index]
def add(self,add_key,add_data):
self.key.append(add_key)
self.data.append(add_data)
key = [0,1,2,3]
data = ['a','b','c','d']
d = Dict(key,data)
d.add(7,'g')
for key,data in d:
print key,data
'''
# output
0 a
1 b
2 c
3 d
7 g
'''
Generators
生成器是一個用于生成迭代器的簡單且強大的工具。它寫起來就和常規(guī)的函數(shù)一樣找田,但每當(dāng)需要返回數(shù)據(jù)的時候,會使用 yield
語句着憨。每次next()
方法被調(diào)用墩衙,生成器會回到上次它處理過的地方(它會記住所有的數(shù)據(jù)值以及上次執(zhí)行的語句)甲抖。創(chuàng)建一個生成器非常簡單,看下面的栗子:
def access(data):
for index in range(len(data)):
yield data[index]
for char in access('access'):
print char;
'''
# output
a
c
c
e
s
s
'''
所有能被生成器做到的事情准谚,都可以用基于類的迭代器來完成(就在上一節(jié)提到的迭代器)挫剑。生成器會自動生成 __iter()__
和 next()
方法,這使得生成器看起來異常的緊湊(和基于類的迭代器相比)樊破。
另一個重要的特性是,局部變量以及執(zhí)行狀態(tài)在每次調(diào)用之間都被自動的保存了哲戚。與使用實例變量 (如 self.key
和 self.data
) 相比顺少,使得函數(shù)變得更易編寫,且更加清楚祈纯。
除了自動創(chuàng)建方法和保存程序狀態(tài),當(dāng)生成器終止時粒没,它們自動拋出 StopIteration
簇爆。結(jié)合起來,這些特性使得創(chuàng)建迭代器和編寫常規(guī)函數(shù)一樣容易响蓉。
Generator Expressions
一些簡單的生成器可以簡潔地編碼為表達式哨毁,使用類似于列表推導(dǎo)的語法,但使用括號而不是方括號想幻。這些表達式設(shè)計用于生成器立即被封閉它的函數(shù)使用的情況话浇。
與完整的生成器定義相比,生成器表達式更緊湊幔崖,但特性也少了赏寇。生成器表達式比等效的列表推導(dǎo)更內(nèi)存友好。
上栗子:
>>> sum(i*i for i in range(10)) # sum of squares
285
>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec)) # dot product
260
>>> from math import pi, sin
>>> sine_table = dict((x, sin(x*pi/180)) for x in range(0, 91))
>>> unique_words = set(word for line in page for word in line.split())
>>> valedictorian = max((student.gpa, student.name) for student in graduates)
>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1,-1,-1))
['f', 'l', 'o', 'g']
===========日志分割線===========
update log:
- 更新于 2017年1月19日01:03:16 | 添加
Coldwings
的關(guān)于新式類繼承的栗子 - 初次完成于 2017年1月18日19:04:44 | 全篇翻譯完畢
- 更新于 2017年1月18日16:55:08 | 添加
Exceptions Are Classes Too
至文末 - 更新于 2017年1月5日 21:34:00 | 添加
Inheritance
至文末 - 更新于 2017年1月4日 23:00:36 | 添加
Class and Instance Variables
- 創(chuàng)建于 2017年1月4日 16:26:36