1. 程式人生 > >python 面向對象(初級篇)

python 面向對象(初級篇)

特色 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 面向對象(初級篇)