Python里的类和对象是什么?

2024-08-09 17:52:30 浏览数 (1)

学习 Python 到了一定阶段,我们就会接触到面向对象编程(OOP)。面向对象编程的核心概念之一就是“类”。本文将详细介绍 Python 中的类以及类与对象之间的关系。

类(Class)的概念

类可以看作是一种“蓝图”,它是一种将数据(属性)和操作这些数据的方法(函数)封装在一起的结构。就像建筑师使用蓝图来建造房屋一样,程序员使用类来创建对象。

例如,我们可以定义一个Human类,它有眼睛、耳朵、鼻子和嘴巴等属性。通过这个类,我们可以创建具体的人类对象,如oxxo,这个对象将具有类定义的所有属性。

代码语言:javascript复制
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属性

对象(Object)的概念

在 Python 中,一切都是对象,包括数字、字符串、函数等。对象是类的实例,只是 Python 默认隐藏了大部分对象的底层机制,仅展示最常用的接口。对象是一种自定义的数据结构,可以包含变量、属性、函数或方法。一个对象可通过其属性或方法来定义与外部的交互方式。

创建类

创建类的方式类似于创建一个函数,差别在于函数使用 def 开头,而类使用 class 开头,下面的代码会创建一个“空”的类 Human(很像一个人在最开始只是一个细胞,身上什么器官都还没长出来):

代码语言:javascript复制
python 代码解读复制代码class Human():
    pass        # 使用 pass 可以创建一个空类

接着使用创建类的默认方法__init__(注意前后是两条底线),将默认的属性加入到类里。

  • __init__默认带有self一个参数,代表通过类创建的对象本体,使用.属性就能将指定的属性加入类中。
  • __init__可以不用写,但如果需要有一些默认的属性,就可以定义在里面。
  • __init__是类的一个特殊方法,每当创建类的新实例时都会自动调用它。
代码语言:javascript复制
ruby 代码解读复制代码class Human():
    def __init__(self):  # 创建默认属性的写法
        self.eye = 2       # 两个眼睛
        self.ear = 2       # 两个耳朵
        self.nose = 1      # 一个鼻子
        self.mouth = 1     # 一张嘴巴

除了默认的属性,也可以从外部定义自定义属性,下面的代码额外定义了 hand 和 leg 两个属性。

代码语言:javascript复制
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。

代码语言:javascript复制
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取得这个属性。

代码语言:javascript复制
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 属性。

代码语言:javascript复制
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 的参数,建立对象时就能动态传入。

代码语言:javascript复制
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 属性。

代码语言:javascript复制
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 只读属性

如果在类里有些属性不希望被外部更动,就能使用@property 的装饰器,将该属性设为只读属性,下面的例子,oxxo.a 可以将原本的 a 属性换成 12345,但 oxxo.b 就无法更动 b 属性,因为 b 属性已经变成只读属性。

代码语言:javascript复制
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

0 人点赞