1. 程式人生 > 其它 >[AI Studio] 飛槳PaddlePaddle Python零基礎入門深度學習筆記<五>

[AI Studio] 飛槳PaddlePaddle Python零基礎入門深度學習筆記<五>

技術標籤:paddlepaddle飛槳筆記python多型

[AI Studio] 飛槳PaddlePaddle Python零基礎入門深度學習筆記<五>

新需求


橄欖球教練Roger,拿出了自己的資料結構,我們的隊員除了速度訓練,還需要進行力量的練習。既然你的類表現的不錯,我能不能用呢?
loren,2011-11-3,270,3.59,4.11,3:11,3:23,4-10,3-23,4:10,4.21,4-21

首先我們複習一下昨天的部分
第一我們先開啟檔案,讀取Roger教練記錄的資料,這需要一個函式

def get_coach_data(filename):
    with
open(filename) as f: line = f.readline() return line.strip().split(',')

為了方便處理多人資料,我們學習了一個新的概念,

class Athlete:
    def __init__(self,a_name,a_dob=None,a_times=[]):
        self.name = a_name
        self.dob = a_dob
        self.times = a_times
    def top3(self):
        return sorted
(set([self.sanitize(t) for t in self.times]))[0:3] def sanitize(self,time_string): if '-' in time_string: splitter = '-' elif ':' in time_string: splitter = ':' else: return (time_string) (mins,secs) = time_string.split(splitter)
return (mins+'.'+secs)

在以上程式碼中
類的主體結構是

class 類名:
	def __init__(self,引數1,引數2,etc.):
		self.屬性名 = 引數1
		self.屬性名 = 引數2
	def 方法名(self,引數1,引數2,etc.):
		#方法內容
		return #return並不是必須的部分,但方法要有內容
  1. 例項化後 類內方法可以呼叫類內方法,例如top3()方法中呼叫了
    self.sanitize(t)
    return sorted(set([self.sanitize(t) for t in self.times]))[0:3]
  2. 設定屬性名時,在類內部呼叫方法時,都要在前加
    self.
    return sorted(set([self.sanitize(t) for t in self.times]))[0:3]
  3. 千萬不要遺漏類名後、方法後的冒號!

一,繼承

來看看如何完成Roger教練的新需求吧,一樣為了快速處理大量資料,我們需要一個類來作為資料模板,但是和昨天不同的是,明顯Athlete類已經不能滿足我們的需求了,但難道要再打一段很長很長的Rugby類嗎?

class Rugby:
    def __init__(self,a_name,a_dob=None,a_times=[],a_squat):
        self.name = a_name
        self.dob = a_dob
        self.times = a_times
        self.squat = a_squat
    def top3(self):
        return sorted(set([self.sanitize(t) for t in self.times]))[0:3]
    def sanitize(self,time_string):
        if '-' in time_string:
            splitter = '-'
        elif ':' in time_string:
            splitter = ':'
        else:
            return (time_string)
        (mins,secs) = time_string.split(splitter)
        return (mins+'.'+secs)

明顯程式碼重複性太高了,完全不符合簡潔性,所以我們需要使用繼承
Athlete類就是父類
Rugby類就是子類
子類繼承了父類所有的屬性和方法,同時子類還可以擁有更多的屬性和方法

#定義橄欖球運送員類
class Rugby(Athlete):
    def __init__(self,a_name,a_bod,a_squat,a_times):
        #呼叫父類__init__
        Athlete.__init__(self,a_name,a_bod,a_times)
        #深蹲次數
        self.squat = a_squat
    # 繼承後下面兩個函式就在Rugby類中,只是看不到而已
    # def top3(self):
    #     return sorted(set([self.sanitize(t) for t in self.times]))[0:3]
    # def sanitize(self,time_string):
    #     if '-' in time_string:
    #         splitter = '-'
    #     elif ':' in time_string:
    #         splitter = ':'
    #     else:
    #         return (time_string)
    #     (mins,secs) = time_string.split(splitter)
    #     return (mins+'.'+secs)

如果這樣,只需要四行程式碼就可以繼承Athlete的所有內容,外加一個新的屬性squat

loren = get_coach_data('mywork/loren.txt')
rugby = Rugby(loren.pop(0),loren.pop(0),loren.pop(0),loren)
print('姓名:%s,生日:%s,深蹲:%s個,最塊的3次成績:%s' %(rugby.name,rugby.dob,rugby.squat,rugby.top3()))

將Rugby類例項化後測試繼承結果
輸出成功了,證明繼承成功

關於類
定義:

class 子類名(父類名):

情況1,如果子類有新增的屬性,那麼需要在子類__init方法中,呼叫父類的__init__

情況2,如果子類沒有新增的屬性,子類不需要寫__init__方法

使用: 物件名 = 子類名(引數)

繼承的好處:程式碼重用,升級功能(重寫),新增功能(新的方法)

我們已經學會了如何給子類新增屬性,那麼關於新的方法呢?


方法重寫

平常需要新的方法時,直接在新的子類中define一個就可以,但如果我們的新方法名和父類的一個方法相同時,新方法會覆蓋掉舊方法,也就是方法重寫。

子類方法與父類方法完全相同,子類若重寫了父類的方法,則子類物件呼叫方法時就是呼叫的自己類中重新的方法,但放心,方法重寫不會影響父類方法。

Roger教練不需要隊員的三個最快成績,相反,他需要三個最慢成績,甚至不需要資料去重,那我們應該怎麼寫呢?


class Rugby(Athlete):
    def __init__(self,a_name,a_bod,a_squat,a_times):

        Athlete.__init__(self,a_name,a_bod,a_times)

        self.squat = a_squat
    def top3(self):
        return sorted([self.sanitize(t) for t in self.times])[-3:]

這樣一來,Rugby內的top3方法就變成了:

將資料規範化,寫進一個新列表,然後排序,取出末三位

二,多型

又來10個各種各樣的運動員,他們的top3完全不同,程式碼看起來是這樣的。

class OtherAthlete(Athlete):
    def __init__(self,a_name,a_bod,a_squat,a_times):

        Athlete.__init__(self,a_name,a_bod,a_times)

        self.squat = a_squat
    def top3(self):
        return sorted([self.sanitize(t) for t in self.times])[0:3]

我需要為每種遠動員定義一個子類,呼叫的時候是一堆重複的程式碼。

mark1 = get_coach_data('mywork/mark.txt')
mark2 = get_coach_data('mywork/mark1.txt')
mark3 = get_coach_data('mywork/mark2.txt')


mark1 = OtherAthlete(mark1.pop(0),mark1.pop(0),mark1.pop(0),mark1)
mark2 = OtherAthlete(mark2.pop(0),mark2.pop(0),mark2.pop(0),mark2)
mark3 = OtherAthlete(mark3.pop(0),mark3.pop(0),mark3.pop(0),mark3)

print('姓名:%s,生日:%s,深蹲:%s個,最快的3次成績:%s' %(mark1.name,mark1.dob,mark1.squat,mark1.top3()))
print('姓名:%s,生日:%s,深蹲:%s個,最快的3次成績:%s' %(mark2.name,mark2.dob,mark2.squat,mark2.top3()))
print('姓名:%s,生日:%s,深蹲:%s個,最快的3次成績:%s' %(mark3.name,mark3.dob,mark3.squat,mark3.top3()))

這樣的重複程式碼很麻煩,Python作為面嚮物件語言的三大特徵——封裝,繼承,多型

多型的體現就可以解決這個問題
我們將需要子類做的事情放進一個函式中

def print_rugby(athlete):

    print(athlete.name)
    print(athlete.dob)
    print(athlete.squat)
    print(athlete.top3())

這個函式的引數是例項化後的父類,每當我們需要呼叫子類的組成部分的時候,只需要呼叫print_rugby函式,並且將子類作為引數放進去

全部的程式碼是這樣的

loren = get_coach_data('mywork/loren.txt')
mark = get_coach_data('mywork/mark.txt')

loren = Rugby(loren.pop(0),loren.pop(0),loren.pop(0),loren)
mark = OtherAthlete(mark.pop(0),mark.pop(0),mark.pop(0),mark)
#新定義一個函式,將父類作為一個引數,方便重複使用子類
#稱坐多型
def print_rugby(athlete):

    print(athlete.name)
    print(athlete.dob)
    print(athlete.squat)
    print(athlete.top3())
#具體怎麼使用決定於子類
print_rugby(loren)
print_rugby(mark)

結果如下

輸出結果

多型性:一個事物多種形態

上面例子中print_rugby的引數athlete,athlete.name,athlete.top3()的行為由athlete的子類決定。

多型的好處是:減少重複程式碼,分離經常改變的程式碼與不經常改變的程式碼,使得程式碼可維護性提高。

工廠

方便建立多個物件

#如何優化建立物件的程式碼呢?
#將大段程式碼的變化,轉為引數的變化
def obj_factory(name,filename):
    with open(filename) as f:
        line = f.readline()
    templ = line.strip().split(',')
    if name == 'r':
        return Rugby(templ.pop(0),templ.pop(0),templ.pop(0),templ)
    elif name == 'oa':
        return OtherAthlete(templ.pop(0),templ.pop(0),templ.pop(0),templ)

oa = obj_factory('oa','mywork/mark.txt')
print(oa.name)

三,多繼承

一個子類可以繼承多個父類的屬性,程式碼的複用性越高,看起來就越簡潔,而不是一團漿糊

class Father(): 
    def talk(self):
        print("---爸爸的表達能力---")

class Mather():
    def smart(self):
        print("---媽媽聰明的頭腦---")

class Child(Father,Mather):
    pass

child1 = Child()
child1.talk()
child1.smart()

輸出結果
切記,多個父類在建立之時就應該注意,不應該擁有相同的方法名,不然多繼承時會出現問題

四,封裝

在每個需要Athlete的時候,我都需要把Athlete類的定義複製貼上要用的程式碼上方。
有沒有什麼辦法可以讓程式碼主體更加簡潔呢?

import sys
sys.path.append('mywork')

# import athlete
# print(dir(athlete))
from athlete import *

import sys
匯入sys模組 sys.path.append(‘work’)
將模組athlete.py新增到模組搜尋路徑
from athlete import *
匯入athlete模組,使用athlete模組下的所有程式碼

如果有一個模組mymodule.py中也包含get_coach_data函式,該怎麼區分這兩個函式呢?

import sys
sys.path.append('mywork')

from p1.mymodule import *
from p2.mymodule import *
import p1
import p2
p1.mymodule.demo()
p2.mymodule.demo()

要寫清是哪個資料夾下的哪個檔案裡的demo()函式