python 面向对象超详细教学

面向对象编程(Object-Oriented Programming,简称 OOP)是一种编程范式,它使用“对象”来设计软件。在 OOP 中,对象是数据(字段或属性)和可以对这些数据执行的操作(方法)的封装体。OOP 的核心概念包括类、对象、继承、封装、多态性和抽象

类定义

类是创建对象的蓝图,它封装了数据和行为。在 Python 中,使用 class 关键字定义一个类

class Person:
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age

    def greet(self):  # 实例方法
        return f"Hello, my name is {self.name} and I am {self.age} years old."

构造函数

构造函数是在创建对象时自动调用的特殊方法,通常用于初始化对象的状态。Python 中的构造函数是 __init__ 方法

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

car = Car("Toyota", "Corolla", 2020)

对象实例化

对象是类的具体实例,通过调用类名并传递必要的参数来创建对象

person1 = Person("Alice", 30)
print(person1.greet())  # 输出: Hello, my name is Alice and I am 30 years old.

继承

继承允许新类从现有类中继承属性和方法,从而促进代码复用和扩展

class Employee(Person):
    def __init__(self, name, age, position):
        super().__init__(name, age)  # 调用父类构造函数
        self.position = position

    def work(self):
        return f"{self.name} works as a {self.position}."

方法重写

子类可以重写父类的方法以提供特定的行为。这有助于实现多态性

class Developer(Employee):
    def greet(self):  # 重写父类的方法
        return f"Hi, I'm {self.name}, a developer with {self.age} years of experience."

dev = Developer("Bob", 25, "Software Engineer")
print(dev.greet())  # 输出: Hi, I'm Bob, a developer with 25 years of experience.

属性访问控制

Python 使用下划线 _ 和双下划线 __ 来暗示属性的可见性和私有性

  • 单下划线:约定俗成表示受保护的成员,不应直接访问
  • 双下划线:名称改写机制,使得属性在类外部难以直接访问
  • class Account:
        def __init__(self, owner, balance=0.0):
            self.owner = owner
            self.__balance = balance  # 私有属性
    
        def deposit(self, amount):
            if amount > 0:
                self.__balance += amount
                print(f"Added {amount} to the balance.")
    
        def withdraw(self, amount):
            if 0 < amount <= self.__balance:
                self.__balance -= amount
                print(f"Withdrew {amount}.")
            else:
                print("Invalid transaction.")
    
    account = Account("Alice")
    # account.__balance  # 这会引发 AttributeError

    类方法和静态方法

    类方法:使用 @classmethod 装饰器定义,接收类作为第一个参数(通常命名为 cls),可以用来修改类状态或创建类工厂方法

    class MyClass:
        count = 0
    
        @classmethod
        def increment_count(cls):
            cls.count += 1
    
        @classmethod
        def get_count(cls):
            return cls.count

    静态方法:使用 @staticmethod 装饰器定义,不接收隐式的第一个参数(如 selfcls),主要用于逻辑上属于类但不需要访问实例或类状态的方法

    class MathOperations:
        @staticmethod
        def add(a, b):
            return a + b
    
    print(MathOperations.add(5, 3))  # 输出: 8

    抽象基类

    抽象基类不能被实例化,它们为派生类定义了一个接口。Python 提供了 abc 模块来支持抽象基类

    from abc import ABC, abstractmethod
    
    class Animal(ABC):
        @abstractmethod
        def speak(self):
            pass
    
    class Dog(Animal):
        def speak(self):
            return "Woof!"
    
    dog = Dog()
    print(dog.speak())  # 输出: Woof!
    # animal = Animal()  # 这会引发 TypeError

    多重继承

    Python 支持多重继承,即一个类可以从多个父类继承

    class Flyer:
        def fly(self):
            return "Flying high!"
    
    class Swimmer:
        def swim(self):
            return "Swimming fast!"
    
    class Duck(Flyer, Swimmer):
        def quack(self):
            return "Quack!"
    
    duck = Duck()
    print(duck.fly())   # 输出: Flying high!
    print(duck.swim())  # 输出: Swimming fast!
    print(duck.quack()) # 输出: Quack!

    特殊方法

    特殊方法是带有双下划线前缀和后缀的方法,例如 __init____str____repr__ 等。它们为类提供了钩子,使得类可以自定义与 Python 语言特性交互的方式,如运算符重载、字符串表示形式等

    __add__ 方法

    __add__ 是一个用于定义加法运算符 (+) 行为的特殊方法。当你使用 + 操作符对两个对象进行相加时,Python 会查找并调用该对象的 __add__ 方法。如果找不到,则会尝试调用右边操作数的 __radd__ 方法

    class Vector:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __add__(self, other):
            # 如果 other 不是 Vector 类型,抛出 TypeError
            if not isinstance(other, Vector):
                return NotImplemented
            return Vector(self.x + other.x, self.y + other.y)
    
    v1 = Vector(1, 2)
    v2 = Vector(3, 4)
    v3 = v1 + v2  # 调用 v1.__add__(v2)
    print(v3)     # 输出: Vector(4, 6)
  • 参数

  • self:当前对象
  • other:另一个参与运算的对象
  • 返回值:一个新的 Vector 对象,其 xy 分别是两个向量对应分量的和

  • 注意事项:如果 other 不是预期类型的对象(如不是 Vector),应返回 NotImplemented,以便 Python 尝试其他方式处理这个操作(例如调用 other.__radd__(self)

  • __repr__ 方法

    __repr__ 是一个用于定义对象的“官方”字符串表示形式的特殊方法。它应该返回一个尽可能详细的字符串,最好是可以直接用来重建对象的表达式。__repr__ 的输出主要用于调试和开发人员查看对象的状态

    class Vector:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __repr__(self):
            return f"Vector({self.x}, {self.y})"
    
    v1 = Vector(1, 2)
    print(repr(v1))  # 输出: Vector(1, 2)
    print(v1)        # 输出: Vector(1, 2),因为 print 默认调用 __str__,但如果没有定义 __str__,则会调用 __repr__
  • 返回值:一个字符串,理想情况下,该字符串是一个有效的 Python 表达式,可以通过 eval() 函数重新创建对象

  • 用途

  • 当你在交互式解释器中输入对象名称时,或者当你将对象传递给 print() 或 str() 函数时,如果没有定义 __str__ 方法,Python 会自动调用 __repr__ 来获取对象的字符串表示
  • __repr__ 应该提供足够的信息来帮助开发者理解和调试代码
  • __str__ vs. __repr__

    虽然 __repr____str__ 都用于定义对象的字符串表示,但它们的目标不同:

  • __str__:旨在为最终用户提供易读的描述性文本。通常更加简洁和用户友好

  • class Vector:
        def __str__(self):
            return f"({self.x}, {self.y})"
  • __repr__:旨在为开发者提供详细的、无歧义的表示。它通常包含所有必要的信息以重建对象
  • class Vector:
        def __repr__(self):
            return f"Vector({self.x}, {self.y})"

    如果你只定义了 __repr__,而没有定义 __str__,那么 __repr__ 也会被用作字符串表示。但是,如果两者都定义了,str()print() 会优先使用 __str__,而在调试模式下(如交互式解释器中)会使用 __repr__

    完整示例

    class Vector:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __add__(self, other):
            if not isinstance(other, Vector):
                return NotImplemented
            return Vector(self.x + other.x, self.y + other.y)
    
        def __repr__(self):
            return f"Vector({self.x}, {self.y})"
    
        def __str__(self):
            return f"({self.x}, {self.y})"
    
    # 创建向量实例
    v1 = Vector(1, 2)
    v2 = Vector(3, 4)
    
    # 使用加法运算符
    v3 = v1 + v2
    print(v3)       # 使用 __str__ 输出: (4, 6)
    print(repr(v3)) # 使用 __repr__ 输出: Vector(4, 6)

    封装

    封装不仅涉及隐藏数据,还包括限制对对象内部状态的访问。可以通过属性访问控制来实现封装

    class Temperature:
        def __init__(self, celsius):
            self._celsius = celsius
    
        @property
        def celsius(self):
            return self._celsius
    
        @celsius.setter
        def celsius(self, value):
            if value < -273.15:
                raise ValueError("Temperature below absolute zero!")
            self._celsius = value
    
    temp = Temperature(25)
    print(temp.celsius)  # 输出: 25
    temp.celsius = 30
    print(temp.celsius)  # 输出: 30
    # temp.celsius = -300  # 这会引发 ValueError

    作者:校园日记

    物联沃分享整理
    物联沃-IOTWORD物联网 » python 面向对象超详细教学

    发表回复