学习 Python 到了一定阶段,我们就会接触到面向对象编程(OOP)。面向对象编程的核心概念之一就是“类”。本文将详细介绍 Python 中的类以及类与对象之间的关系。
类可以看作是一种“蓝图”,它是一种将数据(属性)和操作这些数据的方法(函数)封装在一起的结构。就像建筑师使用蓝图来建造房屋一样,程序员使用类来创建对象。
例如,我们可以定义一个Human
类,它有眼睛、耳朵、鼻子和嘴巴等属性。通过这个类,我们可以创建具体的人类对象,如oxxo
,这个对象将具有类定义的所有属性。ini
代码解读复制代码class Human:
def __init__(self):
self.eyes = 2 # 人类默认有两只眼睛
self.ears = 2 # 人类默认有两只耳朵
self.nose = 1 # 人类默认有一个鼻子
self.mouth = 1 # 人类默认有一张嘴巴
oxxo = Human() # 创建一个Human对象
print(oxxo.eyes) # 输出2,打印oxxo的eye属性
在 Python 中,一切都是对象,包括数字、字符串、函数等。对象是类的实例,只是 Python 默认隐藏了大部分对象的底层机制,仅展示最常用的接口。对象是一种自定义的数据结构,可以包含变量、属性、函数或方法。一个对象可通过其属性或方法来定义与外部的交互方式。
创建类的方式类似于创建一个函数,差别在于函数使用 def 开头,而类使用 class 开头,下面的代码会创建一个“空”的类 Human(很像一个人在最开始只是一个细胞,身上什么器官都还没长出来):python
代码解读复制代码class Human():
pass # 使用 pass 可以创建一个空类
接着使用创建类的默认方法__init__
(注意前后是两条底线),将默认的属性加入到类里。
__init__
默认带有self
一个参数,代表通过类创建的对象本体,使用.属性
就能将指定的属性加入类中。
__init__
可以不用写,但如果需要有一些默认的属性,就可以定义在里面。
__init__
是类的一个特殊方法,每当创建类的新实例时都会自动调用它。ruby
代码解读复制代码class Human():
def __init__(self): # 创建默认属性的写法
self.eye = 2 # 两个眼睛
self.ear = 2 # 两个耳朵
self.nose = 1 # 一个鼻子
self.mouth = 1 # 一张嘴巴
除了默认的属性,也可以从外部定义自定义属性,下面的代码额外定义了 hand 和 leg 两个属性。ini
代码解读复制代码class Human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
Human.hand = 2 # 定义hand属性
Human.leg = 2 # 定义leg属性
oxxo = Human()
print(oxxo.hand) # 2
print(oxxo.leg) # 2
除了定义属性,也可以给类定义方法,下面的例子给 Human 类定义了 say 和 play 两个方法。
注意,类方法的第一个参数必须是 self。ruby
代码解读复制代码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)
oxxo = Human()
oxxo.say('hello') # hello
oxxo.play('baseball') # baseball
刚刚有提到self
这个参数,这个参数代表“通过类建立的对象本体”,使用self
可以读取到这个对象的所有属性,下面的例子从外部定义了 oxxo.name 的属性,在 Human 里就能使用self.name
取得这个属性。python
代码解读复制代码class Human:
def __init__(self):
self.eyes = 2
self.ears = 2
self.nose = 1
self.mouth = 1
def say(self, message):
print(f"{self.name} says: {message}")
def play(self, activity):
print(f"{self.name} is playing {activity}")
# 创建对象并添加自定义属性
oxxo = Human()
oxxo.name = "Oxxo"
oxxo.age = 30
oxxo.say("Hello, world!") # 输出:Oxxo says: Hello, world!
print(oxxo.age) # 输出:30
一个类可以产生多个对象(Human 的类可以产生无数不同的人),每个对象产生后,也可以定义自己特殊的属性,就如同人出生后,虽然都有眼睛鼻子嘴巴,但某些人会去学画画,某些人会去学钢琴,下面的代码会产生 oxxo 和 gkpen 两个不同的人,oxxo 会自定义 age 属性,gkpen 会自定义 weight 属性。ini
代码解读复制代码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 的参数,建立对象时就能动态传入。python
代码解读复制代码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.mouth 的属性,就覆盖原本的 mouth 属性。python
代码解读复制代码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.mouth = 5 # 覆写 play 属性
print(oxxo.mouth) # 5
如果在类里有些属性不希望被外部更动,就能使用@property 的装饰器,将该属性设为只读属性,下面的例子,oxxo.a 可以将原本的 a 属性换成 12345,但 oxxo.b 就无法更动 b 属性,因为 b 属性已经变成只读属性。python
代码解读复制代码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' # 发生错误 can't set attribute
print(oxxo.b) # 12345