← 返回首页
🐍

面向对象高级

📂 python ⏱ 2 min 395 words

类方法

类方法使用@classmethod装饰器定义,它接收类本身作为第一个参数,而不是实例。

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls, date_string):
        year, month, day = map(int, date_string.split('-'))
        return cls(year, month, day)

    @classmethod
    def today(cls):
        from datetime import date
        today = date.today()
        return cls(today.year, today.month, today.day)

# 使用类方法
date1 = Date(2024, 1, 15)
date2 = Date.from_string("2024-06-20")
date3 = Date.today()

print(date1.year)  # 输出: 2024
print(date2.month) # 输出: 6

静态方法

静态方法使用@staticmethod装饰器定义,它不接收类或实例作为参数。

class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b

    @staticmethod
    def is_even(number):
        return number % 2 == 0

    @staticmethod
    def factorial(n):
        if n < 0:
            raise ValueError("负数没有阶乘")
        if n == 0 or n == 1:
            return 1
        return n * MathUtils.factorial(n - 1)

# 使用静态方法
print(MathUtils.add(3, 5))      # 输出: 8
print(MathUtils.is_even(4))     # 输出: True
print(MathUtils.factorial(5))   # 输出: 120

属性装饰器

属性装饰器让你可以像访问属性一样调用方法,实现计算属性和数据验证。

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """获取半径"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """设置半径,确保为正数"""
        if value <= 0:
            raise ValueError("半径必须为正数")
        self._radius = value

    @property
    def area(self):
        """计算面积(只读属性)"""
        return 3.14159 * self._radius ** 2

    @property
    def circumference(self):
        """计算周长(只读属性)"""
        return 2 * 3.14159 * self._radius

# 使用属性
circle = Circle(5)
print(circle.radius)        # 输出: 5
print(circle.area)          # 输出: 78.53975
print(circle.circumference) # 输出: 31.4159

circle.radius = 10
print(circle.area)          # 输出: 314.159

抽象类

抽象类使用abc模块定义,它不能被实例化,用于定义接口规范。

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        """计算面积"""
        pass

    @abstractmethod
    def perimeter(self):
        """计算周长"""
        pass

    def describe(self):
        """非抽象方法,可以有默认实现"""
        return f"这是一个形状,面积是{self.area()},周长是{self.perimeter()}"

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius ** 2

    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

# 使用抽象类
circle = Circle(5)
rectangle = Rectangle(4, 6)

print(circle.describe())
print(rectangle.describe())

数据类

Python 3.7+引入了dataclasses模块,简化类的创建。

from dataclasses import dataclass, field
from typing import List

@dataclass
class Student:
    name: str
    age: int
    grades: List[float] = field(default_factory=list)

    @property
    def average_grade(self):
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)

    def __post_init__(self):
        """初始化后处理"""
        if self.age < 0:
            raise ValueError("年龄不能为负数")

# 使用数据类
student1 = Student("张三", 20, [85, 90, 95])
student2 = Student("李四", 22)

print(student1)  # 输出: Student(name='张三', age=20, grades=[85, 90, 95])
print(student1.average_grade)  # 输出: 90.0

枚举类

枚举类用于定义一组命名的常量值。

from enum import Enum, auto

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

class Direction(Enum):
    NORTH = "北"
    SOUTH = "南"
    EAST = "东"
    WEST = "西"

# 使用枚举
print(Color.RED)        # 输出: Color.RED
print(Color.RED.value)  # 输出: 1
print(Direction.NORTH.value)  # 输出: 北

# 枚举比较
print(Color.RED == Color.RED)    # 输出: True
print(Color.RED == Color.GREEN)  # 输出: False

最佳实践

掌握这些高级面向对象特性,能让你写出更加Pythonic的代码。