面對物件2
文章目錄
一. 面對物件三大特徵介紹
- 封裝(隱藏)
通過私有屬性,私有方法的方式進行封裝
- 繼承
繼承可以讓子類繼承父類特性,提高程式碼重用性
是一種增量進化,在父類基礎上增加功能,改進演算法
- 多型
同一種方法呼叫物件不同會產生不同行為
1. 繼承
- 已有的類稱為父類或基類,新的類稱為子類或派生類
- Python支援多重繼承,一個子類可以繼承多個父類
- 類定義中若沒有指定父類,則預設是object類,它是所有類的父類,裡面定義了一些類共有的預設操作,比如__new__
- 定義子類時,必須在其建構函式內呼叫父類的建構函式
#測試繼承的基本使用
class Person: #可以不定義構造器
def say_age(self):
print("年齡我不知道")
class Student(Person):
pass
print(Student.mro()) #檢視繼承結構
s=Student()
s.say_age()
# 測試繼承的基本使用
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age #父類的私有屬性,子類也會繼承,但是要帶上父類名去呼叫
def say_age(self):
print("年齡我不知道")
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age) #子類必須顯示呼叫父類構造器,共享父類程式碼
self.score=score #自己特有的屬性
print(Student.mro()) # 檢視繼承結構
s = Student("gao",18,72)
s.say_age()
print(s.name)
#print(s.age) #'Student' object has no attribute 'age'
print(s.__dict__) #{'name': 'gao', '_Person__age': 18, 'score': 72}說明繼承了,不過名字裡有父類
print(s._Person__age)
1. 類成員的繼承與重寫
- 子類繼承了父類除構造方法之外的所有成員(包括私有屬性和方法,但要通過父類名來呼叫)
- 方法重寫:子類可以重新定義父類中的方法,這樣會覆蓋父類的方法
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age # 父類的私有屬性,子類也會繼承,但是要帶上父類名去呼叫
def say_age(self):
print("我的年齡是:",self.age)
def say_name(self):
print("我的名字是:{0}".format(self.name))
class Student(Person):
def __init__(self, name, age, score):
Person.__init__(self, name, age) # 子類必須顯示呼叫父類構造器,共享父類程式碼
self.score = score # 自己特有的屬性
def say_name(self):
print("報告老師,我的名字是:",self.name)
s = Student("gao", 18, 72)
s.say_name()
2. 常用方法
3. 多重繼承
- 多重繼承使類的整體層次異常複雜,儘量避免使用
- 父類出現相同名字方法,從左至右搜尋
- mro也是按從左至右的順序
class A:
def aa(self):
print("aa")
def say(self):
print("AAA")
class B:
def bb(self):
print("bb")
def say(self):
print("BBB")
class C(B,A): #沒有建構函式,也可以繼承
def __init__(self,name):
self.name=name
def cc(self):
print("cc")
c=C(3)
print(C.mro()) #[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
c.aa()
c.bb()
c.cc()
c.say() #父類中出現名稱相同的方法,按從左向右搜尋
4. super()獲得父類定義
- 子類中想獲得父類方法,可以通過super()
- 和直接用父類名呼叫效果一樣
class A:
def say(self):
print("A:",self)
print("say AAA")
class B(A):
def say(self):
super().say() #和直接用A.say()效果一樣
print("B:",self)
b=B()
b.say()
2. 多型
- 多型指同一方法呼叫由於物件不同會產生不同行為
- 方法有多型,屬性沒有多型
- 多型必要條件:繼承,方法重寫
class Man:
def eat(self):
print("餓了,吃飯")
class Chinese(Man):
def eat(self):
print("用筷子吃飯")
class English(Man):
def eat(self):
print("用叉子吃飯")
class Indian(Man):
def eat(self):
print("用右手吃飯")
def manEat(m):
if isinstance(m,Man):
m.eat()
else:
print("不能吃飯")
#Chinese.eat() #TypeError: eat() missing 1 required positional argument: 'self'
manEat(Chinese)
manEat(English()) #有沒有括號都可以
二. 特殊方法和屬性
1. 特殊方法和運算子過載
- Python的運算子實際上是通過呼叫物件的特殊方法實現的
- 常見的特殊方法:
__init __: 構造方法 (物件建立:p=Person())
__del __:析構方法
__call __:函式呼叫(函式名(引數)直接呼叫被__call __定義過的方法)
__len __:長度
- 每個運算子都對應了相應方法:
+:__add __
-:__sub __
<,<=,==,>,>=,!=:__lt __, __le __, __eq __, __gt __, __ge __, __ne __
|,^,&:__or __, __xor __, __and __
<<,>>:__lshift __, __rshift __
*,/,%,//:__mul __, __truediv __, __mod __, __floordiv __
** : __pow __
- 可以重寫上述特殊方法,實現運算子過載
class Person:
def __init__(self,name):
self.name=name
def __add__(self,other):
if isinstance(other,Person):
return("{0}--{1}".format(self.name,other.name)) #注意是other.name
else:
return "不是同類"
def __mul__(self,other):
if isinstance(other,int):
return self.name*other
else:
return"不是同類物件"
p1=Person("gao")
p2=Person("peng")
x=p1+p2 #加號呼叫的是__add__函式
print(x)
print(p1*3) #乘號呼叫的是__mul__函式
2. 特殊屬性
class A:
def aa(self):
print("aa")
def say(self):
print("AAA")
class B:
def bb(self):
print("bb")
def say(self):
print("BBB")
class C(B,A): #沒有建構函式,也可以繼承
def __init__(self,name):
self.name=name
def cc(self):
print("cc")
c=C(3)
c.aa()
c.bb()
c.cc()
c.say() #父類中出現名稱相同的方法,按從左向右搜尋
print(dir(c)) #dir()是內建函式
print(c.__dict__)
print(c.__class__)
print(C.__bases__) #只有一個父類用base,必須用C(型別名),而不是c
print(C.mro()) #必須用C(型別名),而不是c
print(A.__subclasses__) #用型別名
三. 淺拷貝與深拷貝
- 變數的賦值:只是形成兩個變數指向同一物件
- 淺拷貝:物件包含的子物件內容不拷貝,源物件與拷貝物件引用同一子物件
- 遞迴拷貝物件中包含的子物件,源物件與拷貝物件的子物件不同
#測試物件的淺拷貝,深拷貝
import copy #copy要匯入copy包
class MobilePhone:
def __init__(self,CPU,screen):
self.CPU=CPU
self.screen=screen
class CPU:
def calculate(self):
print("算1234567")
print("cpu物件:",self)
class Screen:
def show(self):
print("顯示一個好看的畫面")
print("screen物件:",self)
#測試變數賦值
c1=CPU()
c2=c1
print(c2)
print(c1)
'''地址相同
<__main__.CPU object at 0x000001870105EC48>
<__main__.CPU object at 0x000001870105EC48>
'''
#測試淺複製
s1=Screen()
m1=MobilePhone(c1,s1)
m2=copy.copy(m1)
print(m1,m1.CPU,m1.screen)
print(m2,m2.CPU,m2.screen)
'''
m1和m2不同,cpu和screen相同
<__main__.MobilePhone object at 0x0000018701066088> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
<__main__.MobilePhone object at 0x0000018701066108> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
'''
#測試深複製
m3=copy.deepcopy(m1)
print(m1,m1.CPU,m1.screen)
print(m3,m3.CPU,m3.screen)
'''
都不相同
<__main__.MobilePhone object at 0x0000018701066088> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
<__main__.MobilePhone object at 0x0000018700FE97C8> <__main__.CPU object at 0x0000018700FEB048> <__main__.Screen object at 0x0000018701066148>
'''
四. 組合
is關係用繼承,has關係用組合
#測試組合
#繼承:
class A1:
def say_a1(self):
print("a1,a1,a1")
class A2(A1):
pass
a2=A2()
a2.say_a1()
#組合:
class A1():
def say_a1(self):
print("a1,a1,a1")
class A2:
def __init__(self,a):
self.a=a
a1=A1()
a2=A2(a1) #或直接寫成a2=A2(A1())
a2.a.say_a1()
五. 練習
1. 工廠模式
class CarFactory:
def create_car(self,brand):
if brand=="賓士":
return Benz()
elif brand=="寶馬":
return BMW()
elif brand== "比亞迪":
return BYD()
else:
return "未知品牌,無法建立"
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory=CarFactory()
c1=factory.create_car("賓士")
c2=factory.create_car("寶馬")
print(c1,c2)
2. 單例模式
class MySingleton:
__obj=None #類屬性
def __new__(cls,*args,**kwargs):
if cls.__obj==None:
cls.__obj=object.__new__(cls) #呼叫object類的__new__方法建立物件
return cls.__obj
def __init__(self,name):
print("init...")
self.name=name
a=MySingleton("aa")
b=MySingleton("bb")
print(a)
print(b)
'''建立了一次,但是初始化兩次'''
class MySingleton:
__obj=None #類屬性
__init_flag=True
def __new__(cls,*args,**kwargs):
if cls.__obj==None:
cls.__obj=object.__new__(cls) #呼叫object類的__new__方法建立物件
return cls.__obj
def __init__(self,name):
if MySingleton.__init_flag:
print("init...")
self.name=name
MySingleton.__init_flag=False #不能寫成self.__init_flag
a=MySingleton("aa")
b=MySingleton("bb")
print(a)
print(b)
相關文章
- 面對物件五星好評物件
- 2-Java面試-物件導向Java面試物件
- java面對物件程式設計的概念Java物件程式設計
- 面對物件3-回顧方法的呼叫物件
- 使用 Python 學習面對物件的程式設計Python物件程式設計
- 理解面對物件的六大原則物件
- 面試——談談你對Java 物件導向思想的理解面試Java物件
- 好程式設計師前端教程面對物件與原型原型鏈程式設計師前端物件原型
- Java程式設計__Chap3 面對物件__程式設計題Java程式設計物件
- [寫作中...]Js物件導向(2): 建立物件JS物件
- 對類物件的方法操作物件
- 我對JavaScript物件的理解JavaScript物件
- 物件對映 - Mapping.Mapster物件APP
- canvas Path2D 物件Canvas物件
- 10.物件導向(2)物件
- 實驗2 類和物件物件
- 實驗2 類與物件物件
- 面試2面試
- js對陣列中相同物件元素進行去重,裡面物件相同id,其他不同屬性進行文字疊加JS陣列物件
- “面對面”的網路暴力
- 如何例項化不同頁面物件對應不同的 iframe,而不用頻繁切換物件
- MapStruct 解了物件對映的毒Struct物件
- Javascript - 物件對映automapper介紹JavaScript物件APP
- java物件關係對映ROMJava物件
- 談談我對物件導向以及類與物件的理解物件
- Util應用框架基礎(二) - 物件到物件對映(AutoMapper)框架物件APP
- java物件導向的面試題Java物件面試題
- 一、Java物件導向面試題Java物件面試題
- 面試題:JVM在Java堆中對物件的建立、記憶體結構、訪問方式面試題JVMJava物件記憶體
- 面試題2面試題
- webpack面試2Web面試
- java面試2Java面試
- Mapster 高效能物件對映框架物件框架
- 像物件一樣對待資料物件
- Redis OM .NET Redis物件對映框架Redis物件框架
- 對JavaScript中函式物件的理解JavaScript函式物件
- C# 高效能物件對映C#物件
- 在活動目錄裡面建立物件物件