面向对象编程(OOP)是一种程序设计范式,通过“对象”来组织代码。本章将学习Python中类和对象的基本概念,包括封装、继承和多态等核心特性。
面向对象编程的核心概念:
使用 ``class`` 关键字定义类。
class Dog: """狗的类""" # 类属性(所有实例共享) species = "Canis familiaris" # 构造方法 def __init__(self, name, age): """初始化方法""" self.name = name # 实例属性 self.age = age # 实例方法 def bark(self): """狗叫""" return f"{self.name} says: Woof!" def get_info(self): """获取狗的信息""" return f"{self.name} is {self.age} years old" # 创建对象 buddy = Dog("Buddy", 3) miles = Dog("Miles", 5) # 访问属性和方法 print(buddy.name) # Buddy print(buddy.bark()) # Buddy says: Woof! print(buddy.get_info()) # Buddy is 3 years old
class Person: def __init__(self, name, age=0): """ 构造方法 self代表类的实例,必须作为第一个参数 """ self.name = name self.age = age self._id = None # 内部属性 def introduce(self): return f"Hi, I'm {self.name}, {self.age} years old." # 创建对象 person1 = Person("Alice", 25) person2 = Person("Bob") # 使用默认年龄
class Example: def __init__(self, value): self.value = value # 给实例添加属性 def show(self): print(f"Value: {self.value}") def update(self, new_value): self.value = new_value # self会自动传递 obj = Example(10) obj.show() # 实际是 Example.show(obj) obj.update(20) # 实际是 Example.update(obj, 20)
class Car: # 类属性 - 所有实例共享 wheels = 4 def __init__(self, brand, color): # 实例属性 - 每个实例独立 self.brand = brand self.color = color self.odometer = 0 # 使用 car1 = Car("Toyota", "Red") car2 = Car("Honda", "Blue") print(car1.wheels) # 4 print(car2.wheels) # 4 # 修改类属性 Car.wheels = 3 print(car1.wheels) # 3 print(car2.wheels) # 3 # 给实例添加属性(不影响其他实例) car1.wheels = 5 print(car1.wheels) # 5(实例属性) print(car2.wheels) # 3(类属性)
class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self._balance = balance # 约定:受保护属性 self.__transaction_log = [] # 名称修饰:私有属性 def deposit(self, amount): if amount > 0: self._balance += amount self.__transaction_log.append(f"+{amount}") def get_balance(self): return self._balance account = BankAccount("Alice", 100) # 可以访问,但不建议 print(account._balance) # 100 # 名称修饰后的私有属性 # print(account.__transaction_log) # AttributeError print(account._BankAccount__transaction_log) # 可以访问,但不建议
class Temperature: def __init__(self, celsius=0): self._celsius = celsius @property def celsius(self): """获取摄氏度""" return self._celsius @celsius.setter def celsius(self, value): """设置摄氏度""" if value < -273.15: raise ValueError("温度不能低于绝对零度") self._celsius = value @property def fahrenheit(self): """获取华氏度(计算属性)""" return self._celsius * 9/5 + 32 @fahrenheit.setter def fahrenheit(self, value): """设置华氏度""" self._celsius = (value - 32) * 5/9 # 使用 temp = Temperature(25) print(temp.celsius) # 25(像属性一样访问) temp.celsius = 30 # 像属性一样设置 print(temp.fahrenheit) # 86.0
class Circle: pi = 3.14159 def __init__(self, radius): self.radius = radius # 实例方法 - 可以访问实例和类 def area(self): return self.pi * self.radius ** 2 def circumference(self): return 2 * self.pi * self.radius
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): """创建今天的日期""" import datetime now = datetime.datetime.now() return cls(now.year, now.month, now.day) def __str__(self): return f"{self.year}-{self.month:02d}-{self.day:02d}" # 使用 birthday = Date.from_string("1990-05-15") today = Date.today() print(birthday) # 1990-05-15 print(today)
class MathUtils: @staticmethod def add(x, y): """静态方法,不需要self或cls""" return x + y @staticmethod def is_prime(n): if n < 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True # 使用(通过类或实例调用都可以) print(MathUtils.add(3, 5)) # 8 print(MathUtils.is_prime(17)) # True
# 父类(基类) class Animal: def __init__(self, name): self.name = name def speak(self): raise NotImplementedError("子类必须实现此方法") def introduce(self): return f"I am {self.name}" # 子类(派生类) class Dog(Animal): def __init__(self, name, breed): super().__init__(name) # 调用父类构造方法 self.breed = breed def speak(self): return f"{self.name} says: Woof!" class Cat(Animal): def speak(self): return f"{self.name} says: Meow!" # 使用 dog = Dog("Buddy", "Golden Retriever") cat = Cat("Whiskers") print(dog.speak()) # Buddy says: Woof! print(cat.speak()) # Whiskers says: Meow! print(dog.introduce()) # I am Buddy(继承的方法)
class Rectangle: 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 Square(Rectangle): def __init__(self, side): super().__init__(side, side) # 调用父类构造 self.side = side def area(self): # 调用父类方法 return super().area() def diagonal(self): return self.side * (2 ** 0.5) square = Square(5) print(square.area()) # 25 print(square.perimeter()) # 20
class Flyable: def fly(self): return "I can fly!" class Swimmable: def swim(self): return "I can swim!" class Duck(Animal, Flyable, Swimmable): def speak(self): return f"{self.name} says: Quack!" duck = Duck("Donald") print(duck.speak()) # Donald says: Quack! print(duck.fly()) # I can fly! print(duck.swim()) # I can swim!
class A: def method(self): return "A" class B(A): def method(self): return "B" class C(A): def method(self): return "C" class D(B, C): pass print(D.method()) # B(按MRO顺序) print(D.__mro__) # (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
Python是动态类型语言,通过“鸭子类型”实现多态。
class Dog: def speak(self): return "Woof!" def move(self): return "Running on 4 legs" class Bird: def speak(self): return "Tweet!" def move(self): return "Flying in the sky" class Fish: def speak(self): return "Blub!" def move(self): return "Swimming in water" # 多态函数 def animal_concert(animals): for animal in animals: print(f"{type(animal).__name__}: {animal.speak()}") # 不同的对象,相同的方法调用 animals = [Dog(), Bird(), Fish()] animal_concert(animals)
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): """计算面积""" pass @abstractmethod def perimeter(self): """计算周长""" pass 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): import math return math.pi * self.radius ** 2 def perimeter(self): import math return 2 * math.pi * self.radius # shape = Shape() # 错误!不能实例化抽象类 rect = Rectangle(3, 4) circle = Circle(5) shapes = [rect, circle] for shape in shapes: print(f"{type(shape).__name__}: Area={shape.area():.2f}")
class BankAccount: def __init__(self, owner, balance=0): self._owner = owner self._balance = balance @property def balance(self): """只读属性:余额""" return self._balance @property def owner(self): """只读属性:所有者""" return self._owner def deposit(self, amount): """存款""" if amount <= 0: raise ValueError("存款金额必须大于0") self._balance += amount return self._balance def withdraw(self, amount): """取款""" if amount <= 0: raise ValueError("取款金额必须大于0") if amount > self._balance: raise ValueError("余额不足") self._balance -= amount return self._balance # 使用 account = BankAccount("Alice", 1000) account.deposit(500) account.withdraw(200) print(account.balance) # 1300 # account.balance = 5000 # AttributeError: can't set attribute
from datetime import datetime, timedelta class Book: def __init__(self, isbn, title, author): self.isbn = isbn self.title = title self.author = author self.is_borrowed = False self.due_date = None def borrow(self, days=14): if self.is_borrowed: return False self.is_borrowed = True self.due_date = datetime.now() + timedelta(days=days) return True def return_book(self): if not self.is_borrowed: return False self.is_borrowed = False self.due_date = None return True def __str__(self): status = "已借出" if self.is_borrowed else "可借阅" return f"《{self.title}》- {self.author} [{status}]" class Member: def __init__(self, member_id, name): self.member_id = member_id self.name = name self.borrowed_books = [] self.max_books = 5 def borrow_book(self, book): if len(self.borrowed_books) >= self.max_books: return False, "已达最大借书数量" if book.borrow(): self.borrowed_books.append(book) return True, f"成功借阅《{book.title}》" return False, "该书已被借出" def return_book(self, book): if book in self.borrowed_books: book.return_book() self.borrowed_books.remove(book) return True, f"成功归还《{book.title}》" return False, "未借阅该书" # 使用示例 library = [] member = Member("M001", "张三") book1 = Book("978-7-111", "Python编程", "张三") book2 = Book("978-7-112", "数据结构与算法", "李四") library.extend([book1, book2]) success, msg = member.borrow_book(book1) print(msg) print(book1)
import math from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass def __str__(self): return f"{self.__class__.__name__}: area={self.area():.2f}" 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 math.pi * self.radius ** 2 def perimeter(self): return 2 * math.pi * self.radius class Triangle(Shape): def __init__(self, a, b, c): self.a = a self.b = b self.c = c def area(self): s = self.perimeter() / 2 return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c)) def perimeter(self): return self.a + self.b + self.c def calculate_total_area(shapes): return sum(shape.area() for shape in shapes) # 使用 shapes = [Rectangle(3, 4), Circle(5), Triangle(3, 4, 5)] for shape in shapes: print(shape) print(f"总面积: {calculate_total_area(shapes):.2f}")
class Vector: def __init__(self, x, y): self.x = x self.y = 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 __str__(self): return f"Vector({self.x}, {self.y})" def magnitude(self): return (self.x ** 2 + self.y ** 2) ** 0.5 # 测试 v1 = Vector(3, 4) v2 = Vector(1, 2) print(v1 + v2) # Vector(4, 6) print(v1 * 2) # Vector(6, 8) print(v1.magnitude()) # 5.0
class Stack: def __init__(self): self._items = [] def push(self, item): self._items.append(item) def pop(self): if self.is_empty(): raise IndexError("栈为空") return self._items.pop() def peek(self): if self.is_empty(): raise IndexError("栈为空") return self._items[-1] def is_empty(self): return len(self._items) == 0 def size(self): return len(self._items) def __str__(self): return f"Stack({self._items})" # 测试 stack = Stack() stack.push(1) stack.push(2) stack.push(3) print(stack.pop()) # 3 print(stack) # Stack([1, 2])
本章学习了面向对象编程的核心概念:
面向对象编程让代码更加模块化、可维护和可扩展。下一章将学习更多高级OOP特性。