Python入门(9)--类与对象基础
Python类与对象基础 🐍
1. 类的定义与实例化 📝
在Python中,类是创建对象的蓝图。让我们从一个简单的例子开始:
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!"
# 创建实例
buddy = Dog("Buddy", 5)
max_dog = Dog("Max", 3)
# 访问属性和方法
print(buddy.name) # 输出: Buddy
print(max_dog.species) # 输出: Canis familiaris
print(buddy.bark()) # 输出: Buddy says Woof!
1.1 类变量 vs 实例变量
class Counter:
total_count = 0 # 类变量
def __init__(self, name):
self.name = name # 实例变量
self.count = 0 # 实例变量
Counter.total_count += 1
def increment(self):
self.count += 1
# 创建计数器实例
counter1 = Counter("First")
counter2 = Counter("Second")
print(Counter.total_count) # 输出: 2
print(counter1.count) # 输出: 0
counter1.increment()
print(counter1.count) # 输出: 1
print(counter2.count) # 输出: 0
2. 属性与方法 🔧
2.1 属性装饰器
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("Temperature below absolute zero!")
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
print(temp.fahrenheit) # 输出: 77.0
temp.fahrenheit = 86 # 通过fahrenheit设置温度
print(temp.celsius) # 输出: 30
2.2 方法类型
class MathOperations:
pi = 3.14159
def __init__(self, value):
self.value = value
# 实例方法
def square(self):
return self.value ** 2
# 类方法
@classmethod
def from_string(cls, string_value):
try:
value = float(string_value)
return cls(value)
except ValueError:
raise ValueError("Invalid string value")
# 静态方法
@staticmethod
def is_positive(number):
return number > 0
# 使用不同类型的方法
math_ops = MathOperations(5)
print(math_ops.square()) # 实例方法:25
new_ops = MathOperations.from_string("10") # 类方法
print(MathOperations.is_positive(-5)) # 静态方法:False
3. 构造函数与析构函数 🏗️
class FileHandler:
def __init__(self, filename):
"""构造函数"""
print(f"Opening file {filename}")
self.filename = filename
self.file = open(filename, 'w')
def write_content(self, content):
self.file.write(content)
def __del__(self):
"""析构函数"""
print(f"Closing file {self.filename}")
self.file.close()
# 使用with语句更好的管理资源
class DatabaseConnection:
def __init__(self, host, port):
print(f"Connecting to {host}:{port}")
self.host = host
self.port = port
def __enter__(self):
"""上下文管理器的进入方法"""
print("Starting transaction")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""上下文管理器的退出方法"""
print("Closing connection and committing transaction")
return True
# 使用示例
with DatabaseConnection("localhost", 5432) as db:
print("Performing database operations")
4. 实战案例:宠物商店管理系统 🏪
现在让我们创建一个简单的宠物商店管理系统,整合我们学到的所有概念:
from datetime import datetime, timedelta
from typing import List, Optional
class Pet:
"""宠物基类"""
def __init__(self, name: str, age: int, price: float):
self.name = name
self.age = age
self.price = price
self.arrival_date = datetime.now()
self.adopted = False
def get_info(self) -> str:
status = "已被领养" if self.adopted else "等待领养"
return f"{self.name} (年龄: {self.age}岁, 价格: ¥{self.price}, 状态: {status})"
class Dog(Pet):
"""狗类"""
def __init__(self, name: str, age: int, price: float, breed: str):
super().__init__(name, age, price)
self.breed = breed
def get_info(self) -> str:
return f"狗狗 - {super().get_info()}, 品种: {self.breed}"
class Cat(Pet):
"""猫类"""
def __init__(self, name: str, age: int, price: float, color: str):
super().__init__(name, age, price)
self.color = color
def get_info(self) -> str:
return f"猫咪 - {super().get_info()}, 毛色: {self.color}"
class PetShop:
"""宠物商店类"""
def __init__(self, name: str):
self.name = name
self._pets: List[Pet] = []
self._adoption_records = []
@property
def available_pets(self) -> List[Pet]:
"""获取可领养的宠物列表"""
return [pet for pet in self._pets if not pet.adopted]
def add_pet(self, pet: Pet) -> None:
"""添加新宠物"""
self._pets.append(pet)
print(f"新宠物 {pet.name} 已添加到商店")
def adopt_pet(self, pet: Pet, adopter_name: str) -> bool:
"""处理宠物领养"""
if pet not in self._pets or pet.adopted:
return False
pet.adopted = True
record = {
'date': datetime.now(),
'pet': pet,
'adopter': adopter_name
}
self._adoption_records.append(record)
return True
def get_adoption_history(self) -> List[dict]:
"""获取领养历史"""
return self._adoption_records
def search_pets(self, max_price: Optional[float] = None,
pet_type: Optional[str] = None) -> List[Pet]:
"""搜索符合条件的宠物"""
results = []
for pet in self.available_pets:
if max_price and pet.price > max_price:
continue
if pet_type:
if pet_type.lower() == "dog" and not isinstance(pet, Dog):
continue
if pet_type.lower() == "cat" and not isinstance(pet, Cat):
continue
results.append(pet)
return results
# 使用示例
def main():
# 创建宠物商店
shop = PetShop("快乐宠物屋")
# 添加一些宠物
shop.add_pet(Dog("旺财", 2, 2000, "金毛"))
shop.add_pet(Dog("大黄", 1, 1500, "柴犬"))
shop.add_pet(Cat("咪咪", 1, 1000, "橘色"))
shop.add_pet(Cat("小花", 3, 1200, "三花"))
# 显示所有可用宠物
print("\n当前可领养的宠物:")
for pet in shop.available_pets:
print(pet.get_info())
# 搜索价格在1500以下的宠物
print("\n1500元以下的宠物:")
for pet in shop.search_pets(max_price=1500):
print(pet.get_info())
# 领养一只宠物
if shop.available_pets:
pet_to_adopt = shop.available_pets[0]
if shop.adopt_pet(pet_to_adopt, "张三"):
print(f"\n恭喜!{pet_to_adopt.name} 已经被张三领养")
# 显示领养历史
print("\n领养历史:")
for record in shop.get_adoption_history():
print(f"{record['date']:%Y-%m-%d}: "
f"{record['pet'].name} 被 {record['adopter']} 领养")
if __name__ == "__main__":
main()
系统特点:
- 类的继承体系:使用
Pet
作为基类,Dog
和Cat
作为子类 - 属性管理:使用实例变量存储宠物信息
- 方法实现:包含实例方法和属性方法
- 类型提示:使用
typing
模块增加代码可读性 - 错误处理:在领养过程中包含适当的检查
- 数据封装:使用私有属性存储宠物和领养记录
- 功能完整:支持添加宠物、领养、搜索和历史记录查询
扩展建议:
- 添加更多宠物类型
- 实现库存管理功能
- 添加宠物健康状态追踪
- 实现会员管理系统
- 添加交易记录和财务统计
- 实现数据持久化存储
- 添加用户界面(CLI或GUI)
这个实战案例展示了类和对象的实际应用,涵盖了面向对象编程的核心概念,并提供了一个可扩展的基础框架。
5. 高级特性与最佳实践 🚀
5.1 数据类(Python 3.7+)
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime
@dataclass
class Product:
name: str
price: float
stock: int = 0
created_at: datetime = datetime.now()
description: Optional[str] = None
def is_available(self) -> bool:
return self.stock > 0
def update_stock(self, quantity: int) -> None:
new_stock = self.stock + quantity
if new_stock < 0:
raise ValueError("Stock cannot be negative")
self.stock = new_stock
# 使用数据类
laptop = Product("MacBook Pro", 1299.99, 10)
print(laptop) # 自动实现的__str__方法
laptop.update_stock(-5)
print(laptop.stock) # 输出: 5
5.2 抽象基类(ABC)
from abc import ABC, abstractmethod
from typing import Protocol
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount: float) -> bool:
"""处理支付"""
pass
@abstractmethod
def refund(self, amount: float) -> bool:
"""处理退款"""
pass
class AliPayProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
print(f"使用支付宝处理 ¥{amount} 的支付")
return True
def refund(self, amount: float) -> bool:
print(f"使用支付宝处理 ¥{amount} 的退款")
return True
class WeChatPayProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
print(f"使用微信支付处理 ¥{amount} 的支付")
return True
def refund(self, amount: float) -> bool:
print(f"使用微信支付处理 ¥{amount} 的退款")
return True
# 使用Protocol进行静态类型检查
class Discountable(Protocol):
def calculate_discount(self, price: float) -> float:
...
class VIPCustomer:
def calculate_discount(self, price: float) -> float:
return price * 0.9
def apply_discount(item: Discountable, price: float) -> float:
return item.calculate_discount(price)
5.3 混入类(Mixins)
class LoggerMixin:
def log(self, message: str) -> None:
print(f"[{self.__class__.__name__}] {message}")
class TimestampMixin:
def get_timestamp(self) -> str:
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
class JSONSerializableMixin:
def to_json(self) -> dict:
return {
key: value for key, value in self.__dict__.items()
if not key.startswith('_')
}
class Order(LoggerMixin, TimestampMixin, JSONSerializableMixin):
def __init__(self, order_id: str, amount: float):
self.order_id = order_id
self.amount = amount
self.created_at = self.get_timestamp()
self.log(f"Created order {order_id} with amount ¥{amount}")
def process(self) -> None:
self.log(f"Processing order {self.order_id}")
# 处理订单逻辑...
# 使用混入类
order = Order("ORD001", 299.99)
print(order.to_json())
5.4 描述符(Descriptors)
class ValidString:
def __init__(self, minlen: int = 1, maxlen: int = 50):
self.minlen = minlen
self.maxlen = maxlen
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__.get(f"_{owner.__name__}")
def __set__(self, instance, value: str):
if not isinstance(value, str):
raise TypeError("Value must be a string")
if not self.minlen <= len(value) <= self.maxlen:
raise ValueError(
f"String length must be between {self.minlen} and {self.maxlen}"
)
instance.__dict__[f"_{instance.__class__.__name__}"] = value
class ValidEmail:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__.get("_email")
def __set__(self, instance, value: str):
import re
if not isinstance(value, str):
raise TypeError("Email must be a string")
if not re.match(r"[^@]+@[^@]+\.[^@]+", value):
raise ValueError("Invalid email format")
instance.__dict__["_email"] = value
class User:
name = ValidString(minlen=2, maxlen=30)
email = ValidEmail()
def __init__(self, name: str, email: str):
self.name = name
self.email = email
# 使用描述符
try:
user = User("张三", "zhangsan@example.com")
print(f"用户名: {user.name}")
print(f"邮箱: {user.email}")
# 这将引发ValueError
user.name = "A" # 名字太短
except ValueError as e:
print(f"错误: {e}")
5.5 上下文管理器进阶
from contextlib import contextmanager
from typing import Generator, Any
class DatabaseTransaction:
def __init__(self, connection_string: str):
self.connection_string = connection_string
def __enter__(self):
print(f"开始事务: 连接到 {self.connection_string}")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
print("提交事务")
else:
print(f"回滚事务: {exc_val}")
print("关闭连接")
return True # 抑制异常
@contextmanager
def timer() -> Generator[None, Any, None]:
"""计时器上下文管理器"""
from time import time
start = time()
yield
end = time()
print(f"执行时间: {end - start:.2f} 秒")
# 使用示例
def process_data():
with DatabaseTransaction("postgresql://localhost:5432/db") as transaction:
print("执行数据库操作")
# raise Exception("模拟错误")
def compute_intensive_task():
with timer():
# 模拟耗时操作
sum(i * i for i in range(1000000))
# 测试上下文管理器
process_data()
compute_intensive_task()
6. 设计模式实践 🎯
6.1 单例模式(Singleton Pattern)
from typing import Optional
import threading
class Singleton:
_instance: Optional['Singleton'] = None
_lock = threading.Lock()
def __new__(cls):
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
# 确保初始化只执行一次
if not hasattr(self, 'initialized'):
self.initialized = True
self.config = {}
@classmethod
def get_instance(cls) -> 'Singleton':
if cls._instance is None:
cls._instance = Singleton()
return cls._instance
class ConfigManager(Singleton):
"""配置管理器 - 单例模式示例"""
def __init__(self):
super().__init__()
if not hasattr(self, 'config_loaded'):
self.config_loaded = True
self.settings = {
'debug': False,
'api_key': None,
'max_connections': 100
}
def get_setting(self, key: str) -> Any:
return self.settings.get(key)
def update_setting(self, key: str, value: Any) -> None:
self.settings[key] = value
# 使用示例
config1 = ConfigManager()
config2 = ConfigManager()
print(config1 is config2) # 输出: True
config1.update_setting('debug', True)
print(config2.get_setting('debug')) # 输出: True
6.2 工厂模式(Factory Pattern)
from abc import ABC, abstractmethod
from typing import Dict, Type
# 产品接口
class Document(ABC):
@abstractmethod
def create(self) -> str:
pass
# 具体产品
class PDFDocument(Document):
def create(self) -> str:
return "创建PDF文档"
class WordDocument(Document):
def create(self) -> str:
return "创建Word文档"
class ExcelDocument(Document):
def create(self) -> str:
return "创建Excel文档"
# 工厂类
class DocumentFactory:
_document_types: Dict[str, Type[Document]] = {
'pdf': PDFDocument,
'word': WordDocument,
'excel': ExcelDocument
}
@classmethod
def create_document(cls, doc_type: str) -> Document:
document_class = cls._document_types.get(doc_type.lower())
if document_class is None:
raise ValueError(f"不支持的文档类型: {doc_type}")
return document_class()
@classmethod
def register_document_type(cls, type_name: str,
document_class: Type[Document]) -> None:
cls._document_types[type_name.lower()] = document_class
# 使用示例
factory = DocumentFactory()
pdf_doc = factory.create_document('pdf')
word_doc = factory.create_document('word')
print(pdf_doc.create()) # 输出: 创建PDF文档
print(word_doc.create()) # 输出: 创建Word文档
6.3 观察者模式(Observer Pattern)
from typing import List, Protocol
from datetime import datetime
class Observer(Protocol):
def update(self, message: str) -> None:
pass
class Subject:
def __init__(self):
self._observers: List[Observer] = []
def attach(self, observer: Observer) -> None:
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer: Observer) -> None:
self._observers.remove(observer)
def notify(self, message: str) -> None:
for observer in self._observers:
observer.update(message)
class NewsAgency(Subject):
def publish_news(self, news: str) -> None:
print(f"\n新闻发布: {news}")
self.notify(f"[{datetime.now():%Y-%m-%d %H:%M:%S}] {news}")
class NewsSubscriber:
def __init__(self, name: str):
self.name = name
def update(self, message: str) -> None:
print(f"订阅者 {self.name} 收到消息: {message}")
# 使用示例
agency = NewsAgency()
subscriber1 = NewsSubscriber("张三")
subscriber2 = NewsSubscriber("李四")
agency.attach(subscriber1)
agency.attach(subscriber2)
agency.publish_news("Python 3.12 发布了!")
6.4 策略模式(Strategy Pattern)
from typing import Protocol, Dict, Type
from decimal import Decimal
class PricingStrategy(Protocol):
def calculate_price(self, base_price: Decimal) -> Decimal:
pass
class RegularPricing:
def calculate_price(self, base_price: Decimal) -> Decimal:
return base_price
class VIPPricing:
def calculate_price(self, base_price: Decimal) -> Decimal:
return base_price * Decimal('0.8')
class FlashSalePricing:
def calculate_price(self, base_price: Decimal) -> Decimal:
return base_price * Decimal('0.5')
class PriceCalculator:
_strategies: Dict[str, Type[PricingStrategy]] = {
'regular': RegularPricing,
'vip': VIPPricing,
'flash_sale': FlashSalePricing
}
@classmethod
def calculate(cls, strategy_name: str, base_price: Decimal) -> Decimal:
strategy_class = cls._strategies.get(strategy_name)
if strategy_class is None:
raise ValueError(f"未知的定价策略: {strategy_name}")
return strategy_class().calculate_price(base_price)
# 使用示例
base_price = Decimal('100.00')
print(f"原价: ¥{base_price}")
print(f"VIP价: ¥{PriceCalculator.calculate('vip', base_price)}")
print(f"秒杀价: ¥{PriceCalculator.calculate('flash_sale', base_price)}")
7. 实战案例:电商订单系统 🛒
这个案例展示了如何将前面学到的概念应用到实际项目中:
from dataclasses import dataclass
from datetime import datetime
from decimal import Decimal
from typing import List, Optional, Dict
from enum import Enum
import json
# 订单状态枚举
class OrderStatus(Enum):
PENDING = "pending"
PAID = "paid"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
# 数据类
@dataclass
class Product:
id: str
name: str
price: Decimal
stock: int
def __post_init__(self):
self.price = Decimal(str(self.price))
@dataclass
class OrderItem:
product: Product
quantity: int
@property
def subtotal(self) -> Decimal:
return self.product.price * self.quantity
# 混入类
class JSONSerializableMixin:
def to_json(self) -> str:
return json.dumps(self, default=lambda o: o.__dict__)
# 订单类
class Order(JSONSerializableMixin):
def __init__(self, order_id: str, customer_id: str):
self.order_id = order_id
self.customer_id = customer_id
self.items: List[OrderItem] = []
self.status = OrderStatus.PENDING
self.created_at = datetime.now()
self.total_amount = Decimal('0')
self._observers: List[Observer] = []
def add_item(self, product: Product, quantity: int) -> None:
if product.stock < quantity:
raise ValueError(f"商品 {product.name} 库存不足")
item = OrderItem(product, quantity)
self.items.append(item)
self.total_amount += item.subtotal
product.stock -= quantity
def remove_item(self, product: Product) -> None:
for item in self.items:
if item.product.id == product.id:
self.total_amount -= item.subtotal
product.stock += item.quantity
self.items.remove(item)
break
def update_status(self, status: OrderStatus) -> None:
self.status = status
self.notify_observers()
def attach_observer(self, observer: Observer) -> None:
if observer not in self._observers:
self._observers.append(observer)
def notify_observers(self) -> None:
for observer in self._observers:
observer.update(
f"订单 {self.order_id} 状态更新为: {self.status.value}"
)
# 订单管理系统
class OrderManagementSystem:
def __init__(self):
self._orders: Dict[str, Order] = {}
self._products: Dict[str, Product] = {}
def create_order(self, customer_id: str) -> Order:
order_id = f"ORD{len(self._orders) + 1:06d}"
order = Order(order_id, customer_id)
self._orders[order_id] = order
return order
def get_order(self, order_id: str) -> Optional[Order]:
return self._orders.get(order_id)
def add_product(self, product: Product) -> None:
self._products[product.id] = product
def get_product(self, product_id: str) -> Optional[Product]:
return self._products.get(product_id)
def process_order(self, order_id: str) -> None:
order = self.get_order(order_id)
if order is None:
raise ValueError(f"订单不存在: {order_id}")
if order.status == OrderStatus.PENDING:
# 处理支付
order.update_status(OrderStatus.PAID)
# 处理发货
order.update_status(OrderStatus.SHIPPED)
# 订单观察者
class OrderObserver:
def __init__(self, name: str):
self.name = name
def update(self, message: str) -> None:
print(f"[{self.name}] 收到通知: {message}")
# 使用示例
def main():
# 创建订单管理系统
system = OrderManagementSystem()
# 添加一些产品
products = [
Product("P001", "iPhone 13", Decimal("5999.00"), 10),
Product("P002", "MacBook Pro", Decimal("12999.00"), 5),
Product("P003", "AirPods Pro", Decimal("1999.00"), 20)
]
for product in products:
system.add_product(product)
# 创建订单
order = system.create_order("CUST001")
# 添加订单观察者
order_tracker = OrderObserver("订单跟踪系统")
email_notifier = OrderObserver("邮件通知系统")
order.attach_observer(order_tracker)
order.attach_observer(email_notifier)
try:
# 添加商品到订单
order.add_item(system.get_product("P001"), 2)
order.add_item(system.get_product("P003"), 1)
# 处理订单
print(f"\n订单 {order.order_id} 创建成功:")
print(f"总金额: ¥{order.total_amount}")
print("订单项:")
for item in order.items:
print(f"- {item.product.name} x {item.quantity}")
# 处理订单状态变更
system.process_order(order.order_id)
# 输出订单JSON
print("\n订单JSON:")
print(order.to_json())
except ValueError as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()
建议的学习路径 📚
-
基础概念
- 理解类和对象的概念
- 掌握属性和方法的使用
- 学习继承和多态
-
进阶特性
- 深入理解类方法和静态方法
- 掌握属性装饰器
- 学习描述符和元类
-
设计模式
- 从简单的设计模式开始(如单例、工厂)
- 逐步学习更复杂的模式(如观察者、策略)
- 理解模式的适用场景
-
最佳实践
- 遵循 SOLID 设计原则
- 编写可测试的代码
- 使用类型注解
- 编写清晰的文档
-
实战项目
- 从小项目开始
- 逐步增加复杂度
- 注重代码质量和可维护性
如果你觉得这篇文章有帮助,欢迎点赞转发,也期待在评论区看到你的想法和建议!👇
咱们下一期见!