1. 程式人生 > >菜鳥學Python第二十一天

菜鳥學Python第二十一天

面向物件程式設計

  • 兩種程式設計思想

    • 面向過程:解決問題的步驟,先幹什麼後幹什麼,按照步驟一步一步就解決問題.基於該程式設計思想就好比是在編寫一條流水線,是一種機械式的思維方式.

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

      2. 劣勢:可拓展性差,維護性差. (實現流程是固定的,一旦中間某一個步驟發生變化,將導致整體都需要修改)

      3. 使用場景:對拓展性要求低的軟體,比如系統核心,指令碼等. 但是對於拓展性強的的程式就不再適合該思想程式設計,即產生了面向物件程式設計.

    • 面向物件(OOP : object oriented programming ):物件指的是特徵和技能的結合體(基於其特徵能找到實際物體).基於該思想編寫程式就好比在創造一個世界,你就是這個世界的上帝,是一種上帝的思維方式.

      1. 優勢:

        1. 不用考慮繁瑣的實現步驟 , 從一個流水線思維變成了上帝思維

        2. 可拓展性高(當需要一個新功能時,寫一個具備新功能的物件,命令它去完成任務,各個物件出現問題,不會對其他物件產生影響,可維護性高)

      2. 劣勢 :

        1. 程式設計的複雜度高於面向過程.

        2. 無法準確預知結果

      3. 應用場景: 需要較高的拓展性時,(直接與使用者發生互動的程式例如:微信. qq等).......對於不需要拓展的程式而言,使用面向物件就會增加其複雜度.

  • 為什麼要使用面向物件

    • 在當前市場情況下,百分之九十以上的得程式都需要直接與使用者互動,而使用者的需求千變萬化,所以對程式設計的拓展性要求很高,故我們必須要使用面向物件程式設計.

  • 類與物件

    • 物件: 物件是特徵與技能的結合體(基於其特徵能找到實際對應物件)

    • 類:類是一個抽象的概念,是一系列具有相同某一技能或特徵的的結合體.

    • 現有物件還是先有類:

      • 在現實生活中,一定是先有物件,後來隨著人類文明的發展總結的類,物件是具體存在的,而類只是一種抽象的概念

      • 在程式中,務必先定義類,後呼叫類來產生物件.

        在程式中特徵變數標識,技能函式標識

        因而類中最常見的無非是:變數和函式的定義

class Student:  # 定義類(類名首字母大寫)
    school = 'Tsinghua'  # 相同特徵,變數
    
    def learning():  # 相同技能,函式
        print('learning')
    
stu1 = Student()  # 呼叫類產生物件
print(obj)
​
# 執行結果
#  <__main__.Student object at 0x0000000002648358>
# 解釋以上結果:模組名為main,其中Student類下有一個指定記憶體地址為xxx的物件
print(stu.school)  # 輸出物件的屬性(特徵)
stu.learning()  # 輸出物件的屬性(技能)

 

注意:1.類中可以有任意python程式碼,這些程式碼在定義類的時候便會執行

2.因而會產生新的名稱空間,用來存放類的變數名和函式名,可以通過"類名.__ dict__"檢視

3.對於經典類來說 ,我們可以通過過字典操作類名稱空間的名字,但是python為我們提供了專門的語法.

4.點是訪問屬性的語法,類中定義的名字,都是類的屬性

# 程式中類的用法
#  訪問
1,類名.變數名  # 相當於經典操作"類名.__ dict__['變數名']
2,類名.函式名()  #  相當於經典類操作"類名.__ dict__['函式名']
# 增加
類名.變數名 = 變數值 # Student.classes = '計算機一班'
# 修改
類名.變數名 = 變數值 # 即如同字典的操作,更改已存在的變數(key=新value)
# 刪除
del 類名.函式名
​
​
# 物件的初始化__init__:該方法是在物件產生後才會執行,只用來為物件進行初始化操作,可以有任意程式碼,但是一定不能有返回值
class Student:
    ......
    # 函式的初始化(self一定要有,表示要初始化的物件)
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    ......
    
    
s1 = Student('jason', 23, 'male') # 相當於先呼叫類產生空物件s1,然後呼叫類.__init__(s1,'jason',23,'male')
# 物件的操作,類似於類的操作
# 物件名.變數名.......

屬性查詢與繫結方法

  • 屬性查詢

    類有兩種屬性:資料屬性和函式屬性

    1. 類的資料(變數)屬性是所有物件共享的

    2. 類的函式屬性是繫結給物件用的(obj,method稱為繫結方法,記憶體地址都不一樣)

s1 = Student()
s2 = Student()
​
print(id(Student.school)) # 通過類名.變數名訪問類中資料
print(id(s1.school))  # 通過物件名訪問變數
print(id(s2.school))
​
輸出結果
'''
4377347328
4377347328
4377347328
4377347328
'''
得出結論:類的資料是共享的,id都一致
    
 
print(id(Student.learning)) # 通過類名.函式名訪問類中資料
print(id(s1.learn))  # 通過物件名訪問函式
print(id(s2.learn))
​
輸出結果:
 '''
<function OldboyStudent.learn at 0x1021329d8>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>>
'''
  • 類中屬性查詢的順序:obj.name會先從自己的名稱空間裡找name,找不到則去類中找(類中找不到就去父類中找...最後沒找到就會報錯).

  • 繫結方法
  • 繫結方法:就是將物件或者類與函式進行繫結的方法,這裡的方法指的也就是函式

    物件本質上就是一種存放資料的容器 函式是用於處理資料的程式碼 繫結方法就是將資料與處理資料的函式繫結在一起

  • 為什麼要進行繫結:當沒有進行繫結時

    1. 每次傳遞引數,必須手動傳遞,很有可能傳參順序而發生錯誤

    2. 每次處理資料 都需要手動傳引數

    3. 當要處理的資料特別的多 就不能再定義為變量了 你可以使用列表出來儲存要處理的資料但是 每次處理 都需要先獲取資料 在傳遞給處理資料的函式 所以,繫結過後 可以簡化程式碼,提高效率

      class Student:
          school = "BeiJing"def __init__(self, name, sex, age):
              self.name = name
              self.sex = sex
              self.age = age
      ​
          def learning(self):
              print("正在學習..")
      ​
          def sayHI(self):
              print("hello my name is %s my age:%s my sex:%s" % (self.name,self.age,self.sex))
      ​
          # 預設情況下 在類中定義的函式都是繫結方法,共同點是,都會將物件作為第一個引數self
          
      ​
      stu1 = Student("一個學生","man",18)
      ​
      stu1.sayHI()  # 當用用物件來呼叫類中的方法時,預設把物件傳入方法中
      ​
      Student.sayHI(stu1)  # 而用類名來呼叫時,則需要手動傳入物件
      ​
      ​

      類中定義的函式(沒有被任何裝飾器裝飾的),其實主要是給物件使用的,而且是繫結到物件的,雖然所有物件指向的都是相同的功能,但是繫結到不同的物件就是不同的繫結方法

      強調:繫結到物件的方法的特殊之處在於,繫結給誰就由誰來呼叫,誰來呼叫,就會將‘誰’本身當做第一個引數傳給方法,即自動傳值(方法init也是一樣的道理)

 

  • 繫結給類的方法

    • 繫結的方法包括兩種,常用的是繫結給物件的,另一種是繫結給類的

    class Student:
        school = "Tsinghua"def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    ​
        # 繫結給類的方法 使用一個裝飾器叫classmethod,必須有一個引數,表示當前類,引數名也可以自己定義,建議不要修改
        @classmethod
        def print_school(cls):  # 輸出類裡面叫school的屬性
            print(cls.school)
    ​
        # def print_school2(self):  # 輸出類裡面叫school的屬性
        #     print(self.school)
    # 這是繫結給物件的方法
        def sayHello(self):
            print(self.name, " 說: 你好")
    ​
    ​
    ​
    # Student.print_school_name()
    ​
    Student.print_school()
    • 一個方法到底應該繫結給物件還是幫對給類? 當要處理的資料包含在類中時,就應該繫結給類 當要處理的資料包含在物件中時,就應該繫結給物件

    • 繫結給物件和繫結給類的差別

      • 物件繫結方法 可以使用物件來呼叫 也可以使用類名來呼叫 在物件呼叫時會自動傳入物件自己

      • 類呼叫時不會自動傳參

        類的繫結方法,物件和類都能呼叫,並且都會自動傳入這個類

  • 非繫結方法(瞭解)

class Teacher:
​
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
​
    # @staticmethod 用於定義個非繫結方法
    @staticmethod
    def test_func(num):
        print("test_func run!")
        print(num)
​
Teacher.test_func(1)
​
t1 = Teacher("矮根","")
t1.test_func(100)
print(t1.test_func)
​
​
#  什麼是非繫結方法 再類中 即不繫結給類 也不繫結給物件
#  特點:沒有自動傳引數的效果 ,類和物件向都能呼叫,就是一個普通函式
#  當你的這個功能不需要訪問類的資料 也不需要訪問物件的資料,就可以作為一個非繫結方法
#  使用場景較少