[AI Studio] 飞桨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)

[AI Studio] 飞桨PaddlePaddle Python零基础入门深度学习笔记<五>_第1张图片

输出结果

多态性:一个事物多种形态

上面例子中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()函数

你可能感兴趣的:(python,多态,类)