面向對象
類(class):是一種用來描述具有相同屬性和方法的對象的集合。
類變量:類變量在整個實例化的對象中是公用的。一般定義在類中且在函數體之外。
方法:類中的函數
數據成員:類變量或者實例變量用於處理類及其實例對象的相關的數據。
方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱爲方法的重寫。
局部變量:定義在方法中的變量,只作用於當前實例的類。
實例變量:在類的聲明中,屬性是用變量來表示的,這種變量就稱爲實例變量,實例變量就是一個用 self 修飾的變量。
繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作爲一個基類對象對待。就像我們定義一個fruit(水果)類,然後又定義了一個fruit類的派生類apple(蘋果),它有着fruit類的一些屬性和方法,也有着自己的一些獨特的屬性和方法,和fruit類是一種’is-a’的關係。
實例化:類的一個具體對象,類像當於一個模板,只有我們將其實例化爲一個對象後才能對其進行相應的操作。
對象:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。
類定義
定義一個類:
class classname:
....
....
....
注:代碼中’’’ ‘’'爲輸出內容
使用類對象方法
類對象支持兩種操作:屬性引用和實例化
屬性引用:和python中的其他語法一樣,obj.name
在類中帶__
的屬性爲類的私有屬性,私有屬性在類外部無法直接訪問,像__name
.
class Fruit:
#這是類的一個基本屬性
self.number = 100
def get_number(self):
a = self.number
return a
f = Fruit()
print('We have {0} fruits'.format(f.number))
print('We have {0} fruits'.format(f.get_number()))
'''
We have 100 fruits
We have 100 fruits
'''
構造方法
python類中有一個名爲__init__()
的特殊方法,叫構造方法,該方法在類進行實例化時會自動進行調用(可以用於類屬性初始化等),類似C++裏面類的構造函數。
def __init__(self):
self.data = []
類定義了 __init__()
方法,類的實例化操作會自動調用__init__()
方法。
class Fruit:
def __init__(self):
print('你已經實例化了一個對象')
f = Fruit()
'''
你已經實例化了一個對象
'''
init_() 方法可以有參數,參數通過 init() 傳遞到類的實例化操作上。
class Complex:
def __init__(self,real,image):
self.r = real
self.i = image
def get_complex(self):
print('complex real is %.2f , image is %.2f'%(self.r,self.i))
a = Complex(3.5,-3)
a.get_complex()
'''
complex real is 3.50 , image is -3.00
'''
self代表類的實例,而非類
類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。但self並不是Python中的關鍵字哦。
不知是否可以這樣理解,self就代表的是你按照一個類實例化一個對象後的對象的地址。很像C++類中this指針
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
'''
<__main__.Test object at 0x0000025EC6D45608>
<class '__main__.Test'>
'''
類的方法
在類的內部,使用 def 關鍵字來定義一個方法,與一般函數定義不同,類方法必須包含參數 self, 且爲第一個參數。
繼承
Python 同樣支持類的繼承,格式如下:
class Derivedclassname(Baseclassname):
...
...
Baseclassname(基類名)必須與派生類定義在一個作用域內。除了類,還可以用表達式,基類定義在另一個模塊中時這一點非常有用:
class Derivedclassname(modename.Baseclassname):
class Fruit:
def __init__(self,sweet):
self.sweetness = sweet
def describe(self):
print('Our fruit has a sweetness of %.2f'%self.sweetness)
class Apple(Fruit):#單繼承,繼承fruit類
def __init__(self,sweet,color):
self.color = color
Fruit.__init__(self,sweet)
def describe(self):#改寫基類fruit的方法
print('Our apple has a sweetness of {0:.2f}%,and color is {1}'.format(self.sweetness,self.color))
apple = Apple(62.2,'red')
apple.describe()
輸出:
Our apple has a sweetness of 62.20%,and color is red
多繼承
Python同樣可以繼承多個基類:
class Derivedclassname(basename1,basename2,...):
...
...
...
需要注意圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 即方法在子類中未找到時,從左到右查找父類中是否包含方法。
class Fruit:
def __init__(self,sweet):
self.sweetness = sweet
def describe(self):
print('Our fruit has a sweetness of %.2f'%self.sweetness)
class Food:
def __init__(self,uprice,num):
self.unit_price = uprice
self.number = num
self.total_price = num * uprice
def cost(self):
print('You need to pay {0:.3} yuan, thank you'.format(self.total_price))
class Apple(Fruit,Food):
def __init__(self,sweet,color,uprice,num):
self.color = color
Fruit.__init__(self,sweet)
Food.__init__(self,uprice,num)
def describe(self):
print('Our fruit has a sweetness of {0:.2f}%,and color is {1}'.format(self.sweetness,self.color))
apple = Apple(62.2,'red',3.5,21)
apple.describe()
apple.cost()
輸出:
Our fruit has a sweetness of 62.20%,and color is red
You need to pay 73.5 yuan, thank you
方法重寫
如果你的父類方法的功能不能滿足你的需求,你可以在子類重寫你父類的方法,如果想調用已經被覆蓋的基類方法,可以用super(子類名,子類實例對象名).父類方法
class Parent_clasa:
def Method(self):
print ('父類方法')
class Child_class(Parent_clasa): # 定義子類
def Method(self):
print ('子類方法')
c = Child_class() # 子類實例化
c.Method() # 子類調用重寫方法
super(Child_class,c).Method() #用子類對象調用父類已被覆蓋的方法
'''
子類方法
父類方法
'''
子類繼承父類構造函數
如果在子類中需要父類的構造方法就需要顯式地調用父類的構造方法,或者不重寫父類的構造方法。
class A:
def __init__(self,x,y):
self.x = x
self.y = y
print('pos is ({0},{1})'.format(self.x,self.y))
def xxx(self):
print('parent now')
class B(A):
def xxx(self):
print('child now')
b = B(10,3)
b.xxx()
'''
pos is (10,3)
child now
'''
如果重寫了**init** 時,實例化子類,就不會調用父類已經定義的 init
如果重寫了**init** 時,要繼承父類的構造方法,可以使用 super 關鍵字super(子類,self).__init__(參數1,參數2,....)
,或者父類名稱.__init__(self,參數1,參數2,...)
類的私有屬性
兩個下劃線開頭,聲明該屬性爲私有,像__name
不能在類的外部被使用或直接訪問。在類內部的方法中使用時 self.__name
。
class JustCounter:
__secretCount = 0 # 私有變量
publicCount = 0 # 公開變量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter.publicCount)
print (counter.__secretCount) # 報錯,實例不能訪問私有變量
'''
1
2
2
Traceback (most recent call last):
File "test.py", line 16, in <module>
print (counter.__secretCount) # 報錯,實例不能訪問私有變量
AttributeError: 'JustCounter' object has no attribute '__secretCount'
'''
類的私有屬性
兩個下劃線開頭,聲明該方法爲私有方法,像__private_method
,只能在類的內部調用 ,不能在類的外部調用。self.___private_method
。
class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private
def who(self):
print('name : ', self.name)
print('url : ', self.__url)
def __foo(self): # 私有方法
print('這是私有方法')
def foo(self): # 公共方法
print('這是公共方法')
self.__foo()
x = Site('***, 'www.***.com')
x.who() # 正常輸出
x.foo() # 正常輸出
x.__foo() # 報錯
'''
name : ***
url : www.***.com
這是公共方法
這是私有方法
Traceback (most recent call last):
File "F:\Python\Program\test.py", line 61, in <module>
x.__foo() # 報錯
AttributeError: 'Site' object has no attribute '__foo'
'''
類的專有方法(魔法方法!)
-
__init__
: 構造函數,在生成對象時調用,類似C++構造函數 -
__del__
: 析構函數,釋放對象時使用,類似C++析構函數,常用在釋放申請的內存空間 -
__repr__
: 打印,轉換。這個個函數就是在打印類的時候,控制類輸出的字符串class Name: def __init__(self,name): self.name = name print(Name('s')) ''' <__main__.Name object at 0x0000023744AFD248> '''
class Name: def __init__(self,name): self.name = name def __repr__(self): #控制了在打印類時候的輸出 return 'Name({!r})'.format(self.name) print(Name('s')) ''' Name('s') '''
-
__setitem__
: 每當屬性被賦值的時候都會調用該方法,因此不能再該方法內賦值 self.name = value 會死循環 -
__getitem__
: 當訪問不存在的屬性時會調用該方法 -
__len__
: 獲得長度,如果一個類表現得像一個list,要獲取有多少個元素,就得用len()
函數。要讓len()
函數工作正常,類必須提供一個特殊方法__len__()
,它返回元素的個數。
class CountList:
def __init__(self,*args):
self.list = [ x for x in args]
self.count = self.__len__()
def __len__(self):
return len(self.list)
def get_count(self):
return self.count
a = CountList(1,2,3,4,4,5)
print(a.get_count())
print(len(a))
'''
6
6
'''
__cmp__
: 比較運算__call__
: 函數調用__add__
: 加運算__sub__
: 減運算
class MyClass:
def __init__(self, height, weight):
self.height = height
self.weight = weight
# 兩個對象的長相加,寬不變.返回一個新的類
def __add__(self, others):
return MyClass(self.height + others.height, self.weight + others.weight)
# 兩個對象的寬相減,長不變.返回一個新的類
def __sub__(self, others):
return MyClass(self.height - others.height, self.weight - others.weight)
# 說一下自己的參數
def intro(self):
print("高爲", self.height, " 重爲", self.weight)
def main():
a = MyClass(height=10, weight=5)
a.intro()
b = MyClass(height=20, weight=10)
b.intro()
c = b - a
c.intro()
d = a + b
d.intro()
if __name__ == '__main__':
main()
'''
高爲 10 重爲 5
高爲 20 重爲 10
高爲 10 重爲 5
高爲 30 重爲 15
'''
__mul__
: 乘運算__truediv__
: 除運算__mod__
: 求餘運算__pow__
: 乘方
同樣的,類的專有方法也可以重寫