Python3 面向對象
python是一門面向對象語言,在python中有一句話:一切都是對象
面向對象簡介類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的執行個體。
類變量:類變量在整個執行個體化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作為執行個體變量使用。 資料成員:類變量或者執行個體變量用于處理類及其執行個體對象的相關的資料。
方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆寫(override),也稱為方法的重寫。
執行個體變量:定義在方法中的變量,隻作用于目前執行個體的類。
繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模拟"是一個(is-a)"關系(例圖,Dog是一個Animal)。
執行個體化:建立一個類的執行個體,類的具體對象。
方法:類中定義的函數。
對象:通過類定義的資料結構執行個體。對象包括兩個資料成員(類變量和執行個體變量)和方法。 類的定義
文法格式如下:class ClassName:
.
.
.
類執行個體化後,可以使用其屬性;實際上,建立一個類之後,可以通過類名通路其屬性。
類對象
類對象支援兩種操作:屬性引用和執行個體化。
屬性引用文法:obj.name
對象建立後,類命名空間中所有的命名都是有效屬性名#!/usr/bin/python3
class People:
"""一個人類"""
def __init__(self, name, age): # 類的初始化方法,執行個體化的時候首先調用的方法,前後雙下劃線的方法都是特殊方法
self.name = name # 類的屬性,也是特點、特征
self.age = age
def walk(self): # 普能方法
"""人類會走路"""
print(f'{self.name} is walking')
# 執行個體化
p = People('yhyang', 18)
# 通路類的屬性和方法
print(f'我的名字是:{p.name},我今年{p.age}歲')
p.walk()
輸出:
我的名字是:yhyang,我今年18歲
yhyang is walking
注:上例中,init() 是類的初始化方法,用于初始化類中的屬性和方法。self代表類的執行個體,而非類
類的方法與普通的函數隻有一個特别的差別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。
self 代表的是類的執行個體,代表目前對象的位址,而 self.class 則指向類。 類的方法
類地内部,使用 def 關鍵字來定義一個方法,與一般函數定義不同,類方法必須包含參數 self, 且為第一個參數,self 代表的是類的執行個體。
示例代碼:#!/usr/bin/python3
class People:
"""一個人類"""
def __init__(self, name, age): # 類的初始化方法,執行個體化的時候首先調用的方法,前後雙下劃線的方法都是特殊方法
self.name = name # 類的屬性,也是特點、特征
self.age = age
def walk(self): # 普能方法
"""人類會走路"""
print(f'{self.name} is walking')
# 執行個體化
p = People('yhyang', 18)
# 通路類的方法
p.walk()
輸出:
yhyang is walking
類中的變量私有變量:__name,不能被繼承
内部變量:_開頭
通過方法修改私有資料,對資料進行保護
示例代碼:#!/usr/bin/python3
class Car:
name = 'xxx' # 類的屬性
def __init__(self, brand, price, wheels, power):
self._brand = brand
self.price = price
self.wheels = wheels
self.power = power
self.__speed = 0
def run(self, action):
print(f'{self.brand} is running')
if action == '1':
self.__speed += 1 * 10 # 修改私有變量
print('目前速度是:{} km/h'.format(self.__speed))
def start(self):
print(f'{self.brand} is on')
@property
def speed(self): # 隻讀,getter方法
return self.__speed
@property
def brand(self):
return self._brand
@brand.setter # 添加setter方法,可以被指派
def brand(self, brand):
if not isinstance(brand, str):
raise TypeError('牌子是字元串類型') # raise 抛出異常
self._brand = brand # 可以對屬性操作,提前判斷
@property # 把下邊的函數變成了屬性,可以直接用 執行個體名.info 這樣調用
def info(self):
return f'{self.brand}: {self.price}'
# 執行個體化
auto = Car('auto', 30000, 4, 'oil')
auto.run('1') # 調用run()方法,修改私有變量
auto.info # 以通路屬性的方式通路info()方法
auto.brand = 'audiA8' # 此處的brand不是屬性,而是下邊的@brand.setter處定義的brand方法
auto.brand
tesla = Car('Tesla', 100000, 4, 'electric')
tesla.run('1')
tesla.price = 999999 # 此處是類對象的屬性
tesla.price
tesla.name
Car.name
auto.country = 'China' # 在類的對象中動态的新聲明一個屬性,原類之中不存在
auto.country
輸出:
auto is running
目前速度是:10 km/h
'auto: 30000'
'audiA8'
Tesla is running
目前速度是:10 km/h
999999
'xxx'
'xxx'
'China'
特殊方法init: 把各種屬性都綁定到self
slots:限制執行個體的動态屬性,減少記憶體消耗,類型為tuple
str:對象的說明文字
eq: 比較對象是否相等
classmethod 與 staticmethod ;classmethod 會把類本身作為第一個參數傳入
示例代碼1:
#!/usr/bin/python3 class Computer: __slots__ =('__name', 'mem', 'cpu') # 為節省資源,不允許執行個體對象随意添加屬性 def __init__(self, name, mem, cpu): self.__name = name self.mem = mem self.cpu = cpu def play(self, game='qq games'): print('play',game) # 執行個體化 pc2 = Computer('admin', '8G', '8核') pc2.mem pc2.ssd = 'ssd' # 此處會報錯,類中用了__slots__是以不能随意添加 輸出: '8G' AttributeError: 'Computer' object has no attribute 'ssd'
示例代碼2:
#!/usr/bin/python3 class Computer: __slots__ =('_name', 'mem', 'cpu') # 為節省資源,不允許執行個體對象随意添加屬性 def __init__(self, name, mem, cpu): self._name = name self.mem = mem self.cpu = cpu def play(self, game='qq games'): print('play',game) def __str__(self): # 當print(對象)時,自動調用此方法 return f'{self._name}:{self.mem}-{self.cpu}' # 執行個體化 pc3 = Computer('admin', '8G','8核') print(pc3) # 直接列印對象 輸出: admin:8G-8核
示例代碼3:
#!/usr/bin/python3 class Computer: __slots__ =('_name', 'mem', 'cpu') # 為節省資源,不允許執行個體對象随意添加屬性 def __init__(self, name, mem, cpu): self._name = name self.mem = mem self.cpu = cpu def play(self, game='qq games'): print('play',game) def __str__(self): # 當print(對象)時,自動調用此方法 return f'{self._name}:{self.mem}-{self.cpu}' def __eq__(self,other): # 對象A == 對象B 時調用 return self.cpu == other.cpu # 執行個體化 pc2 = Computer('admin','8G','8核') pc3 = Computer('admin','4G','8核') pc2 == pc3 # 調用__eq__方法,認為cpu相等即為兩個對象相等 輸出: True
示例代碼4:
#!/usr/bin/python3 class Computer: __slots__ =('_name', 'mem', 'cpu') # 為節省資源,不允許執行個體對象随意添加屬性 def __init__(self, name, mem, cpu): self._name = name self.mem = mem self.cpu = cpu def play(self, game='qq games'): print('play',game) def __str__(self): # 當print(對象)時,自動調用此方法 return f'{self._name}:{self.mem}-{self.cpu}' def __eq__(self,other): # 對象A == 對象B 時調用 return self.cpu == other.cpu @classmethod def new_pc(cls, info): #cls 相當于類本身,通過 類名.new_pc(‘參數’)來直接生成執行個體,而不調用__init__ "從字元串直接産生新的執行個體" name, mem, cpu = info.split('-') # 傳參時用-連接配接三個參數 return cls(name, mem, cpu) # 使用classmethod建立新對象 pc666 = Computer.new_pc('yhyang-16G-8eeeee核') print(pc666) 輸出: yhyang:16G-8核
示例代碼5:
#!/usr/bin/python3 class Computer: __slots__ =('_name', 'mem', 'cpu') # 為節省資源,不允許執行個體對象随意添加屬性 def __init__(self, name, mem, cpu): self._name = name self.mem = mem self.cpu = cpu def play(self, game='qq games'): print('play',game) def __str__(self): # 當print(對象)時,自動調用此方法 return f'{self._name}:{self.mem}-{self.cpu}' def __eq__(self,other): # 對象A == 對象B 時調用 return self.cpu == other.cpu @classmethod def new_pc(cls, info): #cls 相當于類本身通過 類名.new_pc(‘參數’)來直接生成執行個體,而不調用__init__ "從字元串直接産生新的執行個體" name, mem, cpu = info.split('-') # 傳參時用-連接配接三個參數 return cls(name, mem, cpu) @staticmethod # 不需要生成類的執行個體,就可以使用的方法 ,直接用 類名.calc來調用此方法 def calc(a,b,oper): # 不用第一個參數 "根據操作符+-*/來計算a 和b的結果" if oper == '+': return a + b Computer.calc(2,5,'+') 輸出: 7
面向對象三大特征
封裝
繼承
多态
繼承(多繼承暫時不說)
python支援類的繼承,如下格式:
class DerivedClassName(BaseClassName1): . . .
要注意圓括号中基類的順序,若是基類中有相同的方法名,而在子類使用時未指定,python從左至右搜尋 即方法在子類中未找到時,從左到右查找基類中是否包含方法。
BaseClassName(示例中的基類名)必須與派生類定義在一個作用域内。除了類,還可以用表達式,基類定義在另一個子產品中時這一點非常有用:
class DerivedClassName(modname.BaseClassName):
示例代碼:#!/usr/bin/python3
#類定義
class people:
#定義基本屬性
name = ''
age = 0
#定義私有屬性,私有屬性在類外部無法直接進行通路
__weight = 0
#定義構造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 說: 我 %d 歲。" %(self.name,self.age))
#單繼承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#調用父類的構函
people.__init__(self,n,a,w)
self.grade = g
#覆寫父類的方法
def speak(self):
print("%s 說: 我 %d 歲了,我在讀 %d 年級"%(self.name,self.age,self.grade))
s = student('ken',10,60,3)
s.speak()
輸出:
ken 說: 我 10 歲了,我在讀 3 年級
方法重寫(多态)如果你的父類方法的功能不能滿足你的需求,你可以在子類重寫你父類的方法
super() 函數是用于調用父類(超類)的一個方法。
示例代碼:#!/usr/bin/python3
class Parent: # 定義父類
def FatherMethod(self):
print ('調用父類方法')
class Child(Parent): # 定義子類
def FatherMethod(self):
print ('調用子類方法')
c = Child() # 子類執行個體
c.FatherMethod() # 子類調用重寫方法
super(Child,c).FatherMethod() #用子類對象調用父類已被覆寫的方法
輸出:
調用子類方法
調用父類方法
元程式設計類的類型是type,type類型是元類型metaclass,對象的類型是類類型
順序為 type---> class -----> object
類A繼承于type,通過type的new方法傳回一個對象,可以認為是類A的對象,是以
類執行個體化的方式為:a = A(),其實a是A調用type中new方法的傳回值
示例代碼1:#!/usr/bin/python3
# 運作時動态建立類和函數
# metaclass -> class ->obj
# __new__
class Game:
pass
Game.__class__
輸出:
type
type(Game)
輸出:
type
示例代碼2:#!/usr/bin/python3
# type 是一個metaclass
# 通過type建立一個新的metaclass
class Yuhy(type):
pass
class Yhy(metaclass=Yuhy):
pass
print(type(Yuhy)) # 檢視Yuhy類的類型
print(type(Yhy)) # 檢視Yhy類的類型
輸出:
isinstance(Yhy,Yuhy) # Yhy與Yuhy是否是同樣的類型
輸出:
True
用Yhy.__new__?檢視此方法
Signature: Yhy.__new__(*args, **kwargs)
Docstring: Create and return a new object. See help(type) for accurate signature.
Type: builtin_function_or_method
help(type)
示例代碼:class Yuhy(type):
def __new__(cls, name, bases, my_dict): # classmethod
print(f'{name} 使用__new__建立')
yhy = super().__new__(cls, name, bases, my_dict)
return yhy
class Ks(metaclass=Yuhy):
pass
輸出:
Ks 使用__new__建立
a = Ks()
print(a)
輸出:
<__main__.Ks object at 0x0000024AF06E9A20>
反射能用來幹什麼
反射也叫内省,其實就是讓對象自己告訴我們他有啥,能幹啥
有三個方法hasattr(obj,attr)
setattr(obj,attr,val )
getattr(obj,attr)
示例代碼1:#!/usr/bin/python3
# hasattr(obj, attr) 檢查obj是否有一個名為attr的值的屬性,傳回一個bool
# getattr(obj,attr) 檢查obj中是否有attr屬性或方法,并将其傳回
# setattr(obj,attr,value) 向對象obj中添加一個屬性,值為value
s = 'yhyang' # s是一個字元串對象
s.upper()
輸出:
'YHYANG'
isinstance(s, str)
輸出:
True
hasattr(s,'upper') # 檢視s當中是否有一個叫upper的方法
輸出:
True
示例代碼2:#!/usr/bin/python3
class People:
def eat(self):
print('eate')
def drink(self):
print('drink')
p = People()
p.eat()
hasattr(p,'eat') # 找這個對象p中有沒有eat這個方法
getattr(p,'eat') # 在p中找到eat方法 并傳回
aa = getattr(p,'eat')
aa()
setattr(p, 'sleep', 'sleep1234') # 添加一個新的屬性,值為sleep1234
p.sleep
輸出:
eate
True
>
eate
'sleep1234'
示例代碼3:汽車工廠#!/usr/bin/python3
# 汽車類
class Car:
def info(self):
print('Car 父類 ')
class Audi(Car):
def info(self):
print('Audi 汽車')
class Tesla(Car):
def info(self):
print('Tesla 汽車')
# 工廠類
class Factory:
def create(self):
print('建立汽車,工廠基類')
class AudiFactory(Factory):
def creat(self):
print('創造Audi汽車')
return Audi()
class TeslaFactory(Factory):
def creat(self):
print('創造Tesla汽車')
return Tesla()
# 生産汽車
audi_F = AudiFactory()
audi = audi_F.creat()
audi.info()
#另一種寫法
AudiFactory().creat().info()
TeslaFactory().creat().info()
輸出:
創造Audi汽車
Audi 汽車
創造Audi汽車
Audi 汽車
創造Tesla汽車
Tesla 汽車