对象类别 class
当学习 Python 到某种程度后,就会开始进入面向对象的领域,而“类别”就是学习面向对象的基础,这篇教学将会介绍 Python 里的类别 class,并进一步说明类别和对象的关系。
本篇使用的 Python 版本为 3.7.12,所有范例可使用 Google Colab 实作,不用安装任何软件 ( 参考:使用 Google Colab )
什么是类别 class?
类别,可以比喻成一张“蓝图”,不同的蓝图会有不同的“属性”,根据不同的属性,就会建构出不同的物体。或者也可将类别想像成一个“人”,不同的人会有不同的“特征”( 属性 ),根据不同的特征,就会产生不同样的人。
举例来说,下方的程序码建立了一个名为 human ( 人 ) 的类别,类别默认有四个属性,分别是两个眼睛 eye、两个耳朵 ear、一个鼻子 nose 和一张嘴巴 mouth,接着透过这个类别诞生了一个特定的人 oxxo,这个人就会具有对应的属性 ( 后面会介绍如何建立类别 )。
class human():
def __init__(self): # 建立預設屬性的寫法
self.eye = 2 # 兩個眼睛
self.ear = 2 # 兩個耳朵
self.nose = 1 # 一個鼻子
self.mouth = 1 # 一張嘴巴
oxxo = human() # 製作一個名為 oxxo 的物件
print(oxxo.eye) # 得到 2 ( 印出 oxxo 的 eye 屬性 )。
什么是对象 object?
在 Python 里的任何东西 ( 数字、文字、函数...等 ) 都是对象,只是 Python 默认会将大部分对象的机制隐藏,只显示最常使用的方法,除非有特殊需求,不然不需要更动到默认对象的行为。
什么是对象呢?对象是一种自订的数据结构,里面可能包含了各种变数、属性、函数或方法,一个对象可以透过他的属性或方法,定义他和别的对象进行互动。
建立类别
建立类别的方式类似建立一个函数,差别在于函数使用 def 开头,而类别使用 class 开头,下方的程序码会建立一个“空”的类别 human ( 很像一个人在最开始只是一个细胞,身上什么器官都还没长出来 ):
class human():
pass # 使用 pass 可以建立一個空類別
接着使用建立类别的默认方法“__init__”( 注意前后是两条底线 ),将默认的属性加入类别里。
def __init__(self)默认带有一个 self 参数,代表透过类别建立的对象本体,内容使用“.属性”就能将指定的属性加入类别中。__init__可以不用定义,但如果需要有一些默认的属性,就可以定义在里面
class human():
def __init__(self): # 建立預設屬性的寫法
self.eye = 2 # 兩個眼睛
self.ear = 2 # 兩個耳朵
self.nose = 1 # 一個鼻子
self.mouth = 1 # 一張嘴巴
除了默认的属性,也可以自订属性,下方的例子定义了 say 和 play 两个函数作为 human 的属性,执行后,就等同于一个名为 oxxo 的人说话和玩棒球。
注意,字定义属性的第一个参数也都必须是 self。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg): # 定義 say
print(msg)
def play(self, thing): # 定義 play
print(thing)
oxxo = human()
oxxo.say('hello') # hello
oxxo.play('baseball') # baseball
属性除了可以定义在类别里,也可以从外部定义,下面的程序码额外定义了手 hand 和脚 leg 两个属性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(msg)
def play(self, thing):
print(thing)
human.hand = 2 # 定義 hand 屬性
human.leg = 2 # 定義 leg 屬性
oxxo = human()
print(oxxo.hand) # 2
print(oxxo.leg) # 2
刚刚有提到 self 这个参数,这个参数代表“透过类别建立的对象本体”,使用 self 可以读取到这个对象的所有属性,下方的例子从外部定义了 oxxo.name 的属性,在 human 里就能使用 self.name 取得这个属性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}') # 使用 self.name 取得 name 屬性的值
def play(self, thing):
print(thing)
oxxo = human()
oxxo.name = 'oxxo' # 設定 name 屬性
oxxo.say('hello') # oxxo say: hello
多个对象同一个类别
一个类别可以产生多个对象 ( 人 human 的类别可以产生无数不同的人 ),每个对象产生后,也可以定义自己特殊的属性,就如同人诞生后,虽然都有眼睛鼻子嘴巴,但某些人会去学画画,某些人会去学钢琴,下方的程序码会产生oxxo 和 gkpen 两个不同的人,oxxo 会自定义 age 属性,gkpen 会自定义 weight 属性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human() # 定義 oxxo
gkpen = human() # 定義 gkpen
oxxo.name = 'oxxo' # oxxo 的名字叫做 oxxo
oxxo.age = 18 # oxxo 的 age 為 18
gkpen.name = 'gkpen' # gkpen 的名字叫做 gkpen
gkpen.weight = 70 # gkpen 的 weight 為 70
oxxo.say('hello') # oxxo say: hello
print(oxxo.age) # 18
gkpen.say('song') # gkpen say: song
print(gkpen.weight) # 70
如果觉得这样子定义比较麻烦,也可以在建立类别时,预先设定好一些参数,接着透过类别建立对象时,在做动态的调整,例如下方的例子,在 init 里建立 age、weight 的参数,建立对象时就能动态传入。
class human():
def __init__(self, age, weight): # 新增 age 和 weight 參數
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
self.age = age # 讀取參數,變成屬性
self.weight = weight # 讀取參數,變成屬性
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human(18, 68) # 建立物件時,設定參數數值
gkpen = human(15, 70) # 建立物件時,設定參數數值
print(oxxo.age, oxxo.weight) # 18, 68
print(gkpen.age, gkpen.weight) # 15, 70
覆写属性
如果从外部定义了和类别属性名称相同的属性,就会覆写内部属性,下方的例子,从外部定义了 oxxo.play 的属性,就覆写原本的 play 属性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human()
oxxo.play = '???' # 覆寫 play 屬性
print(oxxo.play) # ???
@property 只读属性
如果在类别里有些属性不希望被外部更动,就能够使用 @property 的装饰器,将该属性设为只读属性,下方的例子,oxxo.a 可以将原本的 a 属性换成 12345,但 oxxo.b 就无法更动 b 属性,因为 b 属性已经变成只读属性。
class a:
def a(self):
return 'aaaaa'
@property
def b(self):
return 'bbbbb'
oxxo = a()
oxxo.a = '12345'
print(oxxo.a) # 12345
oxxo.b = '12345'
print(oxxo.b) # 發生錯誤 can't set attribute
微信扫码关注
抖音扫码关注