Python面向对象编程(OOP)基础

面向对象编程(Object Oriented Programming)是现代编程的核心范式之一。本文将系统介绍Python中面向对象编程的基础知识,帮助初学者快速掌握OOP的核心概念和使用方法。

一、面向对象基本概念

1.1 面向过程 vs 面向对象

面向过程编程

  • 关注"怎么做",即解决问题的步骤

  • 通过函数封装代码块

  • 适合简单任务,但随着需求复杂化代码会变得难以维护

面向对象编程

  • 关注"谁来做",即确定职责分配

  • 通过对象封装数据和方法

  • 更适合复杂项目开发,提供了更好的组织代码的方式

1.2 核心优势

面向对象编程的主要优势在于:

  • 更好的代码组织

  • 更高的可重用性

  • 更容易应对需求变化

  • 更接近现实世界的思维方式

二、类和对象

2.1 基本概念

类(Class)

  • 对具有相同特征和行为的事物的抽象描述

  • 相当于制造产品的图纸

  • 包含属性和方法

对象(Object)

  • 类的具体实例

  • 根据类创建出来的具体存在

  • 相当于根据图纸制造的实际产品

2.2 关系说明

  • 类是模板,对象是实例

  • 先有类,后有对象

  • 一个类可以创建多个对象

  • 对象拥有类中定义的所有属性和方法

三、类的设计

设计类时需要关注三个要素:

  1. 类名:使用大驼峰命名法(如ClassName)

  2. 属性:对象的特征

  3. 方法:对象的行为

3.1 设计技巧

  • 名词提炼法:从需求描述中找出名词作为候选类

  • 动词识别法:从需求描述中找出动词作为候选方法

3.2 示例练习

需求1

  • 小明今年18岁,身高1.75,每天早上跑步,会去吃东西

  • 小美今年17岁,身高1.65,小美不跑步,喜欢吃东西

设计

class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height
        
    def run(self):
        print(f"{self.name}在跑步")
        
    def eat(self):
        print(f"{self.name}在吃东西")

需求2

  • 一只黄颜色的狗狗叫大黄

  • 看见生人汪汪叫

  • 看见家人摇尾巴

设计

class Dog:
    def __init__(self, name, color):
        self.name = name
        self.color = color
        
    def bark(self):
        print(f"{self.name}汪汪叫")
        
    def wag_tail(self):
        print(f"{self.name}摇尾巴")

四、面向对象基础语法

4.0 dir函数

dir() 是 Python 的一个非常有用的内置函数,主要用于返回对象的属性列表或当前作用域内的名称列表。

基本用法

  1. 不带参数调用:返回当前作用域内的名称列表

    dir()  # 返回当前作用域中的名称列表
  2. 带参数调用:返回对象的有效属性列表

    dir(object)  # 返回对象的属性和方法列表

示例

示例1:查看当前作用域
x = 10
y = "hello"

print(dir())  
# 输出类似:['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'x', 'y']
示例2:查看模块内容
import math
print(dir(math))  
# 输出 math 模块的所有函数和属性
示例3:查看对象属性和方法
s = "hello"
print(dir(s))  
# 输出字符串对象的所有方法,如 'capitalize', 'casefold', 'center', 'count', 'encode', 等
示例4:自定义对象
class MyClass:
    def __init__(self):
        self.x = 10
    def method(self):
        pass

obj = MyClass()
print(dir(obj))  
# 输出包含 'method', 'x' 等属性和方法

注意事项

  1. dir() 返回的列表是字母顺序排列的

  2. 对于不同类型的对象,返回的内容会有所不同

  3. 它会返回所有可访问的属性,包括特殊方法(以双下划线开头和结尾的方法)

  4. 当对象定义了 __dir__() 方法时,dir() 会调用该方法并返回其结果

实际应用

dir() 在交互式环境中特别有用,可以快速查看对象可用的方法和属性,是 Python 自省(introspection)的重要工具之一。

# 在交互式环境中快速探索对象
>>> import numpy as np
>>> dir(np)  # 查看 numpy 模块的内容
>>> a = np.array([1,2,3])
>>> dir(a)   # 查看 numpy 数组的方法

4.1 定义简单类

class ClassName:
    def method1(self, parameters):
        # 方法实现
        pass
        
    def method2(self, parameters):
        # 方法实现
        pass

4.2 创建对象

object_name = ClassName()

4.3 示例:猫类

class Cat:
    def eat(self):
        print("小猫爱吃鱼")
    
    def drink(self):
        print("小猫在喝水")

tom = Cat()
tom.eat()
tom.drink()

五、方法中的self参数

5.1 self的作用

  • 表示当前对象实例

  • 通过self可以访问对象的属性和方法

  • Python自动传递,不需要手动传入

5.2 使用示例

class Cat:
    def eat(self):
        print(f"{self.name}爱吃鱼")

tom = Cat()
tom.name = "Tom"
tom.eat()

六、初始化方法

6.1 __init__方法

  • 创建对象时自动调用

  • 用于初始化对象属性

  • 可以接收参数进行灵活初始化

6.2 使用示例

class Cat:
    def __init__(self, name):
        self.name = name
        
    def eat(self):
        print(f"{self.name}爱吃鱼")

tom = Cat("Tom")
tom.eat()

七、常用内置方法

7.1 __del__方法

__del__是Python中的一个特殊方法(魔术方法),用于定义对象被销毁时的行为。

7.1.1 __del__方法基本概念

__del__方法被称为析构函数,当对象即将被垃圾回收时自动调用。

class MyClass:
    def __del__(self):
        print(f"对象 {self} 正在被销毁")

obj = MyClass()
del obj  # 输出: 对象 <__main__.MyClass object at 0x...> 正在被销毁

7.1.2 调用时机

__del__方法在以下情况会被调用:

  1. 当对象的引用计数变为0时

  2. 当垃圾回收器回收对象时

  3. 程序退出时,所有存活的对象都会被销毁

7.1.3 典型使用场景

7.1.3.1 资源清理
class FileHandler:
    def __init__(self, filename):
        self.file = open(filename, 'r')
    
    def __del__(self):
        self.file.close()
        print("文件资源已释放")
7.1.3.2 连接关闭
class DatabaseConnection:
    def __init__(self):
        self.connection = connect_to_database()
    
    def __del__(self):
        self.connection.close()
        print("数据库连接已关闭")

7.1.4 重要注意事项

7.1.4.1 不保证立即执行

__del__的调用时机由垃圾回收器决定,不保证会立即执行:

obj = MyClass()
obj = None  # 不保证立即调用__del__
7.1.4.2 循环引用问题

存在循环引用时,__del__可能永远不会被调用:

class Node:
    def __init__(self):
        self.ref = None
    def __del__(self):
        print("节点被删除")

a = Node()
b = Node()
a.ref = b
b.ref = a  # 循环引用
del a, b   # __del__不会被调用
7.1.4.3 异常处理

__del__中发生的异常会被忽略,不会向上传播:

class Problematic:
    def __del__(self):
        raise Exception("Oops!")

p = Problematic()
del p  # 异常被静默忽略

7.1.5 最佳实践

  1. 优先使用上下文管理器:对于资源管理,with语句更可靠

    with open('file.txt') as f:
        # 使用文件
    # 离开with块自动关闭

  2. 显式清理方法:提供close()cleanup()方法供用户显式调用

  3. 避免复杂逻辑__del__中只做必要清理,避免复杂操作

  4. 弱引用解决循环引用:使用weakref模块处理循环引用

7.1.6替代方案

7.1.6.1 上下文管理器
class Resource:
    def __enter__(self):
        self.acquire_resource()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.release_resource()
7.1.6.2 显式清理方法
class Connection:
    def close(self):
        # 清理代码
        self._closed = True
    
    def __del__(self):
        if not getattr(self, '_closed', True):
            self.close()

7.1.7 总结

  • __del__是Python的析构函数,但不应该依赖它进行关键资源清理

  • 存在循环引用时可能永远不会被调用

  • 对于重要资源,应该提供显式的释放方法

  • 文件、网络连接等资源最好使用with语句管理

记住:在Python中,显式优于隐式,资源管理最好通过上下文管理器或显式方法调用来实现。

7.2 __str__方法

__str__是Python中一个重要的特殊方法(魔术方法),用于定义对象的"非正式"或可打印的字符串表示。

7.2.1__str__方法基础

7.2.1.1 基本语法
class MyClass:
    def __str__(self):
        return "对象的字符串表示"
7.2.1.2 调用方式

__str__方法会在以下情况下自动调用:

  • 使用print()函数打印对象时

  • 使用str()函数转换对象时

  • 在f-string或字符串格式化中使用对象时

obj = MyClass()
print(obj)        # 调用__str__
print(str(obj))   # 调用__str__
print(f"{obj}")   # 调用__str__

7.2.2__str____repr__的区别

特性__str____repr__
目的用户友好的输出明确的、无歧义的对象表示
调用场景print()str(), 格式化字符串交互式环境、repr(), 调试
返回值要求可读性好的字符串应尽可能包含重建对象的信息
默认实现如果没有定义,会调用__repr__所有对象都应该有__repr__实现
示例对比
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        return f"Point at ({self.x}, {self.y})"
    
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"

p = Point(3, 4)
print(str(p))   # 输出: Point at (3, 4)
print(repr(p))  # 输出: Point(x=3, y=4)

7.2.3 最佳实践

7.2.3.1 设计原则
  1. 信息丰富:返回的字符串应包含对象的关键信息

  2. 可读性强:便于人类阅读和理解

  3. 简洁明了:避免过于冗长的输出

  4. 一致性:同一类的不同实例应采用相似的格式

7.2.3.2 良好示例
class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year
    
    def __str__(self):
        return f"'{self.title}' by {self.author} ({self.year})"

book = Book("Python编程", "Guido van Rossum", 2020)
print(book)  # 输出: 'Python编程' by Guido van Rossum (2020)
7.2.3.3 应避免的做法
  1. 包含复杂计算__str__应该快速执行

  2. 修改对象状态__str__应该是无副作用的

  3. 返回非字符串:必须返回字符串类型

  4. 过于技术性:这是__repr__的职责

7.2.4 高级用法

7.2.4.1 多语言支持
class MultiLanguageUser:
    def __init__(self, name, lang='en'):
        self.name = name
        self.lang = lang
    
    def __str__(self):
        return {
            'en': f"User: {self.name}",
            'zh': f"用户: {self.name}",
            'ja': f"ユーザー: {self.name}"
        }.get(self.lang, f"User: {self.name}")
7.2.4.2 动态信息展示
class Progress:
    def __init__(self, total):
        self.total = total
        self.current = 0
    
    def __str__(self):
        percent = (self.current / self.total) * 100
        return f"[{'#' * int(percent//10)}{' ' * (10 - int(percent//10))}] {percent:.1f}%"

7.2.5常见问题解答

Q1: 如果没有定义__str__会怎样?

A1: Python会调用__repr__作为替代。如果__repr__也没有定义,会使用默认的对象表示(如<__main__.MyClass object at 0x...>)。

Q2: __str__可以返回非字符串吗?

A2: 不可以,__str__必须返回字符串类型(str),否则会引发TypeError。

Q3: 什么时候应该优先使用__repr__

A3: 当字符串表示主要用于调试和开发时,应该优先实现__repr__。一个好的经验法则是:先实现__repr__,再根据需要实现__str__

7.2.6 实际应用案例

7.2.6.1 电商产品展示
class Product:
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock
    
    def __str__(self):
        return (f"{self.name}\n"
                f"价格: ¥{self.price:.2f}\n"
                f"库存: {'有货' if self.stock > 0 else '缺货'}")
7.2.6.2 学生成绩报告
class Student:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores
    
    def __str__(self):
        avg = sum(self.scores) / len(self.scores)
        return (f"学生: {self.name}\n"
                f"科目数: {len(self.scores)}\n"
                f"平均分: {avg:.1f}\n"
                f"最高分: {max(self.scores)}\n"
                f"最低分: {min(self.scores)}")

7.2.7 总结

  • __str__用于创建对象的用户友好字符串表示

  • __repr__相比,__str__更注重可读性而非精确性

  • 应该为重要的用户可见类实现__str__方法

  • 遵循信息丰富、可读性强、简洁明了的设计原则

  • 避免在__str__中执行复杂操作或产生副作用

正确实现__str__可以显著提升代码的可读性和用户体验,特别是在调试和日志记录场景中。

八、总结

面向对象编程是Python中非常重要的编程范式,掌握OOP可以让你:

  1. 写出更结构化的代码

  2. 更容易维护和扩展程序

  3. 更好地处理复杂业务逻辑

  4. 提高代码复用性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值