Python類和對象
1、面向對象編程介紹
面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作爲程序的基本單元,一個對象包含了數據和操作數據的函數。面向對象是一種對現實世界理解和抽象的方法
“面向過程”(Procedure Oriented)是一種以過程爲中心的編程思想。“面向過程”也可稱之爲“面向記錄”編程思想,他們不支持豐富的“面向對象”特性(比如繼承、多態、封裝),並且它們不允許混合持久化狀態和域邏輯。
就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。
面向過程是一件事“該怎麼做“,面向對象是一件事“該讓誰來做”,然後那個“誰”就是對象,他要怎麼做是他自己的事,反正最後一羣對象合力能把事做好就行了
面向對象三個特性:
- 繼承
- 封裝
- 多態
2、類和對象
面向對象編程的2個非常重要的概念:類和對象
-
- 類
- 人以類聚 物以羣分。 具有相似內部狀態和運動規律的實體的集合(或統稱爲抽象)。 具有相同屬性和行爲事物的統稱
- 類是抽象的,在使用的時候通常會找到這個類的一個具體的存在,使用這個具體的存在
-
- 對象
- 某一個具體事物的存在 ,在現實世界中可以是看得見摸得着的。 可以是直接使用的
-
- 類和對象之間的關係
- 關係
類的構成
-
類(Class) 由3個部分構成
- 類的名稱:類名
- 類的屬性:一組數據
- 類的方法:允許對進行操作的方法 (行爲)
3、定義類與創建對象
1、類的定義
-
語法:
- class 類名: 方法列表
-
說明:
- 1、定義類時有2種:新式類和經典類,上面的Car爲經典類,如果是Car(object)則爲新式類
- 2、類名的命名規則按照"大駝峯"
2、創建對象
-
語法:
- 對象名 = 類名()
4、self
1.、理解self
- 看如下示例:
定義一個類
class Animal:
方法
def init(self, name):
self.name = name
def printName(self):
print(‘名字爲:%s’%self.name)
定義一個函數
def myPrint(animal):
animal.printName()
dog1 = Animal(‘西西’)
-
總結:
- 1、所謂的self,可以理解爲自己
- 2、可以把self當做C++中類裏面的this指針一樣理解,就是對象自身的意思
- 3、某個對象調用其方法時,python解釋器會把這個對象作爲第一個參數傳遞給self,所以開發者只需要傳遞後面的參數即可
2、init()方法
classCar:
def__init__(self):
self.wheelNum = 4
self.color = ‘藍色’
defmove(self):
print(‘車在跑,目標:夏威夷’)
創建對象
BMW = Car()
print(‘車的顏色爲:%s’%BMW.color)
print(‘車輪胎數量爲:%d’%BMW.wheelNum)
-
總結1:
- 當創建Car對象後,在沒有調用__init__()方法的前提下,BMW就默認擁有了2個屬性wheelNum和color,原因是__init__()方法是在創建對象後,就立刻被默認調用了
-
總結2:
- 1、init()方法,在創建一個對象時默認被調用,不需要手動調用
- 2、init(self)中,默認有1個參數名字爲self,如果在創建對象時傳遞了2個實參,那麼__init__(self)中出了self作爲第一個形參外還需要2個形參,例如__init__(self,x,y)
- 3、init(self)中的self參數,不需要開發者傳遞,python解釋器會自動把當前的對象引用傳遞進去
3、__new__方法
-
classA(object):
def__init__(self):
print(“這是 init 方法”)
def__new__(cls):
print(“這是 new 方法”)
return object.new(cls)
A() -
總結:
- 1、__new__至少要有一個參數cls,代表要實例化的類,此參數在實例化時由Python解釋器自動提供
- 2、__new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,可以return父類__new__出來的實例,或者直接是object的__new__出來的實例
- 3、__init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
- 4、我們可以將類比作製造商,__new__方法就是前期的原材料購買環節,__init__方法就是在有原材料的基礎上,加工,初始化商品環節
4、del()方法
-
實例:
- import time
classAnimal(object):
- import time
初始化方法
創建完對象後會自動被調用
def__init__(self, name):
print(’__init__方法被調用’)
self.__name = name
析構方法
當對象被刪除時,會自動被調用
def__del__(self):
print("__del__方法被調用")
print("%s對象馬上被幹掉了…"%self.__name)
創建對象
dog = Animal(“哈皮狗”)
刪除對象
del dog
cat = Animal(“波斯貓”) cat2 = cat
cat3 = cat
print("—馬上 刪除cat對象")
del cat
print("—馬上 刪除cat2對象")
del cat2
print("—馬上 刪除cat3對象")
del cat3
print(“程序2秒鐘後結束”)
time.sleep(2)
-
創建對象後,python解釋器默認調用__init__()方法;
-
當刪除一個對象時,python解釋器也會默認調用一個方法,這個方法爲__del__()方法
-
當內存中構建一個對象數據的時候回調__init__()方法,
-
當內存中銷燬(釋放)一個對象時回調__del__()方法
-
總結:
- 1、當有1個變量保存了對象的引用時,此對象的引用計數就會加1
- 2、當使用del刪除變量指向的對象時,如果對象的引用計數不是1,比如3,那麼此時只會讓這個引用計數減1,即變爲2,當再次調用del時,變爲1,如果再調用1次del,此時會真的把對象進行刪除
5、定義__str__()方法
-
實例:
- classCar:
def__init__(self, newWheelNum, newColor):
self.wheelNum = newWheelNum
self.color = newColor
def__str__(self):
msg = “嘿,我的顏色是” + self.color + “我有” + str(self.wheelNum) + “個輪胎…”
return msg
def move(self):
print(‘車在跑,目標:夏威夷’)
BMW = Car(4, “白色”)
print(BMW)
- classCar:
-
總結
- 1、在python中方法名如果是__xxxx__()的,那麼就有特殊的功能,因此叫做“魔法”方法
- 2、當使用print輸出對象的時候,只要自己定義了__str__(self)方法,那麼就會打印從在這個方法中return的數據
特殊方法:
- 特殊方法名 默認的參數 功能描述
- init() self 已經創建了對象,初始化對象回調方法
- str() self 和toString
- del() self 對象回收時候回調
- new() cls 對象創建的回調方法
總結:
- 1、__init__完成對象的初始化操作,在對象被創建完成後之後,立刻被調用執行,隱式調用,創建對象時的參數要跟init方法的參數保持一致
- 2、__new__時構造方法,創建對象時,首先調用的是new方法,new方法必須要有返回值,參數必須跟創建對象傳遞的參數一致
- 3、無論什麼情況,iinit和new方法的參數都要保持一致
- 4、先new再init、del
5、保護對象的屬性
如果有一個對象,當需要對其進行修改屬性時,有2種方法
- 對象名.屬性名 = 數據 ---->直接修改
- 對象名.方法名() ---->間接修改
爲了更好的保存屬性安全,即不能隨意修改,一般的處理方式爲
- 將屬性定義爲私有屬性
- 添加一個可以調用的方法,供調用
實例:
- classPeople(object):
def__init__(self, name):
self.__name = name
defgetName(self):
return self.__name
defsetName(self, newName):
if len(newName) >= 5:
self.__name = newName
else:
print(“error:名字長度需要大於或者等於5”)
xiaoming = People(“bin”)
print(xiaoming.__name)
總結:
- 1、Python中沒有像C++中public和private這些關鍵字來區別公有屬性和私有屬性
- 2、它是以屬性命名方式來區分,如果在屬性名前面加了2個下劃線’__’,則表明該屬性是私有屬性,否則爲公有屬性(方法也是一樣,方法名前面加了2個下劃線的話表示該方法是私有的,否則爲公有的)
6、繼承
1. 繼承的概念
- 在現實生活中,繼承一般指的是子女繼承父輩的財產,在程序中,繼承描述的是事物之間的所屬關係,例如貓和狗都屬於動物,程序中便可以描述爲貓和狗繼承自動物;同理,波斯貓和巴釐貓都繼承自貓,而沙皮狗和斑點狗都繼承足夠,如下如圖所示
2. 繼承示例
class Cat(object):
def init(self, name, color=“白色”):
self.name = name
self.color = color
def run(self):
print("%s–在跑"%self.name)
定義一個子類,繼承Cat類,如下:
classBosi(Cat):
def setNewName(self, newName):
self.name = newName
def eat(self):
print("%s–在喫"%self.name)
bs = Bosi(“印度貓”)
print(‘bs的名字爲:%s’%bs.name)
print(‘bs的顏色爲:%s’%bs.color)
bs.eat()
bs.setNewName(‘波斯’)
bs.run()
-
說明:
- 雖然子類沒有定義__init__方法,但是父類有,所以在子類繼承父類的時候這個方法就被繼承了,所以只要創建Bosi的對象,就默認執行了那個繼承過來的__init__方法
-
總結:
- 1、子類在繼承的時候,在定義類時,小括號()中爲父類的名字
- 2、父類的屬性、方法,會被繼承給子類
-
實例:
- class Animal(object):
def init(self, name=‘動物’, color=‘白色’):
self.__name = name
self.color = color
def __test(self):
print(self.__name)
print(self.color)
def test(self):
print(self.__name)
print(self.color)
class Dog(Animal):
def dogTest1(self):
#print(self.__name)
#不能訪問到父類的私有屬性
print(self.color)
def dogTest2(self):
#self.__test()
#不能訪問父類中的私有方法
self.test()
A = Animal()
#print(A.__name)
#程序出現異常,不能訪問私有屬性
print(A.color)
#A.__test()
#程序出現異常,不能訪問私有方法
A.test()
print("------分割線-----")
D = Dog(name = “小花狗”, color = “黃色”)
D.dogTest1()
D.dogTest2()
- class Animal(object):
3. 注意點:
- 1、私有的屬性,不能通過對象直接訪問,但是可以通過方法訪問
- 2、私有的方法,不能通過對象直接訪問
- 3、私有的屬性、方法,不會被子類繼承,也不能被訪問
- 4、一般情況下,私有的屬性、方法都是不對外公佈的,往往用來做內部的事情,起到安全的作用
7、多繼承
1. 多繼承:
classA:
def printA(self):
print(’----A----’)
定義一個父類
classB:
def printB(self):
print(’----B----’)
定義一個子類,繼承自A、B
class C(A,B):
def printC(self):
print(’----C----’)
obj_C = C()
obj_C.printA()
obj_C.printB()
- 說明:
- 1、python中是可以多繼承的
- 2、父類中的方法、屬性,子類會繼承
2、重寫:
-
<1>重寫父類方法
- 所謂重寫,就是子類中,有一個和父類相同名字的方法,在子類中的方法會覆蓋掉父類中同名的方法
- #coding=utf-8
class Cat(object):
def sayHello(self):
print(“halou-----1”)
class Bosi(Cat):
def sayHello(self):
print(“halou-----2”)
bosi = Bosi() bosi.sayHello()
-
<2> 調用父類的方法
- #coding=utf-8
class Cat(object):
def init(self,name):
self.name = name
self.color = ‘yellow’
class Bosi(Cat):
def init(self,name):
- #coding=utf-8
調用父類的__init__方法1(python2)
#Cat.init(self,name)
調用父類的__init__方法2
#super(Bosi,self).init(name)
調用父類的__init__方法3
super().init(name)
def getName(self):
return self.name
bosi = Bosi(‘xiaohua’)
print(bosi.name)
print(bosi.color)
8、多態
多態的概念是應用於Java和C#這一類強類型語言中,而Python崇尚“鴨子類型”
所謂多態:定義時的類型和運行時的類型不一樣,此時就成爲多態
Python僞代碼實現Java或C#的多態
- classF1(object):
def show(self):
print’F1.show’
classS1(F1):
def show(self):
print’S1.show’
classS2(F1):
defshow(self):
print’S2.show’
由於在Java或C#中定義函數參數時,必須指定參數的類型# 爲了讓Func函數既可以執行S1對象的show方法,又可以執行S2對象的show方法,所以,定義了一個S1和S2類的父類# 而實際傳入的參數是:S1對象和S2對象
def Func(F1 obj):
“”“Func函數需要接收一個F1類型或者F1子類的類型”""
print obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函數中傳入S1類的對象 s1_obj,執行 S1 的show方法,結果:S1.show
s2_obj = S2() Func(s2_obj)
在Func函數中傳入Ss類的對象 ss_obj,執行 Ss 的show方法,結果:S2.show
Python “鴨子類型”
- class F1(object):
def show(self):
print’F1.show’
class S1(F1):
def show(self):
print’S1.show’
class S2(F1):
def show(self):
print’S2.show’
def Func(obj):
print obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
9、類屬性與實例屬性
類屬性:所屬類,這個類下所有的對象都可以共享這個類屬性。 相當於java中靜態屬性
1、類屬性
- class People(object):
name = ‘Tom’#公有的類屬性
__age = 12#私有的類屬性
p = People() print(p.name) #正確
print(People.name) #正確
print(p.__age) #錯誤,不能在類外通過實例對象訪問私有的類屬性
print(People.__age) #錯誤,不能在類外通過類對象訪問私有的類屬性
2、實例屬性(對象屬性)
- classPeople(object):
address = ‘山東’#類屬性
def__init__(self):
self.name = ‘xiaowang’#實例屬性
self.age = 20#實例屬性
p = People()
p.age =12#實例屬性
print(p.address) #正確
print(p.name) #正確
print(p.age) #正確
print(People.address) #正確
print(People.name) #錯誤
print(People.age) #錯誤
3、通過實例(對象)去修改類屬性
- classPeople(object):
country = ‘china’#類屬性
print(People.country)
p = People()
print(p.country)
p.country = ‘japan’
print(p.country) #實例屬性會屏蔽掉同名的類屬性
print(People.country)
del p.country #刪除實例屬性
print(p.country)
總結
- 如果需要在類外修改類屬性,必須通過類對象去引用然後進行修改。如果通過實例對象去引用,會產生一個同名的實例屬性,這種方式修改的是實例屬性,不會影響到類屬性,並且之後如果通過實例對象去引用該名稱的屬性,實例屬性會強制屏蔽掉類屬性,即引用的是實例屬性,除非刪除了該實例屬性。
10、類方法和靜態方法
1. 類方法
-
是類對象所擁有的方法,需要用修飾器@classmethod來標識其爲類方法,對於類方法,第一個參數必須是類對象,一般以cls作爲第一個參數(當然可以用其他名稱的變量作爲其第一個參數,但是大部分人都習慣以’cls’作爲第一個參數的名字,就最好用’cls’了),能夠通過實例對象和類對象去訪問
-
classPeople(object):
country = ‘china’#類方法,用classmethod來進行修飾
@classmethod
def getCountry(cls):
return cls.country
p = People() print
p.getCountry() #可以用過實例對象引用
print People.getCountry() #可以通過類對象引用 -
類方法還有一個用途就是可以對類屬性進行修改:
- classPeople(object):
country = ‘china’#類方法,用classmethod來進行修飾 @classmethod
def getCountry(cls):
return cls.country
@classmethod
Def setCountry(cls,country):
cls.country = country
p = People()
print p.getCountry() #可以用過實例對象引用
print People.getCountry() #可以通過類對象引用
p.setCountry(‘japan’)
print p.getCountry()
print People.getCountry()
- classPeople(object):
2. 靜態方法
-
需要通過修飾器@staticmethod來進行修飾,靜態方法不需要多定義參數
- classPeople(object):
country = ‘china’
@staticmethod#靜態方法
Def getCountry():
return People.country
print People.getCountry()
- classPeople(object):
總結:
- 從類方法和實例方法以及靜態方法的定義形式就可以看出來,類方法的第一個參數是類對象cls,那麼通過cls引用的必定是類對象的屬性和方法;而實例方法的第一個參數是實例對象self,那麼通過self引用的可能是類屬性、也有可能是實例屬性(這個需要具體分析),不過在存在相同名稱的類屬性和實例屬性的情況下,實例屬性優先級更高。靜態方法中不需要額外定義參數,因此在靜態方法中引用類屬性的話,必須通過類對象來引用