天天看點

Python全棧工程師 (類變量、方法、繼承、覆寫)

ParisGabriel

         每天堅持手寫  一天一篇  決定堅持幾年 為了夢想為了信仰

 

Python全棧工程師 (類變量、方法、繼承、覆寫)

 開局一張圖

                      Python人工智能從入門到精通

補充:

  執行個體方法都是操作執行個體對象的 屬于此類對象的方法

  執行個體變量

    添加/修改屬性:

      對象.屬性名 = 表達式

    删除:

      del 對象.屬性名

      類      |           對象   |     執行個體

      class         object          instance

類的本質上也是對象 類可以建立此類對象

-----------------------------------------------------------------------------------------------------------------

類:

  類變量:

    類變量是類的屬性, 此屬性屬于類, 不屬于此類的執行個體

  作用:

    通常用來儲存該類建立的對象的共同屬性

  說明:

    類變量可以通過該類的執行個體直接通路

    類變量可以通過類的執行個體間接通路

    類變量可以通過此類的對象__class__屬性間接通路

示例:

# -*- coding:utf-8 -*-

# 類變量


class Human:
    total_count = 0  # 類變量

    def __init__(self, name):
        print(name, '對象被建立')


print(Human.total_count)  # 0
h1 = Human("zhang")
print(h1.total_count)  # 0 用此類執行個體通路類變量
h1.total_count = 100  # 為對象添加執行個體變量
print(h1.total_count)  # 100  優先通路執行個體變量
print(Human.total_count)  # 0 通路類變量


class Human:
    total_count = 0  # 類變量

    def __init__(self, name):
        print(name, '對象被建立')


h1 = Human("zhang")
print(Human.total_count)  # 0
h1.__class__.total_count = 100  # 為類添加修改執行個體變量
print(h1.total_count)  # 100  間接通路類變量
print(Human.total_count)  # 100 通路類變量


# 類變量的應用  用類變量記錄執行個體個數


class Human:
    total_count = 0  # 類變量

    def __init__(self, name):
        print(name, '對象被建立')
        self.__class__.total_count += 1  # 每次建立對象調用__init__ 類變量加1

    def __del__(self):
        self.__class__.total_count += 1  # 每次析構對象後類變量減1


h1 = Human("zhang")
print("此時Human對象的個數是", Human.total_count)  # 1
L = []
L.append(Human("li"))
L.append(Human("zhao"))
print("此時Human對象的個數是", Human.total_count)  # 3
del h1
L.pop()
print("此時Human對象的個數是", Human.total_count)  # 1      

類的文檔字元串:

  和函數等一樣

  用__doc__屬性通路

>>> class Dog:
...     '''這是小動物'''
... 
>>> help(Dog)

>>> Dog.__doc__
'這是小動物'
>>>       

類 __slots__ 清單:

    限定一個類的建立執行個體隻能有固定的屬性(執行個體變量)

    不允許對象添加清單以外的屬性(執行個體變量)

    防止使用者因錯寫屬性的名稱而發生錯誤

    1.__slots__ 清單綁定一個字元串清單

    2.含有__slots__清單的類所建立的執行個體對象沒有__dict__屬性

(不用字典儲存對象的屬性 __slots__限制)

  示例:

class Human:
    # 以下清單限制此類對象隻能有這兩個屬性 防止出錯
    __slots__ = ["name", "age"]

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


h1 = Human("Ta", 15)
print(h1.age)  # 15
h1.Age = 18  # 區分大小寫 出錯 沒有Age屬性,也不允許有
print(h1.age)  # 15      

類方法 @ classmethod

  類方法是用于描述類的行為的方法 類方法屬于類, 不屬于類的執行個體

    類方法需要使用  @classmethod 裝飾器定義

    類方法至少有一個形參, 第一個形參用于綁定類, 約定寫“cls”

    類和該類的執行個體都可以調用類的方法

    類方法不能通路此類建立的執行個體的屬性

# 類方法的使用

class A:
    v = 0

    @classmethod
    def get_v(cls):  # cls 用來綁定調用此方法的類
        return cls.v  # 通路類變量

    @classmethod
    def set_v(cls, value):
        cls.v = value


print(A.get_v())  # 0
A.set_v(100)
print(A.get_v())  # 100
a1 = A()  # 建立執行個體
print("a1.get_v=", a1.get_v)  # 100
a1.set_v(200)
print("a1.get_v=", a1.get_v)  # 200
print("A.get_v=", A.get_v)  # 200      

靜态方法 @staticmethod

  靜态方法是定義在類内部的函數, 此函數的作用域是類的内部

  說明:

    靜态方法需要使用 @staticmethod 裝飾器定義

    靜态方法與普通函數定義相同, 不需要傳入self執行個體參數和cls參數

    靜态方法隻能憑借該類的建立執行個體調用

    靜态方法不能通路變量和執行個體變量(屬性)

# 靜态方法

class A:
    @staticmethod
    def myadd(a, b):
        return a + b


print(A.myadd(100, 200))  # 300
a = A()  # 建立執行個體
print(a.myadd(300, 400))  # 700


# def myadd(a, b):  # 和靜态方法結果一樣
#     return a + b


# class A:
#     pass


# print(A.myadd(100, 200))  # 300
# a = A()  # 建立執行個體
# print(a.myadd(300, 400))  # 700      

執行個體方法, 類方法, 靜态方法,函數, 小結:

  1.不想通路 類内 的和 執行個體内 的變量, 用靜态方法

  2.隻想通路類變量, 不想通路執行個體變量, 用類方法

  3.既要通路類變量, 也想通路執行個體變量, 用執行個體方法

  4.函數與靜态方法相同, 隻是靜态方式的作用域定義在類内

繼承inheritance/派生derive:

  什麼是繼承/派生:

  繼承是從已有的類中派生出新的類, 新類具有原類的行為, 并能擴充新的行為

  派生是從已有的類中衍生成新類, 在新類上可以添加新的屬性和行為

  作用:

    用繼承派生機制, 可以将一些共有的功能加在基類中, 實作代碼的共享

    在不改變基類的代碼的基礎上改變原有的功能

  名詞:

    基類(base class) / 超類(super class)/父類(father class)

    派生類(derived class)/子類(child class)

    子類對象一定是父類對象的類型

    父類對象不一定是子類對象的類型

單繼承:

  文法:

    class 類名(基類名)

      語句塊

    單繼承是指由一各基類衍生出新的類

# 單繼承用法


class Human:  # 人類的共性
    def say(srlf, what):
        print("說:", what)

    def walk(self, distance):  # 走路
        print("走了", distance, "公裡")


class Student(Human):  # 繼承
    # def say(srlf, what):
    #     print("說:", what)

    # def walk(self, distance):  # 走路
    #     print("走了", distance, "公裡")

    def study(self, subject):  # 派生
        print("學習", subject)


class Teacher(Student):
    def teach(self, subject):  # 派生
        print("教", subject)


h1 = Human()
h1.say("哈哈")
h1.walk(500)


s1 = Student()
s1.walk(4)
s1.say("666")
s1.study("python")


T1 = Teacher()
T1.walk(4)
T1.say("666")
T1.teach("python")
T1.study("Java")      

繼承說明:

  python3 任何類都可以直接或間接的繼承object類

  object 類是一切類的超類(父類)

  class的繼承參數不寫, 預設繼承object類   一般省略不寫

  object類的超類是None

類的__base__屬性:

  __base__ 屬性用來記錄此類的基類(父類)

Python的内建類:

  help(__builtins__)

覆寫 override

  覆寫是指在有繼承關系的類中, 子類中實作了與基類同名的方法, 在子類

  的執行個體調用該方法時, 實際調用的是子類的覆寫版本, 這種現象叫覆寫

# 覆寫 override


class A:
    def works(self):
        print("A.works被調用")


class B(A):
    '''B繼承A類'''
    def works(self):
        print("B.works被調用")


b = B()
b.works()  # B.works被調用
# B.works 覆寫 A.works 優先調用子類 
# A派生B  B繼承A

# 子類對象顯示調用基類(被覆寫)方法的方式:
#   基類.方法名(執行個體, 實際調用參數)

A.works(b)  # 用類名顯示調用, A.works被調用      

super 函數:

  super(cls, obj)傳回綁定超類的執行個體(要求obj必須是cls類的執行個體)

  super() 傳回綁定超類的執行個體, 等同于:super(__class__),

  執行個體方法的第一個參數), 必須在方法内調用

  作用:

    借助于super()傳回執行個體間接調用其父類的覆寫方法

# 用super函數傳回的對象調用父類的覆寫方法

class A:
    def works(self):
        print("A.works被調用")


class B(A):
    '''B繼承A類'''
    def works(self):
        print("B.works被調用")

    def super_works(self):
        self.works()  # B.works被調用
        super(B, self).works()  # A.works被調用
        super().works()  # A.works被調用

b = B()
b.works()  # B.works被調用
super(B, b).works()  # A.works被調用


b = B()
b.super_works()  # B.works被調用      

顯示調用基類的初始化方法:

  當子類中實作了__init__方法,基類的構造方法不會被調用

  def __init__(self, ...)

# 用super函數調用父類的覆寫__init__初始化方法


class Human:
    def __init__(self, n, a):
        self. name, self.age = n, a
        print("Human類的 __init__ 方法被調用")

    def infos(self):
        print("name:", self.name)
        print("age:", self.age)


class Student(Human):
    def __init__(self, n, a, s=0):
        super().__init__(n, a)  # 用siper 調用父類的__init__方法
        self.score = s  # 添加成績屬性
        print("Student類的 __init__ 方法被調用")

    def info(self):
        super().infos()  # 調用父類的方法
        print("name:", self.name)
        print("age:", self.age)
        print("score:", self.score)  # 不調用父類的方法也不會出錯 但是盡量不要用


s1 = Student("小張", 20)
s1.infos()