1. 多型
1.1 概念
多型指的是一類事物有多種形態
比如動物有多種形態:人、猴、鴨
1.2 程式碼示例
from abc import ABC, abstractmethod
# 對於程式來說,定義一個基類可以有多個子類
class Animal(ABC):
@abstractmethod
def run(self):
pass
@abstractmethod
def speak(self, name):
print(f'{name}正在說話')
# 第一種形態:人
class Person(Animal):
def run(self):
print('可以潤')
def speak(self, name):
print(f'{name}正在說話')
# 第二種形態:猴
class Monkey(Animal):
def run(self):
print('猴哥也可以潤')
# 第三種形態:鴨子
class Duck(Animal):
def run(self):
print('鴨子也可以潤')
1.3 多型性
動態繫結:在程式執行的過程中,根據物件的型別,動態的將方法進行繫結
動態多樣性:動態繫結在繼承背景下的特性就叫動態多型性
靜態多樣性:如任何型別都可以用運算子加號+ 進行運算
from abc import ABC, abstractmethod
# 同一類事物:動物
class Animal(ABC):
@abstractmethod
def run(self):
pass
# 第一種形態:人
class Person(Animal):
def run(self):
print('可以潤')
# 第二種形態:猴
class Monkey(Animal):
def run(self):
print('猴哥也可以潤')
# 第三種形態:鴨子
class Duck(Animal):
def run(self):
print('鴨子也可以潤')
person1 = Person()
monkey1 = Monkey()
duck1 = Duck()
# person1、monkey1、duck1都是動物,只要是動物肯定有run方法
# 於是可以不用考慮三個物件的具體是宣告型別,而直接使用
person1.run()
monkey1.run()
duck1.run()
# 更進一步,可以定義一個統一的介面來使用
def func(obj):
obj.run()
python中一切皆物件,本身就支援多型性
# 在不考慮物件型別的情況下統計物件的長度
a.__len__()
b.__len__()
c.__len__()
# python內建了一個統一的介面
len(a)
len(b)
len(c)
2. 鴨子型別
鴨子型別(duck typing)是一種程式設計風格,不是一個真實存在的約束關係,是一種普遍的規範
看起來像、聲音像、走起路來像鴨子,那麼它就是鴨子
# 二者看起來都像檔案,因而就可以當檔案一樣去用,然而它們並沒有直接的關係
class Txt: # Txt類有兩個與檔案型別同名的方法,即read和write
def read(self):
pass
def write(self):
pass
class Video: # Video類也有兩個與檔案型別同名的方法,即read和write
def read(self):
pass
def write(self):
pass
3. 繫結方法和非繫結方法
3.1 概念
繫結方法(動態方法):
繫結給誰,誰來呼叫就自動將它本身當作第一個引數傳入
繫結給類的方法、繫結給物件的方法
非繫結方法(靜態方法):
既不繫結給類也不繫結給物件
一句話概括:方法即函式,可以理解為繫結函式、非繫結函式
3.2 繫結給物件的方法
概述:
繫結給物件的方法就是在類內部直接定義的方法------即在類內部寫的函式,寫的時候自動帶上self引數
特點就是會自動補全self引數
物件呼叫繫結給物件的方法的時候不需要傳入self引數,類呼叫物件的繫結方法的時候需要傳入self引數(物件名)
class Student:
def __init__(self, name):
self.name = name
def run(self): # 繫結給物件的方法就是在類內部定義的方法,自動補全self物件
print(f'這是run方法,{self.name}可以潤')
stu1 = Student(name='lavigne') # 例項化得到的物件
# (1)物件呼叫物件的繫結方法
# 不需要傳遞self引數,在物件呼叫物件的繫結方法的時候會自動將物件作為self引數傳進去
stu1.run() # 這是run方法,lavigne可以潤
# (2)類呼叫物件的繫結方法
# 必須主動給self傳入一個物件
stu2 = Student(name='avril')
# Student.run() # 報錯 TypeError: Student.run() missing 1 required positional argument: 'self'
Student.run(stu1) # 這是run方法,lavigne可以潤
Student.run(stu2) # 這是run方法,avril可以潤
3.3 繫結給類的方法 classmethod
類在使用時會將類本身當作引數傳給類方法的第一個引數(即便是物件來呼叫也會將類當作第一個引數傳入)
classmethod把類中的函式定義成類方法
class Student:
def __init__(self, name):
self.name = name
@classmethod
def read(cls): # 繫結給類的方法,必須用classmethod裝飾器,並且在定義函式的時候預設補全引數cls
print(f'當前是繫結給類的read方法:{cls}')
# (1)物件呼叫繫結給類的方法
# 不需要傳入cls引數
# 會自動識別例項化當前物件的類,直接將類傳入
stu1 = Student(name='lavigne')
stu1.read() # 當前是繫結給類的read方法:<class '__main__.Student'>
# (2)類呼叫繫結給類的方法
# 不需要傳入cls引數
# 預設將當前類作為cls的預設引數傳入
Student.read() # 當前是繫結給類的read方法:<class '__main__.Student'>
總結:
定義繫結給類的方法的時候,必須用裝飾器@classmethod;類似於繫結給物件的方法函式,會自動補全引數cls
物件呼叫繫結給類的方法,不需要傳入cls引數
類呼叫繫結給類的方法,不需要傳入cls引數
3.4 非繫結方法 staticmethod
在類內部用staticmethod裝飾的函式即非繫結方法,就是普通函式
staticmethod既不繫結給類,也不繫結給物件,在定義函式的時候和普通函式一樣不會補全任何預設引數