当前位置: 首页 > news >正文

2025-08-21 Python进阶5——类和对象

文章目录

  • 1 名称和对象
  • 2 作用域和命名空间
    • 2.1 基本概念
    • 2.2 作用域层次
    • 2.3 `global` 和 `nonlocal` 关键字
  • 3 类的基本概念
    • 3.1 类定义语法
    • 3.2 类对象
    • 3.3 `__init__` 方法
    • 3.4 实例对象
    • 3.5 方法的特殊之处
  • 4 类变量和实例变量
  • 5 继承
    • 5.1 基本语法
    • 5.2 方法重写
    • 5.3 调用基类方法
    • 5.4 继承相关的内置函数
    • 5.5 多重继承
  • 6 私有变量
  • 7 杂项说明
    • 7.1 简单数据类
    • 7.2 方法对象的属性
    • 7.3 专有方法与运算符重载
  • 8 总结

1 名称和对象

在深入了解类之前,需要理解 Python 中名称和对象的关系:

  • 对象:是 Python 中所有数据的基本单元,具有类型和值
  • 名称:是绑定到对象的标识符,可以通过名称访问对象
  • 别名:多个名称可以绑定到同一个对象,这种现象称为别名

示例

a = [1, 2, 3]
b = a  # b 是 a 的别名,指向同一个列表对象
b.append(4)
print(a)  # 输出: [1, 2, 3, 4],因为 a 和 b 指向同一个对象

别名对于不可变对象(如数字、字符串、元组)影响不大,但对于可变对象(如列表、字典、自定义对象)可能产生意外效果,需要特别注意。

2 作用域和命名空间

理解作用域和命名空间是掌握类机制的基础。

2.1 基本概念

  • 命名空间(namespace):是从名称到对象的映射,用于避免名称冲突。常见的命名空间包括:
    • 内置名称命名空间(包含 abs() 等内置函数)
    • 模块的全局命名空间
    • 函数的局部命名空间
    • 对象的属性集合
  • 作用域:是代码中可以直接访问某个命名空间的区域。

2.2 作用域层次

执行期间,有 3 或 4 个嵌套的作用域可直接访问:

  1. 最内层:当前函数的局部作用域
  2. 外层:闭包函数的作用域(非局部、非全局)
  3. 倒数第二层:当前模块的全局作用域
  4. 最外层:内置名称的命名空间

2.3 globalnonlocal 关键字

  • global:声明变量在全局作用域中
  • nonlocal:声明变量在外层作用域中(非全局)

示例

def scope_test():def do_local():spam = "local spam"  # 局部变量def do_nonlocal():nonlocal spam        # 声明为外层作用域变量spam = "nonlocal spam"def do_global():global spam          # 声明为全局变量spam = "global spam"spam = "test spam"do_local()print("After local assignment:", spam)  # 输出: test spamdo_nonlocal()print("After nonlocal assignment:", spam)  # 输出: nonlocal spamdo_global()print("After global assignment:", spam)  # 输出: nonlocal spamscope_test()
print("In global scope:", spam)  # 输出: global spam

3 类的基本概念

3.1 类定义语法

class ClassName:<语句-1>...<语句-N>

类定义在执行时创建一个类对象,类中的语句通常是函数定义(方法)。

示例

class MyClass:"""一个简单的示例类"""i = 12345  # 类变量def f(self):  # 方法return 'hello world'

3.2 类对象

类对象支持两种操作:属性引用实例化

  • 属性引用:使用 ClassName.attribute 语法

    print(MyClass.i)  # 访问类变量
    print(MyClass.f)  # 访问方法
    print(MyClass.__doc__)  # 访问文档字符串
    
  • 实例化:使用函数表示法创建类的新实例

    x = MyClass()  # 创建 MyClass 的实例
    

3.3 __init__ 方法

__init__ 方法是一个特殊方法,在实例化时自动调用,用于初始化新创建的对象。

class Complex:def __init__(self, realpart, imagpart):self.r = realpart  # 实例变量self.i = imagpart  # 实例变量x = Complex(3.0, -4.5)
print(x.r, x.i)  # 输出: 3.0 -4.5

3.4 实例对象

实例对象主要用于属性引用,有两种类型的属性:

  • 数据属性:相当于实例变量,首次赋值时创建

    x = MyClass()
    x.counter = 1  # 创建数据属性
    while x.counter < 10:x.counter *= 2
    print(x.counter)  # 输出: 16
    del x.counter  # 删除数据属性
    
  • 方法:是绑定到实例的函数

    x = MyClass()
    print(x.f())  # 调用方法,输出: hello world# 方法对象可以保存后调用
    xf = x.f
    print(xf())  # 输出: hello world
    

3.5 方法的特殊之处

方法与普通函数的区别在于:调用方法时,实例对象会作为第一个参数自动传入。

# 调用 x.f() 相当于调用 MyClass.f(x)
x = MyClass()
print(x.f())  # 等价于 MyClass.f(x)

按照约定,方法的第一个参数通常命名为 self,代表实例对象本身。

4 类变量和实例变量

  • 类变量:属于类本身,被所有实例共享
  • 实例变量:属于每个实例,每个实例有自己的副本

示例

class Dog:kind = 'canine'  # 类变量,所有实例共享def __init__(self, name):self.name = name  # 实例变量,每个实例独有self.tricks = []  # 实例变量,每个实例有自己的列表def add_trick(self, trick):self.tricks.append(trick)# 创建两个实例
d = Dog('Fido')
e = Dog('Buddy')# 类变量被共享
print(d.kind)  # 输出: canine
print(e.kind)  # 输出: canine# 实例变量各自独有
print(d.name)  # 输出: Fido
print(e.name)  # 输出: Buddy# 为每个实例添加不同的技能
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)  # 输出: ['roll over']
print(e.tricks)  # 输出: ['play dead']

注意:避免使用可变对象(如列表、字典)作为类变量,因为所有实例会共享它们,可能导致意外结果。

5 继承

继承允许创建新类(派生类),从现有类(基类)继承属性和方法,从而实现代码复用和扩展。

5.1 基本语法

class DerivedClassName(BaseClassName):<语句-1>...<语句-N>

如果基类在另一个模块中:

class DerivedClassName(modname.BaseClassName):...

5.2 方法重写

派生类可以重写基类的方法,即定义与基类同名的方法。

class Animal:def speak(self):return "Some sound"class Dog(Animal):def speak(self):  # 重写 speak 方法return "Woof!"class Cat(Animal):def speak(self):  # 重写 speak 方法return "Meow"d = Dog()
print(d.speak())  # 输出: Woof!c = Cat()
print(c.speak())  # 输出: Meow# 用子类对象调用父类已被覆盖的方法
print(super(Cat, c).speak())  # 输出: Some sound

5.3 调用基类方法

在派生类中,可以使用 BaseClassName.methodname(self, arguments) 调用基类方法。

class Base:def __init__(self, x):self.x = xclass Derived(Base):def __init__(self, x, y):Base.__init__(self, x)  # 调用基类的 __init__ 方法self.y = yd = Derived(3, 5)
print(d.x, d.y)  # 输出: 3 5

5.4 继承相关的内置函数

  • isinstance(obj, class):检查对象是否是类的实例(包括派生类)
  • issubclass(sub, sup):检查子类与父类的关系
print(isinstance(Dog(), Animal))  # 输出: True
print(issubclass(Dog, Animal))    # 输出: True

5.5 多重继承

Python 支持多重继承,一个类可以继承多个基类:

class Base1:def method1(self):return "Method from Base1"class Base2:def method2(self):return "Method from Base2"class Derived(Base1, Base2):pass  # 继承 Base1 和 Base2 的所有方法d = Derived()
print(d.method1())  # 输出: Method from Base1
print(d.method2())  # 输出: Method from Base2

方法解析顺序:当多个基类有同名方法时,Python 使用深度优先、从左到右的规则查找方法,也称为方法解析顺序(MRO)。可以通过 __mro__ 属性查看:

print(Derived.__mro__)
# 输出类似: (<class '__main__.Derived'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>)

6 私有变量

Python 没有真正的私有变量,但通过名称改写机制提供有限的支持:

  • 形式为 __spam 的变量(至少两个前导下划线,至多一个尾随下划线)会被改写为 _classname__spam
  • 这种机制主要用于避免子类中的名称冲突

示例

class Mapping:def __init__(self, iterable):self.items_list = []self.__update(iterable)  # 实际会被改写为 _Mapping__updatedef update(self, iterable):for item in iterable:self.items_list.append(item)__update = update  # 私有副本,实际为 _Mapping__updateclass MappingSubclass(Mapping):def update(self, keys, values):  # 不会与基类的 __update 冲突for item in zip(keys, values):self.items_list.append(item)

注意:名称改写只是一种约定,并非真正的访问限制,仍然可以通过 _classname__spam 访问 “私有” 变量。

7 杂项说明

7.1 简单数据类

对于仅需要存储数据的类,可以使用 dataclasses 模块简化定义:

from dataclasses import dataclass@dataclass
class Employee:name: strdept: strsalary: intjohn = Employee('john', 'computer lab', 1000)
print(john.dept)    # 输出: computer lab
print(john.salary)  # 输出: 1000

7.2 方法对象的属性

方法对象有两个有用的属性:

  • __self__:方法所属的实例
  • __func__:方法对应的函数对象
class MyClass:def my_method(self):passx = MyClass()
m = x.my_method
print(m.__self__ is x)    # 输出: True
print(m.__func__ is MyClass.my_method)  # 输出: True

7.3 专有方法与运算符重载

  • __init__ :构造函数,在生成对象时调用
  • __del__ :析构函数,释放对象时使用
  • __repr__ :打印,转换
  • __setitem__ :按照索引赋值
  • __getitem__ :按照索引获取值
  • __len__ :获得长度
  • __cmp__ :比较运算
  • __call__ :函数调用
  • __add__ :加运算
  • __sub__ :减运算
  • __mul__ :乘运算
  • __truediv__ :除运算
  • __mod__: 求余运算
  • __pow__ :乘方

Python同样支持运算符重载,我们可以对类的专有方法进行重载,实例如下:

class Vector:def __init__(self, a, b):self.a = aself.b = b# 定义字符串表示def __str__(self):return f'Vector ({self.a}, {self.b})'# 重载加法运算符def __add__(self, other):return Vector(self.a + other.a, self.b + other.b)# 使用重载的加法运算符
v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)  # 输出:Vector (7, 8)

8 总结

  • 类是封装数据和方法的重要机制,支持面向对象编程
  • 类变量被所有实例共享,实例变量为每个实例独有
  • 继承允许创建派生类,实现代码复用和扩展
  • 迭代器和生成器提供了便捷的遍历机制
  • Python 的类机制灵活,支持多重继承、动态修改等高级特性
http://www.dtcms.com/a/342325.html

相关文章:

  • Visual Studio 在机台上远程调试详细教程
  • LeetCode 反转链表
  • imx6ull-驱动开发篇33——platform 平台驱动模型
  • 【运维进阶】Shell 变量
  • Docker--Docker网络
  • 【学习笔记】网络安全专用产品类别与参考标准
  • 【问题思考】二分查找对比三分查找(任意点查找)的优越性(熵的角度)【gemini完成】
  • 语义分割开山之作:FCN网络从入门到精通
  • 概率论基础教程第5章 连续型随机变量(三)
  • 【复杂网络技术】什么是图神经网络?
  • Elasticsearch 面试题完整笔记
  • 大数据面试常见问题
  • 【网络】http 协议中 Vary 标头的作用
  • UI自动化测试
  • 【力扣 Hot100】滑动窗口巧解字串问题
  • 鸿蒙中基础耗时分析:Time分析
  • Minecraft 1.18.2 或更高版本(如1.19.2、1.20.1)选择模组mod加载器
  • spark数据缓存机制
  • 在没有客户端的客户环境下,如何用 Python 一键执行 MySQL 与达梦数据库 SQL
  • 【开源项目】边浏览边学外语:开源工具 Read Frog 如何用 AI 重构语言学习
  • Java实战:深度解析SQL中的表与字段信息(支持子查询、连接查询)
  • 粗粮厂的基于flink的汽车实时数仓解决方案
  • Elasticsearch Ruby 客户端elasticsearch / elasticsearch-api
  • 小程序UI(自定义Navbar)
  • 【TrOCR】用Transformer和torch库实现TrOCR模型
  • yggjs_rlayout 科技风主题布局使用教程
  • StarRocks不能启动 ,StarRocksFe节点不能启动问题 处理
  • macos使用FFmpeg与SDL解码并播放H.265视频
  • 【TrOCR】模型预训练权重各个文件说明
  • 从800米到2000米:耐达讯自动化Profibus转光纤如何让软启动器效率翻倍?