想象一下,如果编程是搭建乐高积木,那么面向对象编程(OOP)就是创造了一套可以自定义形状、功能和行为的积木系统。不再局限于使用现成的积木,你可以设计自己的积木类型!
类(Class) 是蓝图,对象(Object) 是实体。
想象你有一个"蛋糕模具"(类),你可以用它制作出无数个"蛋糕"(对象)。每个蛋糕都有相同的基本结构(属性),但可以有不同的口味、装饰(状态)。
# 定义一个蛋糕类
class Cake:
def __init__(self, flavor, layers):
self.flavor = flavor # 属性:口味
self.layers = layers # 属性:层数
self.is_baked = False # 属性:是否烤好
def bake(self, time): # 方法:烘焙
print(f"烘焙{self.flavor}蛋糕 {time} 分钟...")
self.is_baked = True
def add_topping(self, topping): # 方法:添加装饰
print(f"在{self.flavor}蛋糕上添加{topping}")
# 创建两个不同的蛋糕对象
chocolate_cake = Cake("巧克力", 3)
strawberry_cake = Cake("草莓", 2)
# 使用对象的方法
chocolate_cake.bake(30)
chocolate_cake.add_topping("巧克力碎片")
strawberry_cake.bake(25)
strawberry_cake.add_topping("新鲜草莓")
就像使用咖啡机,你只需要按按钮,不需要了解内部工作原理。封装让我们隐藏复杂的实现细节,只暴露必要的功能。
class BankAccount:
def __init__(self, owner, initial_balance=0):
self.owner = owner
self.__balance = initial_balance # 私有属性,外部不能直接访问
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return True
return False
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
return True
return False
def get_balance(self):
return self.__balance # 通过方法访问私有属性
# 使用银行账户
account = BankAccount("张三", 1000)
account.deposit(500)
print(account.get_balance()) # 1500
# 无法直接访问私有属性
# print(account.__balance) # 这会报错!
在Python中,单下划线(_
)表示"内部使用",双下划线(__
)表示"私有"。实际上,Python会将__balance
转换为_BankAccount__balance
,这种命名改写称为名称修饰(name mangling)。
继承允许一个类(子类)获得另一个类(父类)的所有属性和方法。这就像孩子继承了父母的特征,但可以发展自己的特性。
# 父类
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def make_sound(self):
print("某种动物声音")
def info(self):
print(f"我是{self.name},一只{self.species}")
# 子类
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类的初始化方法
super().__init__(name, "狗")
self.breed = breed
# 重写父类方法
def make_sound(self):
print("汪汪!")
# 添加新方法
def fetch(self):
print(f"{self.name}去捡球了!")
# 创建对象
animal = Animal("未知", "某种动物")
dog = Dog("旺财", "金毛")
animal.info() # 我是未知,一只某种动物
dog.info() # 我是旺财,一只狗
animal.make_sound() # 某种动物声音
dog.make_sound() # 汪汪!
dog.fetch() # 旺财去捡球了!
多态允许不同类的对象对同一消息做出不同的响应。这就像按下"播放"按钮,音乐播放器播放音乐,视频播放器播放视频。
# 继续使用前面的Animal类体系
def make_animal_sound(animal):
animal.make_sound() # 不关心具体是什么动物,只调用make_sound方法
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name, "猫")
self.color = color
def make_sound(self):
print("喵喵!")
# 创建不同动物
dog = Dog("旺财", "金毛")
cat = Cat("咪咪", "橘色")
# 同一个函数可以处理不同类型的对象
make_animal_sound(dog) # 汪汪!
make_animal_sound(cat) # 喵喵!
抽象让我们专注于对象的"是什么"和"能做什么",而不是"怎么做"。在Python中,我们可以通过abc
模块实现抽象类。
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
def perimeter(self):
return 2 * 3.14 * self.radius
class Rectangle(Shape):
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
# 不能创建抽象类的实例
# shape = Shape() # 这会报错!
# 创建具体形状
circle = Circle(5)
rectangle = Rectangle(4, 6)
print(f"圆的面积: {circle.area()}")
print(f"矩形的面积: {rectangle.area()}")
Python类有许多特殊方法,以双下划线开头和结尾,如__init__
、__str__
等。这些方法可以让我们自定义对象的行为。
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
self.current_page = 0
# 定义对象的字符串表示
def __str__(self):
return f"{self.title} by {self.author}"
# 定义对象的官方表示
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
# 定义对象的长度
def __len__(self):
return self.pages
# 定义对象的布尔值
def __bool__(self):
return self.pages > 0
# 使对象可以像函数一样被调用
def __call__(self, page):
if 0 <= page < self.pages:
self.current_page = page
return f"翻到了第{page}页"
return "无效页码"
# 创建书籍对象
book = Book("Python大冒险", "编程达人", 300)
print(str(book)) # Python大冒险 by 编程达人
print(repr(book)) # Book('Python大冒险', '编程达人', 300)
print(len(book)) # 300
print(bool(book)) # True
print(book(100)) # 翻到了第100页
使用属性装饰器,我们可以像访问属性一样调用方法,使代码更加简洁优雅。
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)
# 像访问属性一样使用getter
print(temp.celsius) # 25
print(temp.fahrenheit) # 77.0
# 像修改属性一样使用setter
temp.celsius = 30
print(temp.fahrenheit) # 86.0
temp.fahrenheit = 68
print(temp.celsius) # 20.0
# 设置无效温度会引发异常
# temp.celsius = -300 # ValueError: 温度不能低于绝对零度
除了常规的实例方法,Python类还可以有类方法和静态方法。
class Pizza:
total_pizzas = 0 # 类变量
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
Pizza.total_pizzas += 1
# 实例方法:需要访问实例属性
def get_description(self):
toppings_str = ", ".join(self.toppings)
return f"{self.size}寸披萨,配料:{toppings_str}"
# 类方法:需要访问类属性
@classmethod
def get_total(cls):
return f"总共制作了{cls.total_pizzas}个披萨"
# 类方法作为替代构造函数
@classmethod
def create_cheese_pizza(cls, size):
return cls(size, ["奶酪"])
# 静态方法:不需要访问实例或类属性
@staticmethod
def is_valid_size(size):
return size in [6, 9, 12, 18]
# 创建披萨
pizza1 = Pizza(12, ["奶酪", "蘑菇", "青椒"])
pizza2 = Pizza(9, ["奶酪", "香肠"])
# 调用实例方法
print(pizza1.get_description()) # 12寸披萨,配料:奶酪, 蘑菇, 青椒
# 调用类方法
print(Pizza.get_total()) # 总共制作了2个披萨
# 使用类方法作为替代构造函数
cheese_pizza = Pizza.create_cheese_pizza(18)
print(cheese_pizza.get_description()) # 18寸披萨,配料:奶酪
# 调用静态方法
print(Pizza.is_valid_size(12)) # True
print(Pizza.is_valid_size(7)) # False
继承表示"是一个"关系,组合表示"有一个"关系。通常,组合比继承更灵活。
# 组合示例
class Engine:
def __init__(self, power):
self.power = power
def start(self):
return f"引擎启动,功率{self.power}马力"
class Radio:
def __init__(self, brand):
self.brand = brand
def play_music(self):
return f"{self.brand}音响播放音乐"
# 汽车通过组合使用引擎和收音机
class Car:
def __init__(self, model, engine_power, radio_brand):
self.model = model
self.engine = Engine(engine_power) # 组合
self.radio = Radio(radio_brand) # 组合
def start_journey(self):
return f"{self.model}:{self.engine.start()},{self.radio.play_music()}"
# 创建汽车
my_car = Car("特斯拉Model 3", 300, "哈曼卡顿")
print(my_car.start_journey())
# 特斯拉Model 3:引擎启动,功率300马力,哈曼卡顿音响播放音乐
有时我们需要确保一个类只有一个实例,比如配置管理器、数据库连接池等。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
class ConfigManager(Singleton):
def __init__(self):
# 这里仅在第一次创建实例时初始化
if not hasattr(self, 'config'):
self.config = {
'debug': True,
'log_level': 'INFO',
'max_connections': 100
}
def get_config(self, key):
return self.config.get(key)
def set_config(self, key, value):
self.config[key] = value
# 创建两个实例
config1 = ConfigManager()
config2 = ConfigManager()
# 它们是同一个对象
print(config1 is config2) # True
# 通过一个实例修改配置
config1.set_config('debug', False)
# 另一个实例也会受到影响
print(config2.get_config('debug')) # False
Python允许一个类继承多个父类,但这可能导致方法解析顺序(MRO)的问题。
class A:
def who_am_i(self):
return "I am A"
class B(A):
def who_am_i(self):
return "I am B"
class C(A):
def who_am_i(self):
return "I am C"
# D同时继承B和C
class D(B, C):
pass
# 查看MRO
print(D.__mro__)
# (, , , , )
# 调用方法
d = D()
print(d.who_am_i()) # I am B (因为B在MRO中排在C前面)
面向对象编程中,设计模式是对常见问题的解决方案。以下是一些常见的设计模式:
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "汪汪!"
class Cat(Animal):
def speak(self):
return "喵喵!"
class AnimalFactory:
def create_animal(self, animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError(f"不支持的动物类型: {animal_type}")
# 使用工厂
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")
print(dog.speak()) # 汪汪!
print(cat.speak()) # 喵喵!
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)
class Observer:
def __init__(self, name):
self.name = name
def update(self, message):
print(f"{self.name} 收到消息: {message}")
# 创建主题和观察者
subject = Subject()
observer1 = Observer("观察者1")
observer2 = Observer("观察者2")
# 添加观察者
subject.attach(observer1)
subject.attach(observer2)
# 通知观察者
subject.notify("你好,世界!")
# 观察者1 收到消息: 你好,世界!
# 观察者2 收到消息: 你好,世界!
# 移除观察者
subject.detach(observer1)
subject.notify("再见!")
# 观察者2 收到消息: 再见!
让我们将所学知识应用到一个小型的代码版本管理系统:
from datetime import datetime
import uuid
class CodeFile:
def __init__(self, name, content=""):
self.name = name
self.content = content
self.created_at = datetime.now()
self.updated_at = self.created_at
def update_content(self, content):
self.content = content
self.updated_at = datetime.now()
def __str__(self):
return f"文件: {self.name}, 最后更新: {self.updated_at}"
class Commit:
def __init__(self, message, author):
self.id = str(uuid.uuid4())[:8] # 生成短UUID
self.message = message
self.author = author
self.timestamp = datetime.now()
self.files = {} # 文件快照
def add_file(self, file):
# 创建文件的快照 (深拷贝)
snapshot = CodeFile(file.name, file.content)
self.files[file.name] = snapshot
def __str__(self):
return f"提交 {self.id}: {self.message} by {self.author} at {self.timestamp}"
class Repository:
def __init__(self, name):
self.name = name
self.files = {} # 当前工作区文件
self.commits = [] # 提交历史
def create_file(self, name, content=""):
if name in self.files:
raise ValueError(f"文件 {name} 已存在")
self.files[name] = CodeFile(name, content)
return self.files[name]
def update_file(self, name, content):
if name not in self.files:
raise ValueError(f"文件 {name} 不存在")
self.files[name].update_content(content)
return self.files[name]
def commit(self, message, author):
commit = Commit(message, author)
for file in self.files.values():
commit.add_file(file)
self.commits.append(commit)
return commit
def get_file_history(self, file_name):
history = []
for commit in self.commits:
if file_name in commit.files:
history.append({
'commit': commit,
'content': commit.files[file_name].content
})
return history
def __str__(self):
return f"仓库: {self.name}, 文件数: {len(self.files)}, 提交数: {len(self.commits)}"
# 使用示例
repo = Repository("我的项目")
# 创建文件
hello_py = repo.create_file("hello.py", "print('Hello, World!')")
readme = repo.create_file("README.md", "# 我的项目\n这是一个示例项目。")
# 提交
repo.commit("初始提交", "张三")
# 更新文件
repo.update_file("hello.py", "print('Hello, Python!')\nprint('Welcome to OOP!')")
repo.commit("更新 hello.py", "张三")
# 查看仓库信息
print(repo) # 仓库: 我的项目, 文件数: 2, 提交数: 2
# 查看文件历史
history = repo.get_file_history("hello.py")
for entry in history:
print(f"{entry['commit'].id}: {entry['content']}")
面向对象编程是Python强大的编程范式之一,通过类和对象的概念,可以将复杂问题分解为易于管理的部分。关键点包括:
掌握这些概念后,你就可以设计出结构清晰、易于维护的代码,为更高级的Python应用打下坚实基础!
创建一个动物园系统
实现一个简单的银行系统
开发一个命令行游戏
创建一个自定义容器类
__getitem__
, __setitem__
, etc.记住,理解概念很重要,但真正掌握面向对象编程需要大量实践。从简单的项目开始,逐步挑战更复杂的问题!
# 动物园系统实现
class Animal:
"""动物基类"""
def __init__(self, name, age, health=100, hunger=0):
self.name = name
self.age = age
self.health = health
self.hunger = hunger
def make_sound(self):
"""动物发出声音"""
pass
def eat(self, food_amount):
"""动物进食"""
self.hunger = max(0, self.hunger - food_amount)
print(f"{self.name} has eaten. Hunger level: {self.hunger}")
def update_status(self):
"""更新动物状态"""
self.hunger += 10
if self.hunger > 100:
self.health -= 10
print(f"{self.name} is too hungry and losing health!")
def __str__(self):
return f"{self.__class__.__name__}: {self.name}, Age: {self.age}, Health: {self.health}, Hunger: {self.hunger}"
class Mammal(Animal):
"""哺乳动物类"""
def __init__(self, name, age, fur_color, health=100, hunger=0):
super().__init__(name, age, health, hunger)
self.fur_color = fur_color
def give_birth(self):
"""哺乳动物生育"""
print(f"{self.name} has given birth to a baby!")
class Bird(Animal):
"""鸟类"""
def __init__(self, name, age, wing_span, health=100, hunger=0):
super().__init__(name, age, health, hunger)
self.wing_span = wing_span
def fly(self):
"""鸟类飞行"""
print(f"{self.name} is flying with a wingspan of {self.wing_span}cm!")
class Lion(Mammal):
"""狮子类"""
def make_sound(self):
return "ROAR!"
def hunt(self):
"""狮子捕猎"""
self.hunger = max(0, self.hunger - 30)
print(f"{self.name} has hunted successfully. Hunger decreased to {self.hunger}")
class Parrot(Bird):
"""鹦鹉类"""
def __init__(self, name, age, wing_span, vocabulary=None, health=100, hunger=0):
super().__init__(name, age, wing_span, health, hunger)
self.vocabulary = vocabulary or []
def make_sound(self):
return "Squawk!"
def talk(self):
"""鹦鹉说话"""
if not self.vocabulary:
return f"{self.name} doesn't know any words yet."
return f"{self.name} says: {self.vocabulary[0]}"
def learn_word(self, word):
"""鹦鹉学习新词"""
self.vocabulary.append(word)
print(f"{self.name} learned a new word: {word}")
class Zoo:
"""动物园类"""
def __init__(self, name):
self.name = name
self.animals = {}
self.animal_count = 0
def add_animal(self, animal):
"""添加动物到动物园"""
self.animal_count += 1
animal_id = self.animal_count
self.animals[animal_id] = animal
print(f"{animal.name} has been added to {self.name} Zoo with ID: {animal_id}")
return animal_id
def remove_animal(self, animal_id):
"""从动物园移除动物"""
if animal_id in self.animals:
animal = self.animals.pop(animal_id)
print(f"{animal.name} has been removed from {self.name} Zoo")
return True
return False
def feed_animal(self, animal_id, food_amount):
"""喂养动物"""
if animal_id in self.animals:
self.animals[animal_id].eat(food_amount)
return True
return False
def update_all_animals(self):
"""更新所有动物状态"""
print(f"Updating all animals in {self.name} Zoo...")
for animal in self.animals.values():
animal.update_status()
def get_animal_sounds(self):
"""获取所有动物的声音"""
sounds = {}
for animal_id, animal in self.animals.items():
sounds[animal_id] = animal.make_sound()
return sounds
def __str__(self):
result = f"{self.name} Zoo with {len(self.animals)} animals:\n"
for animal_id, animal in self.animals.items():
result += f"ID {animal_id}: {animal}\n"
return result
# 测试代码
if __name__ == "__main__":
# 创建动物园
central_zoo = Zoo("Central")
# 创建动物
simba = Lion("Simba", 5, "Golden", health=95, hunger=20)
nala = Lion("Nala", 4, "Tan")
polly = Parrot("Polly", 2, 30, ["Hello", "Goodbye"])
# 添加动物到动物园
simba_id = central_zoo.add_animal(simba)
nala_id = central_zoo.add_animal(nala)
polly_id = central_zoo.add_animal(polly)
# 测试动物行为
print(simba.make_sound()) # ROAR!
simba.hunt() # 狮子捕猎
polly.learn_word("I'm hungry!") # 鹦鹉学习新词
print(polly.talk()) # 鹦鹉说话
# 喂养动物
central_zoo.feed_animal(nala_id, 30)
# 更新所有动物状态
central_zoo.update_all_animals()
# 打印动物园信息
print(central_zoo)
# 获取所有动物的声音
sounds = central_zoo.get_animal_sounds()
for animal_id, sound in sounds.items():
animal = central_zoo.animals[animal_id]
print(f"Animal ID {animal_id} ({animal.name}) says: {sound}")
# 银行系统实现
import datetime
from abc import ABC, abstractmethod
import uuid
class Transaction:
"""交易类"""
def __init__(self, amount, description, transaction_type):
self.transaction_id = str(uuid.uuid4())[:8] # 生成唯一交易ID
self.amount = amount
self.description = description
self.timestamp = datetime.datetime.now()
self.transaction_type = transaction_type # "deposit", "withdrawal", "transfer"
def __str__(self):
return f"[{self.timestamp.strftime('%Y-%m-%d %H:%M:%S')}] {self.transaction_type.upper()}: {self.amount:.2f} - {self.description} (ID: {self.transaction_id})"
class Account(ABC):
"""账户抽象基类"""
def __init__(self, account_number, owner_name, balance=0):
self.account_number = account_number
self.owner_name = owner_name
self._balance = balance
self.transactions = []
@property
def balance(self):
"""获取账户余额"""
return self._balance
def deposit(self, amount, description="Deposit"):
"""存款"""
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self._balance += amount
transaction = Transaction(amount, description, "deposit")
self.transactions.append(transaction)
return transaction
def withdraw(self, amount, description="Withdrawal"):
"""取款"""
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
transaction = Transaction(amount, description, "withdrawal")
self.transactions.append(transaction)
return transaction
def get_transaction_history(self):
"""获取交易历史"""
return self.transactions
@abstractmethod
def get_account_type(self):
"""获取账户类型"""
pass
def __str__(self):
return f"{self.get_account_type()} - {self.account_number} ({self.owner_name}): ${self.balance:.2f}"
class SavingsAccount(Account):
"""储蓄账户类"""
def __init__(self, account_number, owner_name, balance=0, interest_rate=0.01):
super().__init__(account_number, owner_name, balance)
self.interest_rate = interest_rate
def apply_interest(self):
"""应用利息"""
interest = self._balance * self.interest_rate
self.deposit(interest, "Interest applied")
return interest
def get_account_type(self):
return "Savings Account"
class CheckingAccount(Account):
"""支票账户类"""
def __init__(self, account_number, owner_name, balance=0, overdraft_limit=100):
super().__init__(account_number, owner_name, balance)
self.overdraft_limit = overdraft_limit
def withdraw(self, amount, description="Withdrawal"):
"""支票账户取款,支持透支"""
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > (self._balance + self.overdraft_limit):
raise ValueError(f"Withdrawal exceeds overdraft limit. Maximum withdrawal: ${self._balance + self.overdraft_limit:.2f}")
self._balance -= amount
transaction = Transaction(amount, description, "withdrawal")
self.transactions.append(transaction)
if self._balance < 0:
print(f"Warning: Account {self.account_number} is overdrawn by ${abs(self._balance):.2f}")
return transaction
def get_account_type(self):
return "Checking Account"
class Bank:
"""银行类"""
def __init__(self, name):
self.name = name
self.accounts = {}
self.next_account_number = 10000 # 起始账号
def create_account(self, owner_name, account_type, initial_deposit=0, **kwargs):
"""创建新账户"""
account_number = str(self.next_account_number)
self.next_account_number += 1
if account_type.lower() == "savings":
interest_rate = kwargs.get("interest_rate", 0.01)
account = SavingsAccount(account_number, owner_name, initial_deposit, interest_rate)
elif account_type.lower() == "checking":
overdraft_limit = kwargs.get("overdraft_limit", 100)
account = CheckingAccount(account_number, owner_name, initial_deposit, overdraft_limit)
else:
raise ValueError("Invalid account type")
self.accounts[account_number] = account
if initial_deposit > 0:
account.deposit(initial_deposit, "Initial deposit")
print(f"Account created: {account}")
return account
def get_account(self, account_number):
"""获取账户"""
if account_number not in self.accounts:
raise ValueError("Account not found")
return self.accounts[account_number]
def transfer(self, from_account_number, to_account_number, amount, description="Transfer"):
"""账户间转账"""
if amount <= 0:
raise ValueError("Transfer amount must be positive")
from_account = self.get_account(from_account_number)
to_account = self.get_account(to_account_number)
# 从源账户取款
from_transaction = from_account.withdraw(amount, f"Transfer to account {to_account_number}: {description}")
# 存入目标账户
to_transaction = to_account.deposit(amount, f"Transfer from account {from_account_number}: {description}")
return (from_transaction, to_transaction)
def apply_interest_to_all_savings(self):
"""为所有储蓄账户应用利息"""
applied_count = 0
total_interest = 0
for account in self.accounts.values():
if isinstance(account, SavingsAccount):
interest = account.apply_interest()
total_interest += interest
applied_count += 1
print(f"Applied interest to {applied_count} accounts. Total interest: ${total_interest:.2f}")
return total_interest
def get_total_deposits(self):
"""获取所有账户的总存款额"""
return sum(account.balance for account in self.accounts.values())
def __str__(self):
return f"{self.name} Bank - {len(self.accounts)} accounts, Total deposits: ${self.get_total_deposits():.2f}"
# 测试代码
if __name__ == "__main__":
# 创建银行
chase_bank = Bank("Chase")
# 创建账户
john_savings = chase_bank.create_account("John Smith", "savings", 1000, interest_rate=0.02)
john_checking = chase_bank.create_account("John Smith", "checking", 500, overdraft_limit=200)
alice_savings = chase_bank.create_account("Alice Johnson", "savings", 2500)
# 测试存款和取款
john_savings.deposit(500, "Salary deposit")
john_checking.withdraw(200, "ATM withdrawal")
try:
john_checking.withdraw(1000, "Large purchase")
except ValueError as e:
print(f"Error: {e}")
# 测试转账
chase_bank.transfer(john_savings.account_number, alice_savings.account_number, 300, "Debt repayment")
# 应用利息
chase_bank.apply_interest_to_all_savings()
# 打印账户信息
print("\nAccount Information:")
for account in chase_bank.accounts.values():
print(account)
# 打印交易历史
print("\nTransaction History for John's Savings Account:")
for transaction in john_savings.get_transaction_history():
print(transaction)
# 打印银行信息
print("\nBank Information:")
print(chase_bank)
# 命令行冒险游戏实现
import random
import time
import sys
from enum import Enum, auto
class GameState(Enum):
"""游戏状态枚举"""
MAIN_MENU = auto()
PLAYING = auto()
BATTLE = auto()
SHOP = auto()
INVENTORY = auto()
GAME_OVER = auto()
VICTORY = auto()
QUIT = auto()
class Item:
"""物品基类"""
def __init__(self, name, description, value):
self.name = name
self.description = description
self.value = value
def __str__(self):
return f"{self.name} - {self.description} (Value: {self.value} gold)"
class Weapon(Item):
"""武器类"""
def __init__(self, name, description, value, damage):
super().__init__(name, description, value)
self.damage = damage
def __str__(self):
return f"{self.name} - {self.description} (Damage: {self.damage}, Value: {self.value} gold)"
class Potion(Item):
"""药水类"""
def __init__(self, name, description, value, heal_amount):
super().__init__(name, description, value)
self.heal_amount = heal_amount
def __str__(self):
return f"{self.name} - {self.description} (Heals: {self.heal_amount} HP, Value: {self.value} gold)"
class Armor(Item):
"""护甲类"""
def __init__(self, name, description, value, defense):
super().__init__(name, description, value)
self.defense = defense
def __str__(self):
return f"{self.name} - {self.description} (Defense: {self.defense}, Value: {self.value} gold)"
class Character:
"""角色基类"""
def __init__(self, name, hp, attack_power):
self.name = name
self.max_hp = hp
self.hp = hp
self.base_attack = attack_power
def is_alive(self):
"""检查角色是否存活"""
return self.hp > 0
def take_damage(self, damage):
"""受到伤害"""
self.hp = max(0, self.hp - damage)
return damage
def heal(self, amount):
"""恢复生命值"""
self.hp = min(self.max_hp, self.hp + amount)
return amount
def attack(self, target):
"""攻击目标"""
damage = self.base_attack
return target.take_damage(damage)
class Player(Character):
"""玩家类"""
def __init__(self, name, hp=100, attack_power=10):
super().__init__(name, hp, attack_power)
self.inventory = []
self.gold = 50
self.weapon = None
self.armor = None
self.level = 1
self.exp = 0
self.exp_to_level = 100
def attack(self, target):
"""玩家攻击,考虑武器伤害"""
damage = self.base_attack
if self.weapon:
damage += self.weapon.damage
return target.take_damage(damage)
def take_damage(self, damage):
"""玩家受到伤害,考虑护甲防御"""
if self.armor:
damage = max(1, damage - self.armor.defense) # 至少造成1点伤害
return super().take_damage(damage)
def add_item(self, item):
"""添加物品到库存"""
self.inventory.append(item)
print(f"Added {item.name} to your inventory.")
def remove_item(self, item):
"""从库存移除物品"""
if item in self.inventory:
self.inventory.remove(item)
return True
return False
def equip_weapon(self, weapon_index):
"""装备武器"""
if 0 <= weapon_index < len(self.inventory):
item = self.inventory[weapon_index]
if isinstance(item, Weapon):
old_weapon = self.weapon
self.weapon = item
if old_weapon:
print(f"Unequipped {old_weapon.name} and equipped {item.name}.")
else:
print(f"Equipped {item.name}.")
return True
return False
def equip_armor(self, armor_index):
"""装备护甲"""
if 0 <= armor_index < len(self.inventory):
item = self.inventory[armor_index]
if isinstance(item, Armor):
old_armor = self.armor
self.armor = item
if old_armor:
print(f"Unequipped {old_armor.name} and equipped {item.name}.")
else:
print(f"Equipped {item.name}.")
return True
return False
def use_potion(self, potion_index):
"""使用药水"""
if 0 <= potion_index < len(self.inventory):
item = self.inventory[potion_index]
if isinstance(item, Potion):
healed = self.heal(item.heal_amount)
print(f"Used {item.name} and healed for {healed} HP.")
self.remove_item(item)
return True
return False
def add_exp(self, amount):
"""增加经验值"""
self.exp += amount
print(f"Gained {amount} experience points!")
# 检查是否升级
while self.exp >= self.exp_to_level:
self.level_up()
def level_up(self):
"""升级"""
self.exp -= self.exp_to_level
self.level += 1
self.max_hp += 20
self.hp = self.max_hp
self.base_attack += 5
self.exp_to_level = int(self.exp_to_level * 1.5)
print(f"\n*** LEVEL UP! ***\nYou are now level {self.level}!")
print(f"Max HP increased to {self.max_hp}")
print(f"Attack increased to {self.base_attack}")
def __str__(self):
equipped = []
if self.weapon:
equipped.append(f"Weapon: {self.weapon.name} (+{self.weapon.damage} damage)")
if self.armor:
equipped.append(f"Armor: {self.armor.name} (+{self.armor.defense} defense)")
return (
f"{self.name} (Level {self.level})\n"
f"HP: {self.hp}/{self.max_hp} | Gold: {self.gold} | EXP: {self.exp}/{self.exp_to_level}\n"
f"Attack: {self.base_attack}{' + ' + str(self.weapon.damage) if self.weapon else ''}\n"
f"Defense: {self.armor.defense if self.armor else 0}\n"
f"Equipped: {', '.join(equipped) if equipped else 'Nothing'}"
)
class Enemy(Character):
"""敌人类"""
def __init__(self, name, hp, attack_power, gold_reward, exp_reward):
super().__init__(name, hp, attack_power)
self.gold_reward = gold_reward
self.exp_reward = exp_reward
def __str__(self):
return f"{self.name} (HP: {self.hp}/{self.max_hp}, Attack: {self.base_attack})"
class Shop:
"""商店类"""
def __init__(self):
self.inventory = []
self.initialize_inventory()
def initialize_inventory(self):
"""初始化商店库存"""
# 武器
self.inventory.append(Weapon("Dagger", "A small but sharp dagger", 25, 5))
self.inventory.append(Weapon("Sword", "A standard iron sword", 60, 10))
self.inventory.append(Weapon("Battle Axe", "A heavy battle axe", 120, 20))
# 护甲
self.inventory.append(Armor("Leather Armor", "Basic protection made of leather", 40, 5))
self.inventory.append(Armor("Chain Mail", "Medium armor made of interlocking rings", 100, 10))
self.inventory.append(Armor("Plate Armor", "Heavy armor offering excellent protection", 200, 20))
# 药水
self.inventory.append(Potion("Minor Healing Potion", "Restores a small amount of health", 15, 20))
self.inventory.append(Potion("Healing Potion", "Restores a moderate amount of health", 30, 50))
self.inventory.append(Potion("Major Healing Potion", "Restores a large amount of health", 60, 100))
def buy_item(self, player, item_index):
"""玩家购买物品"""
if 0 <= item_index < len(self.inventory):
item = self.inventory[item_index]
if player.gold >= item.value:
player.gold -= item.value
player.add_item(item)
print(f"You bought {item.name} for {item.value} gold.")
return True
else:
print("You don't have enough gold!")
return False
def sell_item(self, player, item_index):
"""玩家出售物品"""
if 0 <= item_index < len(player.inventory):
item = player.inventory[item_index]
sell_value = item.value // 2 # 卖出价为原价的一半
# 确保未装备的物品才能出售
if item == player.weapon or item == player.armor:
print("You cannot sell equipped items!")
return False
player.gold += sell_value
player.remove_item(item)
print(f"You sold {item.name} for {sell_value} gold.")
return True
return False
class Game:
"""游戏主类"""
def __init__(self):
self.state = GameState.MAIN_MENU
self.player = None
self.current_enemy = None
self.shop = Shop()
self.enemy_types = [
{"name": "Goblin", "hp": 30, "attack": 5, "gold": 10, "exp": 20},
{"name": "Orc", "hp": 50, "attack": 8, "gold": 15, "exp": 30},
{"name": "Troll", "hp": 80, "attack": 12, "gold": 25, "exp": 50},
{"name": "Dragon", "hp": 200, "attack": 20, "gold": 100, "exp": 200}
]
def clear_screen(self):
"""清屏"""
print("\n" * 50)
def slow_print(self, text, delay=0.03):
"""缓慢打印文本,增强游戏体验"""
for char in text:
print(char, end='', flush=True)
time.sleep(delay)
print()
def print_header(self, title):
"""打印标题栏"""
print("\n" + "=" * 60)
print(f"{title:^60}")
print("=" * 60 + "\n")
def wait_for_input(self):
"""等待用户按任意键继续"""
input("\nPress Enter to continue...")
def show_main_menu(self):
"""显示主菜单"""
self.clear_screen()
self.print_header("DUNGEON ADVENTURE")
self.slow_print("Welcome to Dungeon Adventure!", 0.05)
print("\n1. New Game")
print("2. Quit\n")
choice = input("Enter your choice (1-2): ")
if choice == "1":
self.start_new_game()
elif choice == "2":
self.state = GameState.QUIT
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
def start_new_game(self):
"""开始新游戏"""
self.clear_screen()
self.print_header("CHARACTER CREATION")
name = input("Enter your hero's name: ")
if not name:
name = "Hero"
self.player = Player(name)
# 给予玩家初始装备
starter_weapon = Weapon("Rusty Sword", "An old sword with some rust spots", 0, 3)
self.player.add_item(starter_weapon)
self.player.equip_weapon(0)
starter_potion = Potion("Small Health Potion", "A tiny vial of red liquid", 0, 15)
self.player.add_item(starter_potion)
self.slow_print(f"\nWelcome, {self.player.name}! Your adventure begins...", 0.05)
self.slow_print("You find yourself at the entrance of a dark dungeon.", 0.05)
self.slow_print("Legends say it's filled with monsters and treasures.", 0.05)
self.slow_print("Are you brave enough to explore it?", 0.05)
self.wait_for_input()
self.state = GameState.PLAYING
def show_game_menu(self):
"""显示游戏主菜单"""
self.clear_screen()
self.print_header("DUNGEON ADVENTURE")
print(self.player)
print("\nWhat would you like to do?")
print("1. Explore the dungeon")
print("2. Visit the shop")
print("3. Check inventory")
print("4. Rest (Heal 20% HP)")
print("5. Quit to main menu\n")
choice = input("Enter your choice (1-5): ")
if choice == "1":
self.explore()
elif choice == "2":
self.state = GameState.SHOP
elif choice == "3":
self.state = GameState.INVENTORY
elif choice == "4":
self.rest()
elif choice == "5":
self.state = GameState.MAIN_MENU
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
def explore(self):
"""探索地牢"""
self.clear_screen()
self.print_header("EXPLORING THE DUNGEON")
self.slow_print("You venture deeper into the dungeon...", 0.05)
time.sleep(1)
# 随机事件: 战斗、发现物品、或者什么都没发生
event = random.randint(1, 10)
if event <= 7: # 70% 概率遇到敌人
self.encounter_enemy()
elif event <= 9: # 20% 概率发现物品
self.find_item()
else: # 10% 概率什么都没发生
self.slow_print("You explore for a while but find nothing of interest.")
self.wait_for_input()
def encounter_enemy(self):
"""遇到敌人"""
# 根据玩家等级选择合适的敌人
enemy_level = min(len(self.enemy_types) - 1, self.player.level - 1)
enemy_type = self.enemy_types[random.randint(0, enemy_level)]
# 根据玩家等级调整敌人属性
hp_modifier = 1.0 + (self.player.level - 1) * 0.2
attack_modifier = 1.0 + (self.player.level - 1) * 0.1
reward_modifier = 1.0 + (self.player.level - 1) * 0.3
self.current_enemy = Enemy(
enemy_type["name"],
int(enemy_type["hp"] * hp_modifier),
int(enemy_type["attack"] * attack_modifier),
int(enemy_type["gold"] * reward_modifier),
int(enemy_type["exp"] * reward_modifier)
)
self.slow_print(f"You encountered a {self.current_enemy.name}!")
self.state = GameState.BATTLE
def find_item(self):
"""发现物品"""
item_type = random.randint(1, 3)
if item_type == 1: # 发现金币
gold_amount = random.randint(5, 15) * self.player.level
self.player.gold += gold_amount
self.slow_print(f"You found a small pouch containing {gold_amount} gold coins!")
elif item_type == 2: # 发现药水
potion_power = random.randint(1, 3)
if potion_power == 1:
potion = Potion("Minor Healing Potion", "Restores a small amount of health", 15, 20)
elif potion_power == 2:
potion = Potion("Healing Potion", "Restores a moderate amount of health", 30, 50)
else:
potion = Potion("Major Healing Potion", "Restores a large amount of health", 60, 100)
self.player.add_item(potion)
self.slow_print(f"You found a {potion.name}!")
else: # 发现装备
equipment_type = random.randint(1, 2)
equipment_quality = random.randint(1, 3) * self.player.level
if equipment_type == 1: # 武器
weapon_types = ["Dagger", "Sword", "Axe", "Mace", "Spear"]
weapon_name = f"{random.choice(['Rusty', 'Iron', 'Steel', 'Silver', 'Enchanted'])} {random.choice(weapon_types)}"
weapon = Weapon(weapon_name, f"A {weapon_name.lower()} found in the dungeon", equipment_quality * 10, equipment_quality * 2)
self.player.add_item(weapon)
self.slow_print(f"You found a {weapon.name}!")
else: # 护甲
armor_types = ["Armor", "Shield", "Helmet", "Gauntlets", "Boots"]
armor_name = f"{random.choice(['Leather', 'Chain', 'Plate', 'Reinforced', 'Magical'])} {random.choice(armor_types)}"
armor = Armor(armor_name, f"A {armor_name.lower()} found in the dungeon", equipment_quality * 15, equipment_quality)
self.player.add_item(armor)
self.slow_print(f"You found a {armor.name}!")
self.wait_for_input()
def battle(self):
"""战斗系统"""
self.clear_screen()
self.print_header("BATTLE")
print(f"{self.player.name}: {self.player.hp}/{self.player.max_hp} HP")
print(f"{self.current_enemy.name}: {self.current_enemy.hp}/{self.current_enemy.max_hp} HP\n")
print("What will you do?")
print("1. Attack")
print("2. Use Potion")
print("3. Run Away\n")
choice = input("Enter your choice (1-3): ")
if choice == "1": # 攻击
self.player_attack()
elif choice == "2": # 使用药水
self.use_potion_in_battle()
elif choice == "3": # 逃跑
if random.random() < 0.7: # 70% 成功率
self.slow_print("You successfully escaped!")
self.state = GameState.PLAYING
self.wait_for_input()
else:
self.slow_print("You failed to escape!")
self.enemy_attack()
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
def player_attack(self):
"""玩家攻击"""
damage = self.player.attack(self.current_enemy)
self.slow_print(f"You attacked the {self.current_enemy.name} and dealt {damage} damage!")
if not self.current_enemy.is_alive():
self.battle_victory()
else:
self.enemy_attack()
def enemy_attack(self):
"""敌人攻击"""
damage = self.current_enemy.attack(self.player)
self.slow_print(f"The {self.current_enemy.name} attacked you and dealt {damage} damage!")
if not self.player.is_alive():
self.game_over()
else:
self.wait_for_input()
def use_potion_in_battle(self):
"""在战斗中使用药水"""
potions = [(i, item) for i, item in enumerate(self.player.inventory) if isinstance(item, Potion)]
if not potions:
self.slow_print("You don't have any potions!")
self.enemy_attack()
return
print("\nAvailable Potions:")
for i, (idx, potion) in enumerate(potions):
print(f"{i+1}. {potion.name} (+{potion.heal_amount} HP)")
print(f"{len(potions)+1}. Cancel")
try:
choice = int(input(f"\nSelect a potion (1-{len(potions)+1}): "))
if 1 <= choice <= len(potions):
idx = potions[choice-1][0]
if self.player.use_potion(idx):
# 使用药水后敌人仍然会攻击
self.enemy_attack()
elif choice == len(potions)+1:
# 取消使用药水
self.battle()
else:
print("Invalid choice.")
self.use_potion_in_battle()
except ValueError:
print("Please enter a valid number.")
self.use_potion_in_battle()
def battle_victory(self):
"""战斗胜利"""
self.clear_screen()
self.print_header("VICTORY")
self.slow_print(f"You defeated the {self.current_enemy.name}!")
# 奖励
gold_reward = self.current_enemy.gold_reward
exp_reward = self.current_enemy.exp_reward
self.player.gold += gold_reward
self.slow_print(f"You gained {gold_reward} gold!")
self.player.add_exp(exp_reward)
# 小概率额外奖励
if random.random() < 0.3: # 30% 概率获得物品
self.find_item()
self.current_enemy = None
self.state = GameState.PLAYING
self.wait_for_input()
def game_over(self):
"""游戏结束"""
self.clear_screen()
self.print_header("GAME OVER")
self.slow_print("You have been defeated...", 0.1)
self.slow_print(f"\nFinal Stats:")
self.slow_print(f"Level: {self.player.level}")
self.slow_print(f"Gold collected: {self.player.gold}")
self.wait_for_input()
self.state = GameState.MAIN_MENU
def rest(self):
"""休息恢复生命值"""
if self.player.hp == self.player.max_hp:
self.slow_print("You are already at full health!")
else:
heal_amount = int(self.player.max_hp * 0.2) # 恢复20%最大生命值
actual_heal = self.player.heal(heal_amount)
self.slow_print(f"You rest for a while and recover {actual_heal} HP.")
self.wait_for_input()
def show_shop(self):
"""显示商店界面"""
self.clear_screen()
self.print_header("SHOP")
print(f"Your gold: {self.player.gold}\n")
print("Available Items:")
for i, item in enumerate(self.shop.inventory):
print(f"{i+1}. {item} - {item.value} gold")
print(f"\n{len(self.shop.inventory)+1}. Sell items")
print(f"{len(self.shop.inventory)+2}. Back to main menu")
try:
choice = int(input(f"\nEnter your choice (1-{len(self.shop.inventory)+2}): "))
if 1 <= choice <= len(self.shop.inventory):
self.shop.buy_item(self.player, choice-1)
self.wait_for_input()
elif choice == len(self.shop.inventory)+1:
self.sell_items()
elif choice == len(self.shop.inventory)+2:
self.state = GameState.PLAYING
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
except ValueError:
print("Please enter a valid number.")
self.wait_for_input()
def sell_items(self):
"""出售物品界面"""
self.clear_screen()
self.print_header("SELL ITEMS")
if not self.player.inventory:
self.slow_print("You don't have any items to sell!")
self.wait_for_input()
return
print(f"Your gold: {self.player.gold}\n")
print("Your Items:")
for i, item in enumerate(self.player.inventory):
equipped = ""
if item == self.player.weapon:
equipped = " [Equipped Weapon]"
elif item == self.player.armor:
equipped = " [Equipped Armor]"
sell_value = item.value // 2
print(f"{i+1}. {item} - Sell for {sell_value} gold{equipped}")
print(f"\n{len(self.player.inventory)+1}. Back to shop")
try:
choice = int(input(f"\nEnter your choice (1-{len(self.player.inventory)+1}): "))
if 1 <= choice <= len(self.player.inventory):
self.shop.sell_item(self.player, choice-1)
self.wait_for_input()
self.sell_items() # 返回出售界面
elif choice == len(self.player.inventory)+1:
return # 返回商店
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
self.sell_items()
except ValueError:
print("Please enter a valid number.")
self.wait_for_input()
self.sell_items()
def show_inventory(self):
"""显示库存界面"""
self.clear_screen()
self.print_header("INVENTORY")
if not self.player.inventory:
self.slow_print("Your inventory is empty!")
self.wait_for_input()
self.state = GameState.PLAYING
return
print(f"Gold: {self.player.gold}\n")
print("Items:")
weapons = []
armors = []
potions = []
for i, item in enumerate(self.player.inventory):
equipped = ""
if item == self.player.weapon:
equipped = " [Equipped]"
weapons.append((i, item, equipped))
elif item == self.player.armor:
equipped = " [Equipped]"
armors.append((i, item, equipped))
elif isinstance(item, Weapon):
weapons.append((i, item, equipped))
elif isinstance(item, Armor):
armors.append((i, item, equipped))
elif isinstance(item, Potion):
potions.append((i, item, equipped))
if weapons:
print("\nWeapons:")
for i, item, equipped in weapons:
print(f"{i+1}. {item}{equipped}")
if armors:
print("\nArmors:")
for i, item, equipped in armors:
print(f"{i+1}. {item}{equipped}")
if potions:
print("\nPotions:")
for i, item, equipped in potions:
print(f"{i+1}. {item}")
print(f"\nActions:")
print(f"e. Equip item")
print(f"u. Use item")
print(f"b. Back to main menu")
choice = input("\nEnter your choice: ").lower()
if choice == 'e':
self.equip_item()
elif choice == 'u':
self.use_item()
elif choice == 'b':
self.state = GameState.PLAYING
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
def equip_item(self):
"""装备物品界面"""
self.clear_screen()
self.print_header("EQUIP ITEM")
equipment = [(i, item) for i, item in enumerate(self.player.inventory)
if isinstance(item, Weapon) or isinstance(item, Armor)]
if not equipment:
self.slow_print("You don't have any equipment to equip!")
self.wait_for_input()
return
print("Available Equipment:")
for i, (idx, item) in enumerate(equipment):
equipped = ""
if item == self.player.weapon or item == self.player.armor:
equipped = " [Equipped]"
print(f"{i+1}. {item}{equipped}")
print(f"\n{len(equipment)+1}. Cancel")
try:
choice = int(input(f"\nSelect equipment to equip (1-{len(equipment)+1}): "))
if 1 <= choice <= len(equipment):
idx = equipment[choice-1][0]
item = self.player.inventory[idx]
if isinstance(item, Weapon):
self.player.equip_weapon(idx)
elif isinstance(item, Armor):
self.player.equip_armor(idx)
self.wait_for_input()
elif choice == len(equipment)+1:
return
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
self.equip_item()
except ValueError:
print("Please enter a valid number.")
self.wait_for_input()
self.equip_item()
def use_item(self):
"""使用物品界面"""
self.clear_screen()
self.print_header("USE ITEM")
usable_items = [(i, item) for i, item in enumerate(self.player.inventory)
if isinstance(item, Potion)]
if not usable_items:
self.slow_print("You don't have any usable items!")
self.wait_for_input()
return
print("Usable Items:")
for i, (idx, item) in enumerate(usable_items):
print(f"{i+1}. {item}")
print(f"\n{len(usable_items)+1}. Cancel")
try:
choice = int(input(f"\nSelect item to use (1-{len(usable_items)+1}): "))
if 1 <= choice <= len(usable_items):
idx = usable_items[choice-1][0]
self.player.use_potion(idx)
self.wait_for_input()
elif choice == len(usable_items)+1:
return
else:
print("Invalid choice. Please try again.")
self.wait_for_input()
self.use_item()
except ValueError:
print("Please enter a valid number.")
self.wait_for_input()
self.use_item()
def run(self):
"""运行游戏主循环"""
while self.state != GameState.QUIT:
if self.state == GameState.MAIN_MENU:
self.show_main_menu()
elif self.state == GameState.PLAYING:
self.show_game_menu()
elif self.state == GameState.BATTLE:
self.battle()
elif self.state == GameState.SHOP:
self.show_shop()
elif self.state == GameState.INVENTORY:
self.show_inventory()
elif self.state == GameState.GAME_OVER:
self.game_over()
self.clear_screen()
self.slow_print("Thank you for playing Dungeon Adventure!", 0.05)
self.slow_print("Goodbye!", 0.05)
# 运行游戏
if __name__ == "__main__":
game = Game()
game.run()
# 自定义容器类实现
class MultiContainer:
"""
一个多功能容器类,结合了列表和字典的特性
可以通过索引或键来访问元素
"""
def __init__(self, items=None):
# 内部存储结构
self._list_data = [] # 按顺序存储元素
self._dict_data = {} # 通过键存储元素
self._key_index_map = {} # 映射键到索引
# 初始化数据
if items:
if isinstance(items, dict):
for key, value in items.items():
self.add(value, key)
elif isinstance(items, (list, tuple)):
for item in items:
self.add(item)
def add(self, item, key=None):
"""
添加元素到容器
如果提供了key,则可以通过key访问
否则只能通过索引访问
"""
index = len(self._list_data)
self._list_data.append(item)
if key is not None:
if key in self._dict_data:
# 如果键已存在,更新对应的值和索引
old_index = self._key_index_map[key]
self._dict_data[key] = item
self._key_index_map[key] = index
# 注意:这会导致旧索引位置的值被覆盖,但在列表中仍然保留
else:
# 添加新键值对
self._dict_data[key] = item
self._key_index_map[key] = index
return index
def remove(self, key_or_index):
"""
从容器中移除元素
可以通过键或索引移除
"""
if isinstance(key_or_index, int):
# 通过索引移除
if 0 <= key_or_index < len(self._list_data):
# 找到对应的键(如果存在)并从字典中移除
keys_to_remove = []
for key, idx in self._key_index_map.items():
if idx == key_or_index:
keys_to_remove.append(key)
elif idx > key_or_index:
# 更新大于被删除索引的索引映射
self._key_index_map[key] = idx - 1
for key in keys_to_remove:
del self._dict_data[key]
del self._key_index_map[key]
# 从列表中移除
self._list_data.pop(key_or_index)
return True
return False
else:
# 通过键移除
if key_or_index in self._dict_data:
index = self._key_index_map[key_or_index]
del self._dict_data[key_or_index]
del self._key_index_map[key_or_index]
# 从列表中移除
self._list_data.pop(index)
# 更新所有大于index的索引映射
for key, idx in self._key_index_map.items():
if idx > index:
self._key_index_map[key] = idx - 1
return True
return False
def __getitem__(self, key_or_index):
"""
实现 container[key] 或 container[index] 语法
"""
if isinstance(key_or_index, int):
# 通过索引访问
if 0 <= key_or_index < len(self._list_data):
return self._list_data[key_or_index]
raise IndexError("Index out of range")
else:
# 通过键访问
if key_or_index in self._dict_data:
return self._dict_data[key_or_index]
raise KeyError(f"Key '{key_or_index}' not found")
def __setitem__(self, key_or_index, value):
"""
实现 container[key] = value 或 container[index] = value 语法
"""
if isinstance(key_or_index, int):
# 通过索引设置
if 0 <= key_or_index < len(self._list_data):
# 更新列表中的值
self._list_data[key_or_index] = value
# 更新字典中对应索引的值(如果有)
for key, idx in self._key_index_map.items():
if idx == key_or_index:
self._dict_data[key] = value
return
raise IndexError("Index out of range")
else:
# 通过键设置
if key_or_index in self._dict_data:
# 更新现有键的值
index = self._key_index_map[key_or_index]
self._dict_data[key_or_index] = value
self._list_data[index] = value
else:
# 添加新键值对
self.add(value, key_or_index)
def __delitem__(self, key_or_index):
"""
实现 del container[key] 或 del container[index] 语法
"""
if not self.remove(key_or_index):
if isinstance(key_or_index, int):
raise IndexError("Index out of range")
else:
raise KeyError(f"Key '{key_or_index}' not found")
def __contains__(self, item_or_key):
"""
实现 item in container 或 key in container 语法
"""
# 先检查是否为键
if item_or_key in self._dict_data:
return True
# 再检查是否为值
return item_or_key in self._list_data
def __len__(self):
"""
实现 len(container) 语法
"""
return len(self._list_data)
def __iter__(self):
"""
实现迭代器协议,允许 for item in container 语法
默认按列表顺序迭代
"""
return iter(self._list_data)
def items(self):
"""
返回所有键值对,类似字典的 items() 方法
"""
return self._dict_data.items()
def keys(self):
"""
返回所有键,类似字典的 keys() 方法
"""
return self._dict_data.keys()
def values(self):
"""
返回所有值,类似字典的 values() 方法
注意:这与直接迭代容器不同,这只返回有键的值
"""
return self._dict_data.values()
def get(self, key, default=None):
"""
通过键获取值,如果键不存在则返回默认值
类似字典的 get() 方法
"""
return self._dict_data.get(key, default)
def get_by_index(self, index, default=None):
"""
通过索引获取值,如果索引不存在则返回默认值
"""
if 0 <= index < len(self._list_data):
return self._list_data[index]
return default
def get_index(self, key):
"""
获取键对应的索引
"""
if key in self._key_index_map:
return self._key_index_map[key]
raise KeyError(f"Key '{key}' not found")
def get_key(self, index):
"""
获取索引对应的键(如果有)
"""
for key, idx in self._key_index_map.items():
if idx == index:
return key
return None
def pop(self, key_or_index, default=None):
"""
移除并返回指定键或索引的元素
如果不存在,返回默认值
"""
try:
value = self[key_or_index]
self.remove(key_or_index)
return value
except (KeyError, IndexError):
if default is not None:
return default
raise
def clear(self):
"""
清空容器
"""
self._list_data.clear()
self._dict_data.clear()
self._key_index_map.clear()
def update(self, other):
"""
使用另一个容器或字典更新当前容器
"""
if isinstance(other, MultiContainer):
for key, value in other.items():
self[key] = value
# 添加没有键的元素
for i, item in enumerate(other):
if other.get_key(i) is None:
self.add(item)
elif isinstance(other, dict):
for key, value in other.items():
self[key] = value
elif isinstance(other, (list, tuple)):
for item in other:
self.add(item)
def __str__(self):
"""
字符串表示
"""
list_repr = str(self._list_data)
dict_repr = str({k: self._dict_data[k] for k in self._dict_data})
return f"MultiContainer(list={list_repr}, dict={dict_repr})"
def __repr__(self):
return self.__str__()
# 测试代码
if __name__ == "__main__":
# 创建一个空容器
container = MultiContainer()
# 添加元素
container.add("apple") # 只能通过索引访问
container.add("banana", "yellow_fruit") # 可以通过键"yellow_fruit"或索引1访问
container.add("cherry", "red_fruit")
print("Container after adding elements:", container)
# 通过索引访问
print("\nAccessing by index:")
print("container[0]:", container[0])
print("container[1]:", container[1])
# 通过键访问
print("\nAccessing by key:")
print("container['yellow_fruit']:", container["yellow_fruit"])
print("container['red_fruit']:", container["red_fruit"])
# 修改元素
container[0] = "green_apple"
container["yellow_fruit"] = "ripe_banana"
print("\nContainer after modifying elements:", container)
# 使用get方法
print("\nUsing get methods:")
print("container.get('yellow_fruit'):", container.get("yellow_fruit"))
print("container.get('missing_key', 'default'):", container.get("missing_key", "default"))
print("container.get_by_index(0):", container.get_by_index(0))
# 检查成员关系
print("\nMembership tests:")
print("'green_apple' in container:", "green_apple" in container)
print("'yellow_fruit' in container:", "yellow_fruit" in container)
print("'orange' in container:", "orange" in container)
# 长度
print("\nLength of container:", len(container))
# 迭代
print("\nIterating over container:")
for item in container:
print(f" {item}")
# 键和值
print("\nKeys:", list(container.keys()))
print("Values (with keys):", list(container.values()))
print("Items:", list(container.items()))
# 索引和键的关系
print("\nIndex-key relationships:")
for i in range(len(container)):
key = container.get_key(i)
value = container[i]
print(f" Index {i}: Key = {key}, Value = {value}")
# 移除元素
print("\nRemoving elements:")
removed_item = container.pop("yellow_fruit")
print(f"Removed 'yellow_fruit': {removed_item}")
print("Container after removal:", container)
# 更新容器
print("\nUpdating container:")
container.update({"new_key": "new_value", "red_fruit": "strawberry"})
container.update(["orange", "grape"])
print("Container after update:", container)
# 清空容器
container.clear()
print("\nContainer after clearing:", container)
# 使用字典初始化
dict_container = MultiContainer({"a": 1, "b": 2, "c": 3})
print("\nContainer initialized with dict:", dict_container)
# 使用列表初始化
list_container = MultiContainer([10, 20, 30, 40])
print("Container initialized with list:", list_container)