Python面向对象编程核心概念:类、self与构造函数详解

不晚
不晚
发布时间:2026-10-16| 6人浏览过
原创

本文详细解析Python面向对象编程的核心机制,涵盖类的定义规范、驼峰命名法的应用、self参数的作用域与绑定原理,以及__init__构造函数的使用。通过实例演示实例属性与类属性的区别、对象生命周期管理及内存释放机制,帮助开发者掌握Python OOP的关键实践。

面向对象编程(Object-Oriented Programming,简称OOP)是Python编程的核心范式之一,它通过“类”这一概念来组织代码。

面向对象编程的本质,是利用对象的属性和方法来进行编码开发的过程。

在面向对象编程中,自定义对象的数据类型即对应于“类”(class)的概念。

类的声明关键字为 class。

使用 class 关键字声明类时,类名应遵循驼峰命名法,即首字母大写,若由多个单词组成,每个单词的首字母均需大写。尽管在Python的一般变量命名中建议避免使用驼峰命名法,但类名的命名是一个特例,推荐使用驼峰命名法以符合规范。

类的定义与具体使用方式。

类的定义示例如下:

class Nmae(object):        
# class关键字 + 类名(首字母大写) + 小括号(括号内填写 object:为python中的通用对象,书写通用对象的 class 会带有更多的内置功能) + 冒号
    
    变量 = 变量的值
    # 可以定义 类 的变量
    
    def func(self):
        do
    # 也可以定义 类 的函数:类函数内有个必传参数 'self' ,一定要书写在类函数的第一参数位,这是 python 内部的语法规定
    
# 需要注意的是 类的属性与函数的缩进要统一

类的实际使用示例如下:

# 定义一个动物类;动物类中定义一个变量;定义一个 跑 的函数(属性)

class Animal(object):	# 定义一个类
    name = '哈士奇'		# 类变量(类属性)
    
    def run(self):		# 类函数:将 self 作为第一个参数传入 类函数 'run()'
        print(f'{self.name} can run')	
        				# 'self.name'为类属性,如果不加上'self.'则不会找到类属性;如果想要在类函数中调用类属性就必须加上'self.'
            			# 'self' 参数具备两个功能
                		# 1.可以帮助我们调用类属性
                    	# 2.将使用 self 的函数调用到类中,如果我们有另一个函数,可以在另一个函数中通过 'self.' 来进行调用 run 函数
                        
dog = Animal()		# 类的实例化
print(dog.name)		# 通过实例化进行属性调用

dog.run()			# 通过实例化,进行函数调用

# >>> 执行结果如下:
# >>> 哈士奇
# >>> 哈士奇 can run

类方法中的关键参数:self。

在类内部定义的所有实例方法,必须包含 self 参数,且该参数必须位于参数列表的第一位,每个实例方法有且仅有一个 self 参数。

self 参数的含义是:在类中定义的方法里,第一个参数 self 指向调用该方法的实例对象。在方法内部,通过 self.属性名的形式来访问该对象的实例属性。

  • self 是类方法中必须传递的参数,且必须置于第一个参数位置。
  • self 实际上是一个对象引用,它代表当前正在调用该方法的实例化变量本身。
  • 可以通过点号(.)直接通过 self 定义类变量,例如 self.name = 'Neo'。如果在函数体内定义变量,需通过 self + . + 变量名的方式进行赋值。
  • 绑定在 self 上的变量以及含有 self 参数的函数,可以在类的任何其他函数内被随意调用。
  • 在类中非函数部分(即类级别)定义的变量,在定义时不需要使用 self。

如何深入理解 self 参数。

可以通过类比来理解。

  • 如果把“类”比作建造房子的设计图纸。
  • 那么类实例化后生成的对象,就是真正可以居住的实体房子。
  • 根据同一张图纸(类),可以设计出成千上万栋房子(实例对象)。
  • 每栋房子外观相似(拥有相同的实例属性和实例方法),但它们各自拥有不同的主人。
  • 如何区分不同的房子?通过 self 参数,可以确保每个房子的主人只能进入自己的房子(即每个实例对象只能访问自己的实例属性和实例方法)。

关键点总结。

  • 一个类可以生成多个实例对象。当某个实例对象调用实例方法时,该对象会将自身的引用作为第一个参数自动传递给该方法。
  • 换句话说:Python 解释器会自动将实例方法的第一个参数指向调用该方法的对象。
  • 这样做使得 Python 解释器能够明确知道具体要执行哪个对象的实例方法。
  • 在调用实例方法时,用户不需要手动为第一个参数(self)传值。

如果对上述概念仍感困惑,我们可以结合类的两个关键要素——属性和方法,通过具体代码来看看 self 的实际应用效果:

class Persion(object):
    name = None
    age = None

    def run(self):
        print(f'{self.name} 的健身项目是\'跑步\'')

    def swim(self):
        print(f'{self.name} 的健身项目是\'游泳\'')


neo = Persion()
neo.name = 'Neo'
neo.run()

# >>> 执行结果如下:
# >>> Neo 的健身项目是'跑步'

我们重新实例化一个对象,观察这个新实例化对象是否同步了 neo 的 name 属性。

class Persion(object):
    name = None
    age = None

    def run(self):
        print(f'{self.name} 的健身项目是\'跑步\'')

    def swim(self):
        print(f'{self.name} 的健身项目是\'游泳\'')


neo = Persion()
neo.name = 'Neo'
neo.run()


jack = Persion()
jack.run()

# >>> 执行结果如下:
# >>> Neo 的健身项目是'跑步'
# >>> None 的健身项目是'跑步'

从输出结果可以看出,我们修改的 neo 实例化对象对应的 name 值仅作用于其自身实例,而 Person 类本身以及新的 jack 实例化对象并未受到影响。

因此,即使使用新对象进行实例化,仍需通过新的实例化对象来修改类的属性,以达到预期效果。这很好理解:虽然都是人类(类),但每个人的个体特征(实例属性)是独立的。他们在拥有类的共同属性(name, age)后,也可以自定义属于自己的属性。

目前我们的 Person 类定义了两个属性 'name' 和 'age',如果我们要再添加一个属性呢?答案是肯定的。现在我们针对 'Jack' 增加一个自定义属性,尝试一下。

class Persion(object):
    name = None
    age = None

    def run(self):
        print(f'{self.name} 的健身项目是\'跑步\'')

    def swim(self):
        print(f'{self.name} 的健身项目是\'游泳\'')


neo = Persion()
neo.name = 'Neo'
neo.run()


jack = Persion()
jack.top = 180
print('\'Jack\'的身高是', jack.top)

# >>> 执行结果如下
# >>> Neo 的健身项目是'跑步'
# >>> 'Jack'的身高是 180


print('\'Neo\'的身高是', neo.top)
# >>> 执行结果如下:
# >>> AttributeError: 'Persion' object has no attribute 'top'

从上述 jack.top 与 neo.top 的自定义属性对比中,我们可以发现三件事。

1. 实例化对象可以自定义属性。

2. 每个实例化对象自己定义的属性与其他实例化对象不通用。

3. Person 类在实例化对象之后,依然只保留其定义的两个属性(name 和 age)。实例化对象自定义的属性仅作用于该对象本身,并不影响类定义。

self 的解析与总结。

说实话,初次接触 Python 中的 self 时,许多人会感到困惑。这里做一个总结,希望对同样感到困惑的读者有所帮助。

  • 在 Python 中,self 代表类的实例;在定义类的方法时 self 是必须的,但在调用时不必显式传入相应参数。
  • 在 Python 中,self 只有在针对类的方法时才有意义。
  • self 只能用于 Python 类的方法中。

具体的举例说明如下:

关于属性。

关于属性 - 1:如果变量定义在类下面而不是类的方法下面,那么该变量既是类的属性,也是类实例的属性。

class Cat(object):
    eyes = '有2只眼睛'
    legs = '有4条腿'
    tail = '有1只尾巴'


dragonLi = Cat()
dragonLi.name = '狸花猫'
dragonLi_eyes = dragonLi.eyes
dragonLi_legs = dragonLi.legs
dragonLi_tail = dragonLi.tail

print(' 猫 ' + Cat.eyes, Cat.legs, Cat.tail)

print(dragonLi.name, dragonLi_eyes, dragonLi_legs, dragonLi_tail)

# >>> 执行结果如下:
# >>>  猫 有2只眼睛 有4条腿 有1只尾巴
# >>> 狸花猫 有2只眼睛 有4条腿 有1只尾巴

关于属性 - 2:如果变量定义在类的方法下面,若加了 self,则该变量是类实例的属性,不是类的属性;若没有加 self,则该变量只是该方法的局部变量,既不是类的属性也不是类实例的属性。

class Cat(object):
    eyes = '有2只眼睛'
    legs = '有4条腿'
    tail = '有1只尾巴'

    def __init__(self):			# 关于__init__() 会在下面的 '类的构造器'有详细讲解
        self.color_01 = '黄棕色'
        color_02 = '黑棕色'


dragonLi = Cat()
dragonLi_color_01 = dragonLi.color_01
print('狸花猫有两种披毛颜色,一种是:', dragonLi_color_01)

# >>> 执行结果如下:
# >>> 狸花猫有两种披毛颜色,一种是: 黄棕色

dragonLi_color_02 = dragonLi.color_02
print('狸花猫有两种披毛颜色,另一种是:', dragonLi_color_02)

# >>> 执行结果如下:
# >>> AttributeError: 'Cat' object has no attribute 'color_02'.

关于方法。

关于方法 1:如果在类中定义函数时加了 self,则该函数是类实例的方法,而不是类的方法。

class Cat(object):

    def eat(self):
        print('爱吃鱼')


dragonLi = Cat()
dragonLi.eat()

# >>> 执行结果如下:
# >>> 爱吃鱼

Cat.cat()

# >>> 执行结果如下:
# >>> TypeError: Cat.eat() missing 1 required positional argument: 'self'

关于方法 2:如果在类中定义函数时没有加 self,则该函数只是类的方法,而不是类实例的方法。

class Cat(object):

    def eat():
        print('爱吃鱼')


Cat.eat()

# >>> 执行结果如下:
# >>> 爱吃鱼

dragonLi = Cat()
dragonLi.eat()

# >>> 执行结果如下:
# >>> TypeError: Cat.eat() takes 0 positional arguments but 1 was given

小结。

属性规则:

  • 如果变量定义在类下面而不是类的方法下面,那么该变量既是类的属性,也是类实例的属性。
  • 如果变量定义在类的方法下面,若加了 self,则该变量是类实例的属性,不是类的属性;若没有加 self,则该变量只是该方法的局部变量,既不是类的属性也不是类实例的属性。

方法规则:

  • 如果在类中定义函数时加了 self,则该函数是类实例的方法,而不是类的方法。
  • 如果在类中定义函数时没有加 self,则该函数只是类的方法,而不是类实例的方法。

类的构造函数。

前面我们了解了类的创建、类的属性以及类函数的使用方法,现在来看看类的构造函数。

什么是类的构造函数?构造函数是类中的一种默认函数,通过定义它可以在类实例化的同时,将参数传入类中(类似于函数执行时可以传入参数)。

构造函数的创建方法。

重点:构造函数依然要在类中定义。

def __init__(self, a, b)        # def关键字 + __init__ + 小括号(括号内第一个传入的依然是 self ,后面再跟上希望实例化时传入的参数)
    self.a = a                    # 在构造函数里,将参数绑定在 self 中,将变量通过 self 绑定之后,就可以在类的各个函数中进行调用了
    self.b = b

构造函数的用法,示例如下:

class Test(object):
    
    def __init__(self, a):		# __init__ 构造函数一定要写在第一个,这是一个很好的编程规范
        self.a = a
        
    def run(self):
        print(self.a)
        
        
test = Test(1)
test.run()

# >>> 执行结果如下:
# >>> 1


test_02 = Test('Hello')
test_02.run()

# >>> 执行结果如下:
# >>> Hello

接下来我们再使用构造函数针对前面我们创建的 Cat 类进行修改。

class Cat(object):

    def __init__(self, eyes, legs, tail, color='黄棕色'):
        self.eyes = eyes
        self.legs = legs
        self.tail = tail
        self.color = color

    def show_cat(self):
        self.work = '抓老鼠'
        print('猫的通用属性为', self.eyes, self.legs, self.tail)


dragonLi = Cat('2只眼睛', '4条腿', '1只尾巴')
dragonLi.show_cat()

# >>> 执行结果如下:
# >>> 猫的通用属性为 2只眼睛 4条腿 1只尾巴 黄棕色


dragonLi.name = '狸花猫'
dragonLi.color = '虎斑色'

print(dragonLi.name, dragonLi.eyes, dragonLi.legs, dragonLi.tail, dragonLi.color, dragonLi.work)

# >>> 执行结果如下:
# >>> 狸花猫 2只眼睛 4条腿 1只尾巴 虎斑色 抓老鼠

关于对象的生命周期。

注意:这里说的对象生命周期,指的是实例化的对象。

之前我们提到过,当一个变量不再被使用时,就会被内存管理器清理。接下来我们就来看看一个变量的一生,从出现到消亡的过程。在这里插入这一章节介绍对象的生命周期,是为了更好地理解对象,从而更好地使用它们。

我们之前学习的深拷贝与浅拷贝,浅拷贝是创建一个新的内存地址,而深拷贝是使用之前已经定好的变量。

通过对一个对象的生命周期的理解,可以让我们权衡是终结一个对象还是继续使用它们。

我们通过构造函数完成一个对象的实例化,此时对象的生命周期开始。在这个时候,内存管理器发现有一个对象加入,就会为该实例化对象分配一个内存地址(即实例化对象在内存中的“家”)。

接下来我们就可以操作这个对象,可以调用它的内置函数和功能。当我们不再使用这个对象时,一般有两种情况:

第一种是这个内存块中的值没有变量与之绑定。例如,当一个变量的默认值被一个函数调用后,变量有了新的值,此时变量原有的默认值与变量不再是赋值关系。

第二种是当我们执行完所有程序,即代码已经执行到了最后一行。Python 解释器发现已经处理完所有业务,此时脚本会停止处理并释放脚本中所有的对象。释放所有对象其实就是告知内存管理器,内存管理器会自动处理这些对象的内存地址。

以上两种情况的统一表现形态都是不再使用这些对象。此时,每个对象中自带的内置函数 __del__(两个下划线)就会被调用,通知内存管理器从内存中释放每个对象对应的内存块。这就是整个对象的生命周期。

无论是字符串、数字、列表、元组、字典、集合,甚至布尔类型与空类型,我们知道 Python 中一切皆是对象,所以它们也是按照这个规律存在与消亡。

Python 中的内存管理都是自动完成的,所以我们并不需要特意去对它进行专门的处理。

关于 __del__ 函数并不需要我们书写和定义,当我们实例化一个对象之后,它就会默认存在,并拥有自动通知内存管理器清理内存的功能。这也是 Python 的特点之一。

以上就是 Python 学习之面向对象编程详解的详细内容,更多关于 Python 面向对象编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。