python类和对象

Python 类和对象详解

一、类和对象的基本概念

类(Class):是创建对象的蓝图或模板,它定义了一组属性和方法,这些属性和方法描述了对象的行为和状态。

对象(Object):是类的实例,具有类所定义的属性和方法。

python 复制代码
# 定义类
class Dog:
    pass

# 创建对象
my_dog = Dog()

二、构造方法 __init__

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

python 复制代码
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'm {self.age} years old."

# 创建对象时传入参数
person1 = Person("Alice", 30)
person2 = Person("Bob", 25)

print(person1.greet())  # Hello, my name is Alice and I'm 30 years old.
print(person2.greet())  # Hello, my name is Bob and I'm 25 years old.

三、实例属性和类属性

1. 实例属性

  • 属于特定实例的属性
  • 通过 self__init__ 中定义
  • 每个实例都有自己独立的副本
python 复制代码
class Car:
    def __init__(self, brand, model):
        self.brand = brand  # 实例属性
        self.model = model  # 实例属性

car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Civic")

print(car1.brand, car1.model)  # Toyota Camry
print(car2.brand, car2.model)  # Honda Civic

2. 类属性

  • 属于类的属性,所有实例共享
  • 在类内部但在方法外部定义
python 复制代码
class Student:
    # 类属性
    school = "清华大学"
    student_count = 0
    
    def __init__(self, name):
        self.name = name  # 实例属性
        Student.student_count += 1  # 修改类属性
    
    @classmethod
    def get_school_info(cls):
        return f"学校:{cls.school},学生总数:{cls.student_count}"

# 访问类属性
print(Student.school)  # 清华大学

# 创建对象
s1 = Student("张三")
s2 = Student("李四")

print(s1.school)  # 清华大学
print(s2.school)  # 清华大学

# 修改类属性会影响所有实例
Student.school = "北京大学"
print(s1.school)  # 北京大学
print(s2.school)  # 北京大学

print(Student.get_school_info())  # 学校:北京大学,学生总数:2

四、实例方法、类方法和静态方法

1. 实例方法

  • 第一个参数是 self,表示实例本身
  • 只能通过实例调用
  • 可以访问和修改实例属性和类属性
python 复制代码
class Calculator:
    def __init__(self, value=0):
        self.value = value
    
    def add(self, x):
        self.value += x
        return self.value
    
    def multiply(self, x):
        self.value *= x
        return self.value

calc = Calculator(10)
print(calc.add(5))      # 15
print(calc.multiply(2)) # 30

2. 类方法

  • 使用 @classmethod 装饰器
  • 第一个参数是 cls,表示类本身
  • 可以通过类或实例调用
  • 主要用于操作类属性
python 复制代码
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)  # 相当于调用 Date(year, month, day)
    
    @classmethod
    def get_current_year(cls):
        import datetime
        return datetime.datetime.now().year

# 使用类方法创建对象
date1 = Date.from_string("2023-12-25")
print(f"{date1.year}-{date1.month}-{date1.day}")  # 2023-12-25

# 调用类方法
print(Date.get_current_year())  # 当前年份

3. 静态方法

  • 使用 @staticmethod 装饰器
  • 没有特殊参数(没有 selfcls
  • 可以通过类或实例调用
  • 与类和实例无关的工具函数
python 复制代码
class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def factorial(n):
        if n <= 1:
            return 1
        return n * MathUtils.factorial(n-1)

# 使用静态方法
print(MathUtils.add(5, 3))      # 8
print(MathUtils.factorial(5))   # 120

# 也可以通过实例调用
utils = MathUtils()
print(utils.add(10, 20))        # 30

五、访问控制

Python 没有严格的访问控制,但通过命名约定来实现:

  • 公有成员 :正常命名,如 name
  • 保护成员 :以一个下划线开头,如 _protected_var(提示性的,外部仍可访问)
  • 私有成员 :以两个下划线开头,如 __private_var(会进行名称修饰,实际上变为 _类名__private_var
python 复制代码
class BankAccount:
    def __init__(self, account_holder, initial_balance):
        self.account_holder = account_holder  # 公有
        self._account_number = "12345678"     # 保护(约定)
        self.__balance = initial_balance      # 私有(实际会被重命名)
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False
    
    def get_balance(self):
        return self.__balance  # 通过公共方法访问私有属性

account = BankAccount("Alice", 1000)

print(account.account_holder)      # Alice
print(account._account_number)     # 12345678(可以访问,但不建议)
# print(account.__balance)         # ❌ 报错:AttributeError
print(account._BankAccount__balance)  # 1000(可以通过修饰后的名字访问,但不推荐)

print(account.get_balance())       # 1000(推荐的方式)

六、属性装饰器 @property

@property 装饰器可以将方法变成属性,从而可以定义 getter、setter 和 deleter。

python 复制代码
class Circle:
    def __init__(self, radius):
        self._radius = radius  # 使用 _ 表示保护属性
    
    @property
    def radius(self):
        """radius属性的getter方法"""
        return self._radius
    
    @radius.setter
    def radius(self, value):
        """radius属性的setter方法"""
        if value < 0:
            raise ValueError("半径不能为负")
        self._radius = value
    
    @radius.deleter
    def radius(self):
        """radius属性的deleter方法"""
        print("删除半径")
        del self._radius
    
    @property
    def area(self):
        """只读属性,计算面积"""
        return 3.14159 * self._radius ** 2
    
    @property
    def diameter(self):
        """只读属性,计算直径"""
        return 2 * self._radius

circle = Circle(5)

# 使用属性
print(circle.radius)    # 5
print(circle.area)      # 78.53975
print(circle.diameter)  # 10

# 修改属性
circle.radius = 10
print(circle.area)      # 314.159

# 尝试设置负值
try:
    circle.radius = -5
except ValueError as e:
    print(f"错误:{e}")  # 错误:半径不能为负

# 删除属性
del circle.radius  # 输出:删除半径

# circle.area = 100   # ❌ 报错:只读属性

七、继承

继承允许一个类(子类)继承另一个类(父类)的属性和方法。

python 复制代码
# 父类(基类)
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def speak(self):
        return "动物叫声"
    
    def info(self):
        return f"{self.name},{self.age}岁"

# 子类(派生类)
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用父类的构造方法
        self.breed = breed
    
    def speak(self):  # 方法重写
        return "汪汪!"
    
    def info(self):
        # 扩展父类的方法
        base_info = super().info()
        return f"{base_info},品种:{self.breed}"

class Cat(Animal):
    def __init__(self, name, age, color):
        super().__init__(name, age)
        self.color = color
    
    def speak(self):
        return "喵喵!"
    
    def info(self):
        return f"{super().info()},颜色:{self.color}"

# 使用继承
dog = Dog("旺财", 3, "金毛")
cat = Cat("咪咪", 2, "白色")

print(dog.speak())  # 汪汪!
print(cat.speak())  # 喵喵!

print(dog.info())   # 旺财,3岁,品种:金毛
print(cat.info())   # 咪咪,2岁,颜色:白色

# 检查继承关系
print(isinstance(dog, Animal))  # True
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Cat))     # False

print(issubclass(Dog, Animal))  # True
print(issubclass(Cat, Animal))  # True

八、多继承

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

python 复制代码
class Flyable:
    def fly(self):
        return "我能飞"
    
    def take_off(self):
        return "起飞"

class Swimmable:
    def swim(self):
        return "我能游泳"
    
    def dive(self):
        return "潜水"

class Animal:
    def eat(self):
        return "吃东西"

# 多继承
class Duck(Animal, Flyable, Swimmable):
    def __init__(self, name):
        self.name = name
    
    def quack(self):
        return "嘎嘎叫"

duck = Duck("唐老鸭")

# 调用来自不同父类的方法
print(duck.eat())      # 吃东西
print(duck.fly())      # 我能飞
print(duck.swim())     # 我能游泳
print(duck.quack())    # 嘎嘎叫
print(duck.take_off()) # 起飞
print(duck.dive())     # 潜水

# 查看方法解析顺序(MRO)
print(Duck.__mro__)
# (<class '__main__.Duck'>, <class '__main__.Animal'>, 
#  <class '__main__.Flyable'>, <class '__main__.Swimmable'>, <class 'object'>)

九、特殊方法(魔术方法)

特殊方法以双下划线开头和结尾,用于实现类的特殊行为。

常见魔术方法:

python 复制代码
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # 字符串表示
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
    
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    
    # 算术运算
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    # 比较运算
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __lt__(self, other):
        return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
    
    # 容器行为
    def __len__(self):
        return 2
    
    def __getitem__(self, index):
        if index == 0:
            return self.x
        elif index == 1:
            return self.y
        else:
            raise IndexError("索引超出范围")
    
    # 调用对象
    def __call__(self, scale=1):
        return Vector(self.x * scale, self.y * scale)

# 使用魔术方法
v1 = Vector(2, 3)
v2 = Vector(4, 5)

print(v1)                # Vector(2, 3)
print(v1 + v2)           # Vector(6, 8)
print(v1 * 3)            # Vector(6, 9)
print(v1 == Vector(2, 3))  # True
print(v1 < v2)           # True
print(len(v1))           # 2
print(v1[0], v1[1])      # 2 3

# 调用对象
v3 = v1(2)  # 相当于 v1.__call__(2)
print(v3)   # Vector(4, 6)

更多魔术方法:

python 复制代码
class Book:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages
    
    # 上下文管理器
    def __enter__(self):
        print(f"开始阅读《{self.title}》")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"结束阅读《{self.title}》")
    
    # 描述符
    def __get__(self, instance, owner):
        print(f"获取书籍信息:{self.title}")
        return self
    
    # 迭代器
    def __iter__(self):
        self._current_page = 1
        return self
    
    def __next__(self):
        if self._current_page > self.pages:
            raise StopIteration
        page = self._current_page
        self._current_page += 1
        return f"第{page}页"
    
    # 类型转换
    def __int__(self):
        return self.pages
    
    def __float__(self):
        return float(self.pages)
    
    def __bool__(self):
        return self.pages > 0

# 使用上下文管理器
with Book("Python编程", "John", 300) as book:
    print(f"正在阅读 {book.title}")

# 迭代书籍
for page in Book("小说", "作者", 3):
    print(page)
# 输出:
# 第1页
# 第2页
# 第3页

十、抽象基类

抽象基类(Abstract Base Class, ABC)用于定义接口,不能被实例化,子类必须实现抽象方法。

python 复制代码
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        """计算面积"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """计算周长"""
        pass
    
    def info(self):
        """非抽象方法"""
        return f"这是一个形状,面积:{self.area()},周长:{self.perimeter()}"

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)

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

# 不能实例化抽象类
# shape = Shape()  # ❌ 报错:TypeError

# 实例化具体子类
rect = Rectangle(5, 3)
circle = Circle(4)

print(rect.area())       # 15
print(rect.perimeter())  # 16
print(rect.info())       # 这是一个形状,面积:15,周长:16

print(circle.area())     # 50.26544
print(circle.perimeter()) # 25.13272

十一、数据类(Python 3.7+)

数据类用于存储数据,自动生成特殊方法(如 __init____repr__)。

python 复制代码
from dataclasses import dataclass, field
from typing import List

@dataclass
class Point:
    x: float
    y: float
    color: str = "black"  # 默认值
    
    def distance_from_origin(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

@dataclass(order=True)  # 自动生成比较方法
class Person:
    name: str
    age: int
    hobbies: List[str] = field(default_factory=list)  # 默认工厂函数

# 自动生成 __init__、__repr__、__eq__ 等方法
p1 = Point(3, 4)
p2 = Point(3, 4, "red")
print(p1)  # Point(x=3, y=4, color='black')
print(p2)  # Point(x=3, y=4, color='red')
print(p1 == Point(3, 4))  # True

# 排序
person1 = Person("Alice", 30, ["reading", "swimming"])
person2 = Person("Bob", 25)
person3 = Person("Charlie", 25, ["gaming"])

people = [person1, person2, person3]
print(sorted(people))  # 按 name 和 age 排序

十二、枚举类

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

python 复制代码
from enum import Enum, auto

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# 自动赋值
class Status(Enum):
    PENDING = auto()  # 1
    RUNNING = auto()  # 2
    COMPLETED = auto()  # 3
    FAILED = auto()   # 4

# 使用枚举
print(Color.RED)          # Color.RED
print(Color.RED.value)    # 1
print(Color.RED.name)     # RED

# 遍历枚举
for color in Color:
    print(color.name, color.value)

# 通过值获取枚举
print(Color(1))           # Color.RED
print(Color['RED'])       # Color.RED

# 枚举比较
print(Color.RED is Color.RED)     # True
print(Color.RED == Color.RED)     # True
print(Color.RED == Color.GREEN)   # False

十三、__slots__ 优化内存

使用 __slots__ 可以限制类的属性,减少内存占用。

python 复制代码
class RegularClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class SlotsClass:
    __slots__ = ['x', 'y']  # 只能有这些属性
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

# 创建对象
regular = RegularClass(1, 2)
slotted = SlotsClass(1, 2)

# 添加新属性
regular.z = 3  # 可以
# slotted.z = 3  # ❌ 报错:AttributeError

import sys
print(f"RegularClass 内存占用: {sys.getsizeof(regular)} 字节")
print(f"SlotsClass 内存占用: {sys.getsizeof(slotted)} 字节")

十四、单例模式

python 复制代码
class Singleton:
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self, name):
        if not hasattr(self, 'initialized'):  # 防止重复初始化
            self.name = name
            self.initialized = True

s1 = Singleton("实例1")
s2 = Singleton("实例2")

print(s1 is s2)  # True
print(s1.name)   # 实例1
print(s2.name)   # 实例1(实际上指向同一个对象)

十五、类装饰器

类也可以作为装饰器:

python 复制代码
class DecoratorClass:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        print("装饰器逻辑 - 前")
        result = self.func(*args, **kwargs)
        print("装饰器逻辑 - 后")
        return result

@DecoratorClass
def my_function():
    print("原始函数")

my_function()

十六、最佳实践

  1. 遵循命名约定

    • 类名使用驼峰式:MyClass
    • 方法和变量使用蛇形命名:my_method
    • 私有成员使用下划线前缀:_private
  2. 单一职责原则

    • 一个类只做一件事
  3. 优先使用组合而不是继承

    python 复制代码
    # 使用组合
    class Engine:
        def start(self):
            return "引擎启动"
    
    class Car:
        def __init__(self):
            self.engine = Engine()  # 组合
        
        def start(self):
            return self.engine.start()
  4. 使用类型注解

    python 复制代码
    class Point:
        def __init__(self, x: float, y: float) -> None:
            self.x = x
            self.y = y
        
        def move(self, dx: float, dy: float) -> 'Point':
            return Point(self.x + dx, self.y + dy)

总结

Python 的类和对象提供了强大的面向对象编程能力。通过类,我们可以封装数据和行为,通过继承和多态实现代码复用,通过特殊方法自定义类的行为。掌握这些概念对于编写可维护、可扩展的 Python 代码至关重要。

相关推荐
鸡吃丸子2 小时前
React Native入门详解
开发语言·前端·javascript·react native·react.js
盼哥PyAI实验室2 小时前
Python YAML配置管理:12306项目的灵活配置方案
开发语言·python
漂亮的小碎步丶2 小时前
【启】Java中高级开发51天闭关冲刺计划(聚焦运营商/ToB领域)
java·开发语言
hd51cc2 小时前
MFC运行时
开发语言·mfc
wniuniu_2 小时前
ceph一些细节处理
开发语言·ceph
hd51cc2 小时前
异常处理(Exception Handling)
开发语言
SadSunset2 小时前
(19)Bean的循环依赖问题
java·开发语言·前端
JIngJaneIL2 小时前
基于Java+ vue图书管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
Github掘金计划3 小时前
开发者狂喜!GitHub 官方开源:支持 Copilot/Cursor,规范即代码,27k Star 封神!
java·python·kafka·github·copilot