在OOP程序設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Superclass)。
>>> class Animal(object):#名為Animal的class
defrun(self):
多態
a = list() # a是list類型
b = Animal() # b是Animal類型
c = Dog() # c是Dog類型
>>> isinstance(a, list)
True
在繼承關系中,如果一個實例的數據類型是某個子類,那它的數據類型也可以被看做是父類。但是,反過來就不行:
>>> b = Animal()
>>> isinstance(b, Dog)
False
繼承可以把父類的所有功能都直接拿過來,這樣就不必重零做起,子類只需要新增自己特有的方法,也可以把父類不適合的方法覆蓋重寫;有了繼承,才能有多態。在調用類實例方法的時候,盡量把變量視作父類類型,這樣,所有子類類型都可以正常被接收;
判斷對象類型,使用type()函數:
>>> type(123)#基本類型都可以用type()判斷
<type 'int'>
>>> type('str')
<type 'str'>
>>> type(None)
<type 'NoneType'>
>>> type(abs)#變量指向函數或者類,也可以用type()判斷
<type 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
>>> type(123)==type(456)#比較兩個變量的type類型是否相同
True
>>> import types#Python把每種type類型都定義好了常量,放在types模塊里
>>> type('abc')==types.StringType
True
>>> type(u'abc')==types.UnicodeType
True
>>> type([])==types.ListType
True
>>> type(str)==types.TypeType
True
>>> type(int)==type(str)==types.TypeType#特殊的類型
True
isinstance()可以告訴我們,一個對象是否是某種類型。他判斷的是一個對象是否是該類型本身,或者位于該類型的父繼承鏈上。
>>> isinstance(d, Dog) and isinstance(d,Animal)
True
>>> isinstance('a', str)
True#能用type()判斷的基本類型也可以用isinstance()判斷
>>> isinstance('a', (str, unicode))
True# 判斷一個變量是否是某些類型中的一種
>>> isinstance(u'a', basestring)
True#str和unicode都是從basestring繼承下來的
>>> dir('ABC')#獲得一個str對象的所有屬性和方法
['__add__', '__class__', '__contains__','__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__','__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__','__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__','__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__','__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split','_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode','endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha','isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower','lstr
類似__xxx__的屬性和方法在Python中都是有特殊用途的,比如__len__方法返回長度。在Python中,如果你調用len()函數試圖獲取一個對象的長度,實際上,在len()函數內部,它自動去調用該對象的__len__()方法,所以,下面的代碼是等價的:
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
我們自己寫的類,如果也想用len(myObj)的話,就自己寫一個__len__()方法:
>>> class MyObject(object):
def__len__(self):
return 100
>>> obj = MyObject()
>>> len(obj)
100
配合getattr()、setattr()以及hasattr(),我們可以直接操作一個對象的狀態:
class MyObject(object):
def__init__(self):
self.x = 9
defpower(self):
return self.x * self.x
>>> hasattr(obj, 'x') # 有屬性'x'嗎?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
False
>>> setattr(obj, 'y', 19) # 設置一個屬性'y'
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
True
>>> getattr(obj, 'y') # 獲取屬性'y'
19
>>> obj.y # 獲取屬性'y'
19
>>> getattr(obj, 'z', 404) # 獲取屬性'z',如果不存在,返回默認值404
404
>>> hasattr(obj, 'power') # 有屬性'power'嗎?
True
>>> getattr(obj, 'power') # 獲取屬性'power'
<bound method MyObject.power of<__main__.MyObject object at 0x108ca35d0>>
>>> fn = getattr(obj, 'power') # 獲取屬性'power'并賦值到變量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of<__main__.MyObject object at 0x108ca35d0>>
>>> fn() # 調用fn()與調用obj.power()是一樣的
81
>>> class Student(object):
pass
>>> s = Student()
>>> s.name = 'Michael' # 動態給實例綁定一個屬性
>>> print s.name
Michael
>>> def set_age(self, age): # 定義一個函數作為實例方法
self.age = age
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s,Student) # 給實例綁定一個方法
>>> s.set_age(25) # 調用實例方法
>>> s.age # 測試結果
25
但是,給一個實例綁定的方法,對另一個實例是不起作用的:
>>> s2 = Student() # 創建新的實例
>>> s2.set_age(25) # 嘗試調用方法
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute'set_age'
為了給所有實例都綁定方法,可以給class綁定方法:
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = MethodType(set_score,None, Student)
給class綁定方法后,所有實例均可調用:
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99
為了達到限制的目的,Python允許在定義class的時候,定義一個特殊的__slots__變量,來限制該class能添加的屬性:
>>> class Student(object):
__slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱
>>> s = Student() # 創建新的實例
>>> s.name = 'Michael' # 綁定屬性'name'
>>> s.age = 25 # 綁定屬性'age'
>>> s.score = 99 # 綁定屬性'score'
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute'score'
由于'score'沒有被放到__slots__中,所以不能綁定score屬性,試圖綁定score將得到AttributeError的錯誤。
使用__slots__要注意,__slots__定義的屬性僅對當前類起作用,對繼承的子類是不起作用的:
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子類中也定義__slots__,這樣,子類允許定義的屬性就是自身的__slots__加上父類的__slots__。

新聞熱點
疑難解答