7.面向对象

4 阅读4分钟

1. 面向对象编程简介

面向对象编程的英文是:Object Oriented Programming,简称 OOP。 在实际开发过程中,我们经常需要将现实生活中的事物映射成编程中的对象,即用代码来描述、模拟现实生活中的事物。

2. 类 (Class) 与实例化

  • :用来描述、模拟某一事物类型。类名通常采用大驼峰格式(如 Student, IceCream)。
  • 对象:通过类创建出来的实例(instance)。
  • 实例化:通过类创建对象的过程。
# 定义类
class Dog:
    """狗类"""
    pass

# 实例化对象
d1 = Dog()
d2 = Dog()
print(type(d1))  # <class '__main__.Dog'>

3. 方法 (Method) 与属性

方法可以理解为一种需要通过对象来调用的特殊函数,代表对象的能力或行为。

3.1 方法的定义与调用

  • 方法必须定义在类的内部。
  • 方法的第1个参数固定是 self,指向当前正在调用方法的对象(类似 Java 的 this)。
  • 调用时不需要显式传递 self
class Dog:
    def run(self):
        print(f'【{self.name}】跑起来了!')

d1 = Dog()
d1.name = '旺财'  # 动态添加对象属性
d1.run()

3.2 构造方法 __init__

构造方法是一种特殊的方法,对象在创建完毕时会自动调用。一般用于声明和初始化属性。

class Dog:
    # 带有默认参数的构造方法
    def __init__(self, name=None, age=1):
        self.name = name  # 对象属性
        self.age = age

d1 = Dog('宝哥', 5)

4. 对象属性 vs 类属性 vs 局部变量

  • 局部变量:定义在方法内部,不带 self。依赖于方法调用存在,调用完销毁。
  • 对象属性(实例属性):挂载在 self 上,如 self.name。每个实例对象独立拥有一份。
  • 类属性(类变量):直接写在类里面的变量,不带 self。所有实例对象共享这一份数据(类似全局变量)。
class Dog:
    count = 0  # 类属性

    def __init__(self, name):
        self.name = name  # 对象属性
        Dog.count += 1    # 修改类属性

d1 = Dog('旺财')
d2 = Dog('宝哥')
print(Dog.count)  # 2

建议:通过对象访问对象属性,通过访问类属性。如果同名,通过对象访问会优先找到对象属性。

5. 对象方法、类方法、静态方法

方法类型装饰器首个固定参数调用方式推荐适用场景
对象方法self (代表对象)对象.方法()行为的执行者是对象本身
类方法@classmethodcls (代表类)类.方法()无须实例化,且需操作类属性
静态方法@staticmethod无固定参数类.方法()无须实例化,也不操作类属性(相当于普通函数放进了类里)
class Dog:
    @classmethod
    def test_class(cls):
        pass

    @staticmethod
    def test_static():
        pass

6. 面向对象三大特性

6.1 封装 (Encapsulation)

  • 屏蔽内部细节:将属性私有化。在 Python 中,如果属性或方法以双下划线 __ 开头,则对外不可见。
  • 对外提供接口:外界通过特定的 getter / setter 方法访问或修改属性。

不可见的真相:Python 没有真正的私有化。__name 只是被改名成了 _类名__name,依然可以通过 s._Student__name 访问(只能防君子不能防小人)。

@property 装饰器 可以让 getter 和 setter 的使用像访问普通属性一样优雅。

class Student:
    def __init__(self):
        self.__age = None
        
    @property
    def age(self):
        return self.__age
        
    @age.setter
    def age(self, value):
        self.__age = value if value > 0 else 1

s = Student()
s.age = 10     # 调用 setter
print(s.age)   # 调用 getter

6.2 继承 (Inheritance)

子类(派生类)可以继承父类(基类/超类)的属性和方法。Python 支持多继承(但不推荐)。

  • 获取父类/子类类.__base__, 类.__subclasses__()
  • 重写 (Override):子类可以重新定义父类中同名的方法。

调用父类方法 在子类重写的方法中,经常需要调用父类的逻辑,可以使用 super()

class Person:
    def __init__(self, name):
        self.name = name

class Student(Person):
    def __init__(self, name, no):
        super().__init__(name)  # 调用父类的构造方法
        self.no = no

6.3 多态 (Polymorphism)

父类类型的变量指向子类类型的对象,调用同一方法时,会根据对象的真实类型呈现出不同的行为(形态)。

def test(obj: Animal):
    obj.run()  # 如果传Dog调用Dog的run,传Cat调用Cat的run

7. 其他补充知识点

重载 (Overload)

  • 在同一作用域定义多个同名但参数不同的方法。
  • Python 不支持传统重载。因为后面的定义会直接覆盖前面的。
  • Python 通过给参数设置默认值即可优雅替代重载的需求。

内置属性与方法 (Magic Methods)

双下划线开头和结尾的通常是内置方法/属性:

  • __dict__:存放对象所有自定义的属性字典。
  • __str__:执行 str(对象)print(对象) 时自动调用,返回对象的字符串表示。
  • __doc__:文档注释。

isinstanceissubclass

  • isinstance(obj, Class):判断对象 obj 是否为 Class 类型(或其子类)的实例。
  • issubclass(Class1, Class2):判断 Class1 是否为 Class2 的子类。

bool 继承自 int

bool 类型其实是 int 的子类,所以 True + 10 等于 11