python 面向對象(初級篇)
阿新 • • 發佈:2018-03-19
特色 args print 顯式 super關鍵字 通過 模板 輸入 racket
面向對象和面向過程
知乎上有句回答 : 面向過程是編年體;面向對象是紀傳體 # 不知道會不會被告侵權 侵刪哈23333333
- 面向過程:用一對代碼從開始到結束描述整個任務完成的過程.
- 比如你要寫一個格鬥遊戲
- 首先描述擂臺場景
- 描述一個角色出現,另一個角色出現
- 再描述兩個角色的外形 , 比如體型服裝性別特征等等
- 兩個人擺好架勢等待用戶輸入
- while 用戶輸入>>做一次判斷>>角色執行對應的動作......
- 面向對象:把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為
- 同樣是格鬥遊戲
- 擂臺對象,描述擂臺場景的構成
- 角色對象,描述任務外形技能等
- 規則對象,對比賽進行判定
類和對象
創建類和對象
類就是一個模板,模板裏包含一類事物的共同特征,同時包含多個函數,函數裏實現一些功能
對象則是根據模板創建的實例,具化類的特征,通過實例對象可以執行類中的函數
# 創建類 class Foo: # 創建類中的函數 def func(self): pass # 根據類Foo創建對象obj obj = Foo()
- class 關鍵字 表示創建類
- Foo 類名
- 創建對象,類名後邊加括號即可
- 註釋 類中定義的函數一般叫方法,方法的第一個參數必須是 self 稍後會講解
面向對象的三大特性
封裝
""" 封裝 是對具體對象的一種抽象,即將某些部分隱藏起來,在程序外部看不到,其含義是其他程序無法調用 封裝可以被認為是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問,要訪問該類的代碼和數據,必須通過嚴格的接口控制 封裝最主要的功能在於我們能修改自己的實現代碼,而不用修改那些調用我們代碼的程序片段 適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。 """ class Foo1: def __init__(self,name,age,face_value): """ 構造方法,根據類創建對象時自動執行 :param name: :param age: :param face_value:""" self.name = name self.age = age self.face_value = face_value def foo(self): # 類中的方法需要通過self間接調用被封裝的內容 print(self.name) # 將 ‘nathaniel‘,‘19‘,‘Men of God‘ 封裝到obj的 name,age,face_score 屬性中 obj = Foo1(‘nathaniel‘,‘19‘,‘Men of God‘) # self是一個形式參數,默認等於根據類創建的對象 # obj0 = Foo1(‘nathaniel‘,‘19‘,‘Men of God‘) self等於obj0 # obj1 = Foo1(‘nathaniel‘,‘19‘,‘Men of God‘) self等於obj1 # 所以,內容其實是被封裝在了對象當中,每個對象都具有創建它們的類的屬性,並且可以有自己不同的值 # 以上就封裝好了,接下來調用 print(obj.name) # 通過對象直接調用類中的屬性 obj.foo() # 調用類中的方法 class Person: """ 小遊戲 1、創建三個遊戲人物,分別是: 蒼井井,女,18,初始戰鬥力10000 瀧澤蘿沙,女,20,初始戰鬥力8000 波多多,女,22,初始戰鬥力8100 2、遊戲場景,分別: 草叢大作戰,消耗200戰鬥力 冥想修煉,增長100戰鬥力 蒼穹對決,消耗500戰鬥力 """ def __init__(self,name,gender,age,fight): self.name = name self.gender = gender self.age = age self.fight = fight def grassland(self): """ 草叢大作戰,消耗200戰鬥力 :return: """ self.fight = self.fight - 200 def meditation(self): """ 冥想修煉,增長100戰鬥力 :return: """ self.fight = self.fight + 100 def sky_duel(self): """ 蒼穹對決,消耗500戰鬥力 :return: """ self.fight = self.fight - 500 def show(self): """ 展示遊戲人物當前狀態 :return: """ temp = "姓名:%s ; 性別:%s ; 年齡:%s ; 戰鬥力:%s" % (self.name, self.gender, self.age, self.fight) print(temp) cjk = Person(‘蒼井井‘, ‘女‘, 18, 10000) # 創建蒼井井角色 lzl = Person(‘瀧澤蘿沙‘, ‘女‘, 18, 8000) # 創建瀧澤蘿沙角色 bdd = Person(‘波多多‘, ‘女‘, 18, 8100) # 創建波多多角色 cjk.sky_duel() # 蒼井井進行了一次蒼穹對決 lzl.meditation() # 瀧澤蘿沙進行了一次冥想修煉 bdd.grassland() # 波多多進行了一次草叢大作戰 # 展示遊戲人物當前狀態 cjk.show() lzl.show() bdd.show()
繼承
""" 繼承 子類可以繼承父類,父類中的屬性和方法,子類可以直接使用 舉個栗子 狗:"汪汪"叫,吃喝拉撒 貓:"喵喵"叫,吃喝拉撒 他們都繼承動物類的屬性 """ class Animal: def __init__(self,weight): self.weight = weight def action(self): print(‘吃喝拉撒‘) class Dog(Animal): # Dog類繼承Animal類 def __init__(self,name): self.name = name # 子類可以都自己的特色 def voice(self): print(‘汪汪汪‘) class Cat(Animal): # Cat類繼承Animal類 def __init__(self,name): self.name = name # 子類可以都自己的特色 def voice(self): print(‘喵喵喵‘) dog = Dog(‘大黃‘) dog.voice() # 子類可以調用自己的方法 dog.action() # 也可以調用父類的方法 cat = Cat(‘小黑‘) cat.voice() # 子類可以調用自己的方法 cat.action() # 也可以調用父類的方法 print(‘233‘) # 那麽問題來了,創建子類的對象,父類中的構造方法沒有被執行,怎麽辦? class Pig(Animal): def __init__(self,name,weight): self.name = name # 通過super關鍵字執行父類中的構造方法 super(Pig,self).__init__(weight) # 也可以執行父類中的其他方法 super(Pig,self).action() # 子類可以都自己的特色 def voice(self): print(‘哼唧哼唧‘) pig = Pig(‘阿花‘,300) print(‘有趣的阿花%s多斤‘% pig.weight)
ok,現在你學會了繼承,再來看個變態的東西----多繼承
類有新式類和經典類之分,從寫法上區分,如果 當前類或者父類繼承了object類,那麽該類便是新式類,否則便是經典類
- 當類是經典類時,多繼承情況下,會按照深度優先方式搜索
- 當類是新式類時,多繼承情況下,會按照廣度優先方式搜索
Python 2.x中默認都是經典類,只有顯式繼承了object才是新式類
Python 3.x中默認都是新式類,不必顯式的繼承objec
class S0: def func(self): print("This is from S0") class S(S0): def __init__(self): pass class S1(S): def __init__(self): pass class S2(S0): def __init__(self): pass def func(self): print("This is from S2") class S3(S1,S2): def __init__(self): pass obj = S3() obj.func()
執行上述代碼
經典類的答案: This is from S0
新式類的答案: This is from S2
# 一個子類能否繼承多個類 (爸爸媽媽爺爺奶奶叔叔伯伯 # 如果繼承的多個類每個類中都定義了相同的函數,那麽那一個會被使用呢 class S: def show(self): print(‘S‘) def show1(self): print(‘S‘) class S1(S): def show(self): print(‘S1‘) class S2: def show(self): print(‘S2‘) def show1(self): print(‘S2‘) class S22(S): def show(self): print(‘S22‘) def show1(self): print(‘S22‘) class S3(S1,S2): pass class S4(S1,S22): pass obj = S3() obj.show() # 廣度優先 S4().show1() # 廣度優先
多態
對於Java、C#來說 ,創建一個變量必須指定它的數據類型
public static void main(String[] args) {}; Java定義一個方法,指定了變量類型String類,如果賦值不是String類就會報錯
public static void main(Foo[] args) {}; 也可以自己寫一個類Foo類,Foo類有眾多子類,那麽賦值類型就可以是Foo類或其子類中的任意一個
而python則沒有這種限制,因為python原生多態
def func(*args):pass
變量可以是任意類型
# 有興趣的小夥伴可以研究下這段代碼,emmmmmm print("******多繼承使用類名.__init__ 發生的狀態******") class Parent(object): def __init__(self, name): print(‘parent的init開始被調用1‘) self.name = name print(‘parent的init結束被調用2‘) class Son1(Parent): def __init__(self, name, age): print(‘Son1的init開始被調用3‘) self.age = age Parent.__init__(self, name) print(‘Son1的init結束被調用4‘) class Son2(Parent): def __init__(self, name, gender): print(‘Son2的init開始被調用5‘) self.gender = gender Parent.__init__(self, name) print(‘Son2的init結束被調用6‘) class Grandson(Son1, Son2): def __init__(self, name, age, gender): print(‘Grandson的init開始被調用7‘) Son1.__init__(self, name, age) # 單獨調用父類的初始化方法 Son2.__init__(self, name, gender) print(‘Grandson的init結束被調用8‘) print(Grandson.__mro__) gs = Grandson(‘grandson‘, 12, ‘男‘) print(‘姓名:‘, gs.name) print(‘年齡:‘, gs.age) print(‘性別:‘, gs.gender) print("******多繼承使用類名.__init__ 發生的狀態******\n\n") # ---------------------------------------------------- print("******多繼承使用super().__init__ 發生的狀態******") class Parent(object): def __init__(self, name, *args, **kwargs): # 為避免多繼承報錯,使用不定長參數,接受參數 print(‘parent的init開始被調用1‘) self.name = name print(‘parent的init結束被調用2‘) class Son1(Parent): def __init__(self, name, age, *args, **kwargs): # 為避免多繼承報錯,使用不定長參數,接受參數 print(‘Son1的init開始被調用3‘) self.age = age super().__init__(name, *args, **kwargs) # 為避免多繼承報錯,使用不定長參數,接受參數 print(‘Son1的init結束被調用4‘) class Son2(Parent): def __init__(self, name, gender, *args, **kwargs): # 為避免多繼承報錯,使用不定長參數,接受參數 print(‘Son2的init開始被調用5‘) self.gender = gender super().__init__(name, *args, **kwargs) # 為避免多繼承報錯,使用不定長參數,接受參數 print(‘Son2的init結束被調用6‘) class Grandson(Son1, Son2): def __init__(self, name, age, gender): print(‘Grandson的init開始被調用7‘) # 多繼承時,相對於使用類名.__init__方法,要把每個父類全部寫一遍 # 而super只用一句話,執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因 # super(Grandson, self).__init__(name, age, gender) super().__init__(name, age, gender) print(‘Grandson的init結束被調用8‘) print(Grandson.__mro__) gs = Grandson(‘grandson‘, 12, ‘男‘) print(‘姓名:‘, gs.name) print(‘年齡:‘, gs.age) print(‘性別:‘, gs.gender) print("******多繼承使用super().__init__ 發生的狀態******\n\n")
python 面向對象(初級篇)