面向對象:編程範式、類、對象

編程範式:編程

1. 面向過程編程: 核心是「過程」,「過程」指的是解決問題的步驟;就至關於在設計一條流水線app

    優勢:複雜問題流程化,進而簡單化ide

  缺點:可擴展性差,前一發動全身函數

2. 面向對象:核心是「對象」,對象就是特徵與技能的結合體spa

 優勢: 可擴展性強設計

    缺點: 編程複雜度高code

 應用場景: 用戶需求常常變化,如:互聯網應用、遊戲、企業內部應用對象

類: blog

類就是一系列對象類似的特徵與技能的結合體(至關於一個模板),特徵用變量表示,技能用函數表示繼承

強調: 站在不一樣的角度,獲得的分類是不同的

在程序中: 必定是先定義類,後調用類產生對象 

定義類、產生對象的方法以下:

"""定義類"""
class Student:  #  類的首字母大寫
    school = "Luffycity"  

    def learn(self):   
        print("is learning")

    def eat(self):
        print("is eating")

    def sleep(self):
        print("is sleeping")

"""調用類產生對象"""
stu1 = Student()   #  Student() 不是執行類體的代碼,而是獲得一個返回值,這個返回值就是產生的對象;這個過程也叫「實例化」
stu2 = Student()   #  類名調用一次就是實例化一次
stu3 = Student()

print(stu1)
print(stu2)
print(stu3)

#  輸出結果:
#  <__main__.Student object at 0x0000001F205C6438>
#  <__main__.Student object at 0x0000001F205C66D8>
#  <__main__.Student object at 0x0000001F205C6668>

 

類的使用:

定義類時,在類定義階段它內部的代碼就可以運行,以下:

class Student:  #  類的首字母大寫
    school = "Luffycity"  # 特徵
    print("test")

    def learn(self):   # 技能
        print("is learning")

    def eat(self):
        print("is eating")

    def sleep(self):
        print("is sleeping")

#  運行結果:
#  test 

查看類裏面的名稱空間:

class Student:  #  類的首字母大寫
    school = "Luffycity"  # 類的數據屬性

    def learn(self):   # 類的函數屬性
        print("is learning")

    def eat(self):
        print("is eating")

    def sleep(self):
        print("is sleeping")


print(Student.__dict__)
print(Student.__dict__["school"])
print(Student.__dict__["learn"])
"""查看""" print(Student.school) print(Student.learn) """類定義完後增長屬性""" Student.country = "China" # 往Student這個類裏面增長了 country = "China" print(Student.__dict__) print(Student.country) """刪除""" del Student.country print(Student.__dict__) """修改""" Student.country = "Greater China" print(Student.country) # 打印結果: # {'__module__': '__main__', 'school': 'Luffycity', 'learn': <function Student.learn at 0x000000711C26B9D8>, 'eat': <function Student.eat at 0x000000711C26BA60>, 'sleep': <function Student.sleep at 0x000000711C26BD90>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None} # Luffycity # <function Student.learn at 0x000000711C26B9D8> # Luffycity # <function Student.learn at 0x000000711C26B9D8> # {'__module__': '__main__', 'school': 'Luffycity', 'learn': <function Student.learn at 0x000000711C26B9D8>, 'eat': <function Student.eat at 0x000000711C26BA60>, 'sleep': <function Student.sleep at 0x000000711C26BD90>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None, 'country': 'China'} # China # {'__module__': '__main__', 'school': 'Luffycity', 'learn': <function Student.learn at 0x000000711C26B9D8>, 'eat': <function Student.eat at 0x000000711C26BA60>, 'sleep': <function Student.sleep at 0x000000711C26BD90>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None} # Greater China

 

類內部定義的變量是類的數據屬性 ,定義的函數是其函數屬性

類的用途:

  1. 對屬性的操做

  2. 實例化產生一個個對象 (利用  Student() 方法)

 

對象的使用方法:

利用 init 方法來爲對象定製本身獨有的特徵

class Student:
    school = "Luffycity"

    def __init__(self,name,gender,age):  #  實例化的時候就會自動調用 __init__函數
        self.Name = name
        self.Gender = gender
        self.Age = age   # 字典形式

        """
        stu1.Name = "蒼老師"
        stu1.Gender = "女"
        stu1.Age = 18
        """
    def learn(self):
        print("is learning")
    def eat(self):
        print("is eating")
    def sleep(self):
        print("is sleeping")

stu1 = Student("蒼老師","",18)
stu2 = Student("武藤蘭","男",38)
""" 有__init__函數時的實例化步驟: 1. 先產生一個空對象stu1(不帶本身獨特屬性的對象) 2. 觸發__init__函數,觸發方式爲:Student.__init__() , 這是一個函數,就須要按照函數的方式進行傳參,即: Student.__init__(stu1,name,gender,age) (第一步生成的對象stu1傳入self的位置) Student.__init__(stu1,name,gender,age) 產生的效果如__init__函數中的註釋所示。 (添加獨有屬性後,對象的內存地址不變)
3. 返回 帶本身獨特屬性的對象stu1
""" """ stu1 = Student("蒼老師","女",18) 這是在給一個對象定製一個屬性,與類添加屬性一個道理,往對象裏面添加屬性也涉及到名稱空間的變更,只不過這個名稱空間是stu1的名稱空間(由於是往stu1這個對象裏面添加的新屬性) """ print(stu1.__dict__) # 打印結果: # {'Name': '蒼老師', 'Gender': '女', 'Age': 18} """ 經過__init__的方法, stu1這個對象不但擁有類共有的那些特徵和技能,而且也有了本身獨有的屬性""" """查看""" print(stu1.Name) print(stu1.Gender) # 打印結果: # 蒼老師 # """""" stu1.Name = "蒼井空" print(stu1.__dict__) print(stu1.Name) # 打印結果: # {'Name': '蒼井空', 'Gender': '女', 'Age': 18} # 蒼井空 """增長""" stu1.job = "adult video" print(stu1.__dict__) print(stu1.job) # 打印結果: # {'Name': '蒼井空', 'Gender': '女', 'Age': 18, 'job': 'adult video'} # adult video """刪除""" del stu1.job print(stu1.__dict__) # 打印結果: # {'Name': '蒼井空', 'Gender': '女', 'Age': 18}

類中的數據屬性是全部對象共有的;

類中的函數屬性:是綁定給對象使用的,並且綁定到不一樣的對象是不一樣的綁定方法

還以上面的代碼爲例:

print(Student.school,id(Student.school))
print(stu1.school,id(stu1.school))

# 打印結果:
# Luffycity 586247585648
# Luffycity 586247585648

"""類中的數據屬性是全部對象共有的,用的都是同一塊內存地址"""

"""類中的函數屬性:是綁定給對象,並且綁定到不一樣的對象是不一樣的綁定方法"""

print(Student.learn)
print(stu1.learn)
print(stu2.learn)

# 打印結果: (函數的內存地址也不同)
# <function Student.learn at 0x0000005FB155BA60> # 類名.功能名 是一個函數的內存地址,就是一個函數,那就按函數的方法去執行,並且函數不會自動傳參的
# <bound method Student.learn of <__main__.Student object at 0x0000005FB15667B8>> # 對象.功能名是一種綁定方法,因此可以自動傳參
# <bound method Student.learn of <__main__.Student object at 0x0000005FB15667F0>> # 功能跟不一樣對象的綁定方法不同
 

 

把上述例子中類的代碼稍微修改,以下:

class Student:
    school = "Luffycity"

    def __init__(self, name, gender, age):  # 實例化的時候就會自動調用 __init__函數
        self.Name = name
        self.Gender = gender
        self.Age = age  # 字典形式

    def learn(self):
        print("%s is learning" % self.Name)

    def eat(self):
        print("%s is eating" % self.Name)

    def sleep(self):
        print("%s is sleeping" % self.Name)


stu1 = Student("蒼老師", "", 18)
stu2 = Student("武藤蘭","",38)

 

調用 Student.learn() 函數的方法:(此函數需傳入參數)

Student.learn(stu1)   # Student.learn()就是一個普通的函數,因此能夠利用函數的調用方式去執行它;函數的參數要傳入上一步產生的stu1, 由於在類中定義learn()函數時,裏面有參數self


# 執行結果:
# 蒼老師 is learning

 

調用stu1.learn()函數的方法: (此函數無需傳入參數,由於learn功能只需傳入參數self,而stu1會自動傳入self)

"""調用stu1.learn()函數"""
stu1.learn()   # 這個函數調用的是類Student下的learn的功能,stu1會做爲參數自動傳入到self這個形參中 # 執行結果:
# 蒼老師 is learning

 

即: 類中的函數屬性是綁定給對象使用的,綁定到不一樣的對象是不一樣的綁定方法,對象調用綁定方式時,會把對象自己當作第一個參數,傳入self

類中定義的功能(即 函數)是給對象使用的(綁定給對象使用的),並且是哪一個對象來調用就把哪一個對象做爲參數自動傳入到self中(這是 綁定關係),這樣 哪一個對象在調用就是哪一個對象在執行類中的功能;類若是本身使用還須要本身傳入對象(傳入到self中),會比較笨拙

對象只存放本身獨有的特徵,類似的特徵都放在類裏面;這涉及到對象的屬性查找問題,若是對象中的屬性跟類中的屬性重名,則以對象中的屬性爲準(相似於函數中變量的先局部後全局)(例外,屬性不會去全局裏面找,由於你是在調用類,或者說這是類的調用)

"""有重名"""
stu1.x = "CN"
Student.x = "中國"

print(stu1.x)
print(Student.x)

# 打印結果:
# CN
# 中國

"""無重名時,對象調用類中的"""
Student.x = "中國"

print(stu1.x)
print(Student.x)

# 打印結果:
# 中國
# 中國

補充說明1:

  1. 站在不一樣角度,定義出的類是不一樣的

  2. 現實中的類並不徹底等同於程序中的類,好比現實中的公司類,在程序中有時需拆分紅部門類、業務類等

  3. 有時爲了變成需求,程序中可能會定義現實中不存在的類,好比策略類,現實中不存在,但在程序中是一個很常見的類

補充說明2:

  Python中一切皆對象,而且在Python3中統一了類與類型的概念 

class Student:
    school = "Luffycity"

    def __init__(self, name, gender, age):  # 實例化的時候就會自動調用 __init__函數
        self.Name = name
        self.Gender = gender
        self.Age = age  # 字典形式

    def learn(self):
        print("%s is learning" % self.Name)

    def eat(self):
        print("%s is eating" % self.Name)

    def sleep(self):
        print("%s is sleeping" % self.Name)


print(type([1,2]))
print(list)    # [1,2] 和 list是Python中的列表這個數據類型
print(Student)   # Student 是咱們本身建立的類


# 打印結果:
# <class 'list'>
# <class 'list'>
# <class '__main__.Student'>

""" Python3中統一了類與類型的概念 """

# 站在類的角度考慮下面已學過的知識
list1 = [1,2,3]   #  這種方法的本質是 list1 = list([1,2,3])  即 調用list這個類並傳入參數[1,2,3],進而產生list1這個對象,而且[1,2,3]放入到了list1的命名空間中; list1中獨有的特徵就是[1,2,3]
list2 = []   # 同理, list2 = list()


list1.append(4)  # 這行代碼的含義是:list1這個對象調用了list這個類下面的 append() 這個功能(函數)。
print(list1)
"""
list1.append(4) 其實就至關於 list.append(list1,4)
即 list這個類調用其內部的append()函數,並把list1這個對象傳入到self這個形參中
"""
list.append(list1,5)
print(list1)

# 打印結果:
# [1, 2, 3, 4]
# [1, 2, 3, 4, 5]

list2.append(1)  # list2.append(1) : 添加的1只能添加到list2中,不會添加到list1中,由於是list2這個對象在調用append(1)這個功能
print(list2)

#  打印結果:
#  [1]

"""因此,在Python中一切皆對象"""

 

可擴展性:

  使用類能夠將數據與專門操做該數據的功能捆綁在一塊兒

 

例題1:

  編寫一個學生類,產生多個學生對象

  要求: 有一個計數器(屬性),統計總共實例化了多少個對象

代碼以下:

class Student:
    school = "luffycity"
    count = 0

    def __init__(self,name,gender,age):
        self.name = name
        self.gender = gender
        self.age = age

        # self.count += 1  # 這種方式是不可行的,由於每次添加count時都添加到了對象的特有屬性裏面,再產生下一個對象時,新產生的對象並不知道上一個對象count的值是多少;並且因爲 __init__ 裏面沒有對 count 這個變量賦值,因此 self.count 會向類的公共屬性裏面去尋找count 的值

        """正確寫法"""
        Student.count += 1   # 在 __init__函數裏面對類Student的公共屬性count進行處理;count變量並無添加到對象命名空間中(沒有添加到對象的獨有屬性中),count一直都是在類Student的命名空間裏

    def learn(self):
        print("%s is learning" %self.name)

"""
分析要求: 每次實例化都會觸發 __init__ 函數,因此能夠考慮在 __init__ 上進行計數
首先在類的公共屬性上添加一個 count = 0 
"""
stu1 = Student("neo","male",18)
stu2 = Student("蒼老師","female",16)
stu3 = Student("美奈子","female",17)

print(stu1.count)  # 此時的 stu1.count 調用的是類 Student中的變量count,stu1中是沒有count這個變量的
print(stu2.count)
print(stu3.count)
print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)

print(Student.count)

# 打印結果:
# 3
# 3
# 3
# {'name': 'neo', 'gender': 'male', 'age': 18}
# {'name': '蒼老師', 'gender': 'female', 'age': 16}
# {'name': '美奈子', 'gender': 'female', 'age': 17}
# 3

 例題二:

  模仿LOL定義兩個英雄類  

  要求:

    英雄須要有暱稱、攻擊力、生命值等屬性

    實例化出兩個英雄對象

    英雄之間能夠互毆,被打的一方掉血,血量小於0則斷定爲死亡

如下是本身寫的:(只定義了一個英雄類)

class Hero:

    def __init__(self,name,attack,life):
        self.name = name
        self.attack = attack
        self.life = life

    def fighted(self,attacked = 0):
        self.life -= attacked
        if self.life <= 0:
            print("%s is dead" %self.name)
        else:
            print("%s is alive" %self.name)

kasaa = Hero("卡薩丁",1000,2000)
kayle = Hero("凱爾",1300,1500)

kayle.fighted(kasaa.attack)
kayle.fighted(kasaa.attack)

 

示例代碼:

class Garen:
    camp = "Demacia"

    def __init__(self,nickname,attack,life):
        self.nickname = nickname
        self.attack = attack
        self.life = life

    def attacking(self,enemy):
        enemy.life -= self.attack


class Riven:
    camp = "Noxus"

    def __init__(self,nickname,attack,life):
        self.nickname = nickname
        self.attack = attack
        self.life = life

    def attacking(self,enemy):
        enemy.life -= self.attack

garen = Garen("草叢倫",30,100)
riven = Riven("瑞雯雯",50,80)

print(riven.life)
garen.attacking(riven)   # 英雄(對象)之間的交互
print(riven.life)

# 運行結果
# 80
# 50

 

上述代碼中有大量重複的代碼,利用「繼承」來解決。(轉下篇文章)

相關文章
相關標籤/搜索