python继承语法_【python类别概念自学】class的语法整理(继承、抽象类别、魔术方法)...

类别(class)这个概念在很多程序语言中都会出现,

感觉上挺值得一学的,

对于管理大型程序分工上也蛮有帮助的。

之前小马在自学c++时也碰到这个概念:

【c++类别class的语法大全】(1) 物件导向概念; 封装与存取权限; class基础语法; 预设建构子与拷贝建构子

基础语法简介

这边举个介绍类别中最常见的例子- 动物好了

class Animal():

def __init__(self, name):

self.name = name

a = Animal('老虎')

print(a.name)

结果: 老虎

几个重点:

def __init__(self, ): 这个是类别的「起手式」,当类别被创造时会去执行这个函数,所以通常用来写初始属性的设置

类别方法(函数)的第一个参数一定是 self ,他是 Python 类别定义中预设的参数,代表物件本身

要呼叫一个类别的属性或方法都是用.号

类别的概念简介

有人说,

类别像是一个蛋糕的模子,这个蛋糕的模子可以重複制作出相同的蛋糕,就像类别可以宣告出相同的物件,可以让程序不断地被重複利用。

至于为什么写程序需要使用类别,

我认为是主要的好处是封装,

因为开发大型程序时,

可能要团队合作写程序,

不一定所有的程序都是自己写,

有可能别人写好的程序码你需要拿来用。

如果把程序包装成一个物件,

你不用完全了解他里面的程序码是怎么写的,

可以直接拿来用

次要的好处是表达属于关係,

譬如说name(名字)是动物的一个属性,

把name写在动物这个类别里面,

就可以清楚知道说动物有「名字」这个属性。

a = Animal('老虎')

print(a.name)

若单纯宣告一个字串表示动物的名字,

语义可能就没有这么明确

name = '老虎'

不专业语法介绍(想要看很正式介绍的话自行按右上角叉叉去找教科书来读,这边仅分享学习笔记)

继续介绍语法吧,

由于用动物介绍类别已经在别人的文章中使用非常多次了,

这边小马也尝试天马行空写自己的版本,

假设现在我想要写一个「勇者斗恶龙」的游戏,

可能会创造很多不同的角色,

因此我创造一个Charactor的类别:

class Charactor():

def __init__(self, name):

self.name = name

cha = Charactor('小黑')

继承

但是我要创造的角色可能有分「人」和「怪物」两类,

他们的行为可能不太一样,

我们便可以创造新的类别「人」去继承「角色」这个类别

原有的类别被称为基础类别(base class)或双亲类别(parent class) ,新的类别被称为衍生类别(derived class)或子类别(child class),这个衍生类别就自动拥有基础类别的变数与函式。

使用「class 衍生类别(基础类别)」来定义类别间的继承关係,衍生类别就继承了基础类别;在衍生类别中使用「super().基础类别的函式」可以呼叫基础类别的函式来帮忙,若衍生类别所需要的功能已经在基础类别定义过了,就可以呼叫基础类别帮忙,重複利用已经撰写过的程序码。

小範例:

class Charactor():

def __init__(self, name):

self.name = name

class Person(Charactor):

def __init__(self, name, personality):

super().__init__(name)

self.personality = personality

def show(self):

print("我是"+self.personality+"的"+self.name)

p1 = Person("阿古斯", "英勇")

p1.show()

结果:

我是英勇的阿古斯

在这个例子中,我让Person继承Charactor这个类别,

并且Person比Charactor多了「个性」(personality)这个属性,

show()就定义成显示Person的个人资讯

另外再写一个class继承Charactor

另外,角色还有另外一类叫「怪物」,

行为跟「人」可能不太一样,

所以可以另外再写一个类别

(这边接续上面的程序继续写)

class Charactor():

def __init__(self, name):

self.name = name

class Person(Charactor):

def __init__(self, name, personality):

super().__init__(name)

self.personality = personality

def show(self):

print("我是"+self.personality+"的"+self.name)

class Monster(Charactor):

def __init__(self, name, race):

super().__init__(name)

self.race = race

def show(self):

print(self.race+": "+self.name)

p1 = Person("阿古斯", "英勇")

p1.show()

m = Monster("泡泡龙", "龙族")

m.show()

结果:

我是英勇的阿古斯

龙族: 泡泡龙

譬如说我为Monster定义了race(种族)这个属性,

用m = Monster("泡泡龙", "龙族")宣告一只龙,

名字就叫做「泡泡龙」

抽象类别

定义类别,本身就是在进行抽象化,如果一个类别定义时不完整,有些状态或行为必须留待子类别来具体实现,则它是个抽象类别(Abstract Class)。

譬如说我制作的「勇者斗恶龙」游戏的角色都有显示角色资讯(show()函数)这项功能,

但是不同种类的角色显示角色资讯的方式可能不同,

Charactor()这个基础类别中定义show()这个抽象函数(见参考资料3),

让子类别再去实作细节即可

小範例:

from abc import ABCMeta, abstractmethod

class Charactor(metaclass=ABCMeta):

def __init__(self, name):

self.name = name

@abstractmethod

def show(self):

pass

class Person(Charactor):

def __init__(self, name, personality):

super().__init__(name)

self.personality = personality

def show(self):

print("我是"+self.personality+"的"+self.name)

class Monster(Charactor):

def __init__(self, name, race):

super().__init__(name)

self.race = race

def show(self):

print(self.race+": "+self.name)

p1 = Person("阿古斯", "英勇")

p1.show()

m = Monster("泡泡龙", "龙族")

m.show()

语法重点:

写抽象类别时,要引用from abc import ABCMeta, abstractmethod这行

基础类别内要写metaclass=ABCMeta (我其实也不知道这是什么意思)

定义成抽象类别的方法上方会挂上@abstractmethod代表他是子类别必须实作的方法

课后自我练习

在codewar上看到一题跟class有关的问题,

记录下自己的解题历程:

参考题目: CodeWar- 6kyu DefaultList

题意: 实作一个类别,跟python的内建list型别有相同的功能,但是用中括号[]取值时,若超过範围则回传default值 (类似python的defaultdict的感觉,若key值不存在回传default值)

不过问题是怎么定义用中括号[]对这个类别取值的行为呢?

为了做这一题,另外学到了class的特殊方法(又称魔术方法、魔法方法、magic method)

魔术方法

存在于类别内的特殊函式,Python会让运算子或内建函式可以与特殊函式自动对应,例如判断两物件是否相等的运算子「==」会自动与类别内特殊函式「eq」,所以在类别内重新定义特殊函式「eq」,类别中使用运算子「==」的运算就会直接使用特殊函式「eq」进行是否相等的判断

我觉得这个在参考资料- Python类别与例外-高中资讯科技概论教师黄建庭的教程网站中整理的蛮好的,

魔术方法的形式均为____, 前后有两个下底线,

譬如说用中括号[]取值的运算便对应到__getitem__。

我原本是想说,既然要求list有的功能defaultdict都要有,

我的原始答案就乖乖的把list的方法重新定义了一遍:

class DefaultList:

def __init__(self, L, defualt):

self.dList = L

self.defualt = defualt

def extend(self, L):

self.dList.extend(L)

def append(self, i):

self.dList.append(i)

def remove(self, i):

self.dList.remove(i)

def insert(self, idx, val):

self.dList.insert(idx, val)

def pop(self, idx):

self.dList.pop(idx)

def __getitem__(self, index):

return self.dList[index] if -len(self.dList)<=index

后来看了别人的解答后,才惊呼到其实让defaultdict继承list这个类别就好了嘛,

简化后的答案:

class DefaultList(list):

def __init__(self,L, default):

super().__init__(L)

self.default=default

def __getitem__(self,idx):

try:

return super().__getitem__(idx)

except IndexError:

return self.default

参考资料

[自学Python纪录] HackerRank 新手30天挑战-Day04

Python类别与例外-高中资讯科技概论教师黄建庭的教程网站

抽象类别

Python进阶技巧 (2) — Static/Class/Abstract Methods之实现

Python – Magic Methods

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值