NOI

介绍

信息学奥林匹克竞赛是一项旨在挑战学生计算机科学和算法解决问题能力的竞赛。通常,信息学奥林匹克竞赛分为不同级别,包括初级、中级和高级,以适应不同年龄和能力水平的学生。以下是有关中学生信息学奥林匹克竞赛的一些常见信息:

  • 参赛资格:中学生信息学奥林匹克竞赛通常面向中学生,通常包括初中和高中学生。不同比赛可能有不同的年龄要求,但通常是13岁至18岁之间的学生。
  • 竞赛内容:竞赛内容通常涵盖计算机科学、算法、编程和问题解决。学生需要解决一系列难度递增的编程和算法问题,这些问题可能涉及数据结构、图论、搜索算法、动态规划等。
  • 编程语言:通常,竞赛允许学生使用多种编程语言来解决问题,包括Python、C++、Java等。学生可以选择他们最熟悉或最喜欢的编程语言。
  • 竞赛格式:中学生信息学奥林匹克竞赛的格式可以有所不同,但通常包括一轮在线笔试或编程挑战赛,以及一些学校或区域层面的选拔赛。表现优秀的学生可以晋级到国家或国际级别的比赛。
  • 准备和培训:为了参加竞赛,学生通常需要深入学习计算机科学和算法,并练习解决类似竞赛问题的编程练习。学校、教师和竞赛培训机构可能提供相关的培训和资源。
  • 奖励和认可:获奖学生通常会获得奖牌、证书、奖金或其他奖励,并且他们的成绩可能会被用于升学申请或获得学术和职业机会。

中学生信息学奥林匹克竞赛旨在鼓励学生对计算机科学和编程的兴趣,培养他们的解决问题和创造力。这类竞赛也为有志于从事计算机科学或相关领域的学生提供了一个宝贵的学习和发展机会。如果你是一名中学生,有兴趣参加这类竞赛,可以咨询你所在学校或地区的信息学奥林匹克竞赛组织,以获取更多详细信息和参赛指南。

如何入门?

要入门中学生信息学奥林匹克竞赛,你可以按照以下步骤逐渐准备和提高你的竞赛技能:

  • 了解竞赛规则和要求:

首先,获取关于中学生信息学奥林匹克竞赛的详细信息,包括规则、资格要求、竞赛格式和时间表。你可以从学校、教师、竞赛组织或官方竞赛网站获取这些信息。

  • 学习编程基础:

如果你还没有编程经验,建议首先学习一门编程语言,如Python,这是一个易于学习的语言,适合初学者。你可以通过在线教程、编程课程或自学来掌握基础编程概念和技能。
学习算法和数据结构:

竞赛通常涉及复杂的算法和数据结构问题,因此你需要学习和理解这些概念。阅读相关教材、参加在线课程或参考算法书籍都是提高算法能力的好方法。

  • 解决编程练习题:

练习是提高竞赛技能的关键。寻找在线编程挑战平台(如LeetCode、Codeforces、AtCoder等)并解决各种算法和编程问题。这些平台通常提供了大量的练习题目,可以帮助你熟悉不同类型的竞赛问题。

  • 参加竞赛训练班:

有些学校或培训机构提供专门为竞赛准备的培训课程。如果有机会,可以考虑参加这些课程,与其他有志于参加竞赛的学生一起学习和训练。
参加模拟竞赛:

参加模拟竞赛可以帮助你熟悉竞赛的格式和时间限制。寻找在线模拟竞赛或与其他学生一起组织模拟竞赛。
寻求指导和反馈:

如果有老师或教练可以提供指导和反馈,那将会很有帮助。他们可以帮助你识别问题并提供更有效的解决方法。

  • 坚持练习:

信息学奥林匹克竞赛需要长期准备和坚持不懈的努力。每天保持练习,不断提高自己的编程和算法技能。
参加竞赛并积累经验:

最后,积累参加竞赛的经验。即使你在刚开始可能不会获胜,但经验是非常宝贵的,可以帮助你在未来的比赛中表现更好。
总之,准备中学生信息学奥林匹克竞赛需要时间、耐心和坚持。通过不断学习和练习,你可以提高自己的编程和算法技能,逐渐在竞赛中取得更好的成绩。

C++ 入门教程

8-LeWD3rr3UzgTEpt.png

虚拟环境

在Python中,虚拟环境是一种用于隔离项目依赖和包的工具,以便在不同项目之间管理不同版本的库和包。虚拟环境允许你在同一系统上同时运行多个Python项目,每个项目都可以有自己独立的依赖,而不会互相干扰。

创建虚拟环境的基本步骤

以下是在Python中创建虚拟环境的基本步骤:

1. 安装virtualenv(可选):

在某些Python发行版中,virtualenv已经包含在内,你可以直接使用。如果你使用的是较旧的Python版本或者没有安装virtualenv,你可以通过以下方式安装它:

pip install virtualenv

2. 创建虚拟环境:

选择一个用于存放虚拟环境的目录,并使用virtualenv命令创建虚拟环境。例如,假设你想在项目目录中创建一个名为myenv的虚拟环境,你可以运行以下命令:

virtualenv myenv

这将在当前目录下创建一个myenv文件夹,并在其中创建一个独立的Python解释器和标准库。

3. 激活虚拟环境:

在不同的操作系统上,激活虚拟环境的方式有所不同:

  • 在 Windows 上,使用以下命令激活虚拟环境:

    myenv\Scripts\activate

  • 在 macOS 和 Linux 上,使用以下命令激活虚拟环境:

    source myenv/bin/activate

一旦虚拟环境被激活,你的命令行提示符将会显示虚拟环境的名称,表示你正在使用虚拟环境。

3. 安装依赖:

在虚拟环境中,你可以使用pip来安装项目所需的依赖包,这些依赖包将仅在当前虚拟环境中可用,不会影响系统Python或其他虚拟环境。
例如

pip install pygame

4. 退出虚拟环境:

当你完成项目工作或者需要切换到另一个虚拟环境时,可以使用以下命令退出当前虚拟环境:

deactivate

这样,你就可以创建和管理多个独立的Python虚拟环境,每个虚拟环境都可以具有不同的依赖项,使项目之间保持隔离。这对于开发和维护Python项目非常有用。

virtualenv myenv 和 python -m venv myenv两种方式的区别

virtualenvpython -m venv 是两种用于创建 Python 虚拟环境的不同工具,它们有一些区别,包括支持的 Python 版本和一些功能。

1. virtualenv:

virtualenv 是一个独立的第三方工具,需要单独安装(使用 pip install virtualenv)。
它兼容多个 Python 版本,并且可以用于创建 Python 2.x 和 Python 3.x 的虚拟环境。
virtualenv 生成的虚拟环境通常较小,因为它不包含 Python 标准库。
可以使用 --system-site-packages 标志来让虚拟环境访问系统全局安装的包。
示例创建虚拟环境的命令:

virtualenv myenv

2. python -m venv:

python -m venv 是 Python 内置的虚拟环境创建工具,不需要额外安装。
它是 Python 3.3 及更高版本的一部分,因此只能用于创建 Python 3.x 的虚拟环境。
python -m venv 生成的虚拟环境包含了 Python 标准库。
默认情况下,虚拟环境是隔离的,不会访问系统全局安装的包,这有助于确保项目的依赖独立。
示例创建虚拟环境的命令:

python -m venv myenv

总的来说,如果你在使用 Python 3.x,推荐使用 python -m venv 来创建虚拟环境,因为它是 Python 内置的工具,并且通常更容易使用。如果你需要在多个 Python 版本之间切换,或者需要使用 Python 2.x,那么 virtualenv 可能是一个更好的选择。

小结

最新的python3 是主流,已经到python 3.12了,所以还是推荐使用python -m venv方式创建虚拟环境变量,用起来比较顺手。介绍的知识作为参考,上网查询的时候可能会碰到这些不同的做法,有个心理准备!

除了 virtualenv 和 python -m venv,还有其他一些方式可以创建虚拟环境,具体取决于你的需求和环境。以下是一些其他常见的虚拟环境管理工具, conda, pyenv,Pipenv
这些工具都具有不同的优点和特点,可以根据你的需求和偏好选择其中之一来管理虚拟环境。每种工具都有其独特的用例,因此可以根据项目的具体需求来选择最合适的方式。
细节就不展开了,等有了足够的经验,再自行探索,目前我们就用python -m venv myvenv创建虚拟环境
>python -m venv myvenv
>source myvenv/bin/activate
>deactivate

R-C.png

当涉及到面向对象编程(Object-Oriented Programming,OOP)时,Python是一种非常强大且灵活的编程语言。在Python中,一切皆对象,你可以使用类(class)和对象(object)来实现面向对象的编程范例。这使得代码更加模块化、可重用,并且更易于理解。

下面是一个简单的Python面向对象编程入门指南:

1. 类和对象

类是一个定义了对象的结构和行为的蓝图,而对象则是类的实例化。类是创建对象的模板,包含了属性(成员变量)和方法(成员函数)。可以使用关键字class来创建类。

class MyClass:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, {self.name}!"

2. 构造函数和实例化

在上面的例子中,__init__是一个特殊的方法,称为构造函数(Constructor)。它在创建对象时自动调用,并用于初始化对象的属性。self参数表示类的实例本身。

实例化一个类意味着创建类的一个具体对象,这可以通过以下方式完成:

obj = MyClass("John")

3. 成员变量和成员函数

成员变量是类中存储数据的属性,可以通过self.variable_name来定义和访问它们。成员函数是类中定义的方法,可以访问和操作成员变量,也可以执行其他操作。

class MyClass:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, {self.name}!"

    def set_name(self, new_name):
        self.name = new_name

4. 继承

继承是OOP中的一个重要概念,允许你创建一个新类(子类),并从现有类(父类)继承属性和方法。子类可以覆盖父类的方法或添加新的方法。

class ChildClass(MyClass):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age

    def greet(self):
        return f"Hello, {self.name}! You are {self.age} years old."

5. 多态

多态性允许不同类的对象对相同的方法进行调用,但是根据对象的类型,方法的实现可能会有所不同。这增加了灵活性和可扩展性。
举例说明一下多态:
当涉及到多态时,我们通常会利用继承和方法重写的特性。多态允许不同类的对象对相同的方法进行调用,但是根据对象的类型,方法的实现可能会有所不同。这增加了代码的灵活性,使得我们可以在运行时选择调用哪个类的方法。

让我们通过一个简单的例子来说明多态:

假设我们有一个动物类 Animal,它有一个 speak 方法,用于返回该动物的叫声。然后我们有两个子类 Dog 和 Cat,它们分别继承自 Animal 类,并且都重写了 speak 方法。

class Animal:

def speak(self):
    return "Unknown animal sound."

class Dog(Animal):

def speak(self):
    return "Woof!"

class Cat(Animal):

def speak(self):
    return "Meow!"

在我们可以创建 Dog 和 Cat 的对象,并调用它们的 speak 方法:

dog = Dog()
cat = Cat()

print(dog.speak()) # 输出: "Woof!"
print(cat.speak()) # 输出: "Meow!"

在这个例子中,我们使用多态来实现了不同类型的动物有不同的叫声。虽然我们调用了相同的 speak 方法,但由于对象的类型不同,它们的实现也不同。这就是多态的效果。

多态性还可以在更复杂的场景中发挥作用,比如创建一个函数,该函数接受 Animal 类的对象作为参数,并调用它们的 speak 方法:

def animal_sound(animal):

return animal.speak()

使用多态调用不同对象的 speak 方法

print(animal_sound(dog)) # 输出: "Woof!"
print(animal_sound(cat)) # 输出: "Meow!"

通过这种方式,我们可以根据传递给 animal_sound 函数的实际对象来调用不同类的方法,而无需显式地编写多个条件判断语句。这提高了代码的可读性和可维护性。

6. 封装

封装是OOP中的另一个重要概念,它意味着将数据和代码(方法)包装在一个单独的单位中,对外部隐藏内部的实现细节。这可以通过使用私有成员变量和方法来实现,例如在成员变量前加上双下划线__。
举例详细说明一下封装的概念

封装是面向对象编程中的一个重要概念,它指的是将数据(成员变量)和代码(成员函数)包装在一个单独的单位中,并对外部隐藏内部的实现细节。封装使得对象的内部实现对外部是不可见的,只有通过公共接口(成员函数)才能与对象进行交互。这样可以保护数据的完整性,避免直接访问和修改对象的内部状态,从而降低了代码的耦合性,提高了代码的安全性和可维护性。

在Python中,封装通过使用访问控制修饰符来实现,这些修饰符是命名约定,而不是强制性的。Python有三种类型的访问控制修饰符:

公有访问修饰符:成员变量和成员函数默认为公有,可以在类的内部和外部进行访问。

受保护的访问修饰符:在成员变量或成员函数名前加上一个下划线 _,表示这些成员在类的内部和子类中可以访问,但在类的外部不应直接访问。

私有访问修饰符:在成员变量或成员函数名前加上两个下划线 __,表示这些成员只能在类的内部访问,对于类的外部是不可见的。

让我们通过一个简单的示例来说明封装的概念:

class Car:
    def __init__(self, make, model, year):
        self.make = make  # 公有变量
        self.model = model  # 公有变量
        self.__year = year  # 私有变量

    def start_engine(self):
        return "Engine started!"

    def __display_year(self):  # 私有方法
        return f"Manufactured in {self.__year}"

    def get_year(self):  # 公有方法,用于获取私有变量的值
        return self.__display_year()


car = Car("Toyota", "Camry", 2022)

print(car.make)  # 输出: "Toyota"
print(car.start_engine())  # 输出: "Engine started!"

# 下面这两行代码会导致错误,因为 __year 是私有变量
# print(car.__year)
# print(car.__display_year())

# 使用公有方法获取私有变量的值
print(car.get_year())  # 输出: "Manufactured in 2022"

在上面的示例中,我们定义了一个 Car 类,其中包含一个公有变量 make、model,和一个私有变量 __year。我们还定义了一个公有方法 get_year(),用于获取私有变量 __year 的值。通过这种方式,我们实现了封装,隐藏了 __year 变量的实现细节,同时还提供了一个公共接口来访问和获取这个私有变量的值。

总结来说,封装是面向对象编程的一种核心原则,它通过访问控制修饰符来隐藏对象的内部实现细节,提高代码的安全性和可维护性,同时也提供了一个公共接口,通过该接口来与对象进行交互。这样可以有效地隔离和组织代码,让代码更易于理解和维护。

7. 访问控制

Python没有严格的访问控制机制,但通过命名约定来实现对类成员的访问限制。以单下划线开头的成员被认为是受保护的,应该避免直接访问,而以双下划线开头的成员是私有的,外部无法直接访问。
举例详细解释一下访问控制概念

访问控制是面向对象编程中用于限制类成员(成员变量和成员函数)访问权限的机制。在Python中,访问控制是通过访问控制修饰符实现的,这些修饰符是命名约定,不是强制性的。

Python中有三种类型的访问控制修饰符:

公有访问修饰符:成员变量和成员函数默认为公有,在类的内部和外部都可以进行访问。

受保护的访问修饰符:在成员变量或成员函数名前加上一个下划线 _,表示这些成员在类的内部和子类中可以访问,但在类的外部不应直接访问。虽然在语法上是可以访问的,但是通常认为这些成员不应该被外部直接访问。

私有访问修饰符:在成员变量或成员函数名前加上两个下划线 __,表示这些成员只能在类的内部访问,对于类的外部是不可见的。外部无法直接访问私有成员,但在类的内部是可以访问的。

让我们通过一个示例来解释访问控制的细节:

class MyClass:
    def __init__(self):
        self.public_var = "This is a public variable."
        self._protected_var = "This is a protected variable."
        self.__private_var = "This is a private variable."

    def public_method(self):
        return "This is a public method."

    def _protected_method(self):
        return "This is a protected method."

    def __private_method(self):
        return "This is a private method."

变量和成员函数:

public_var 和 public_method 是公有的,可以在类的内部和外部直接访问。

_protected_var 和 _protected_method 是受保护的,在类的内部和子类中可以访问,但在类的外部也可以直接访问。但是通常不建议在类的外部直接访问受保护的成员。

__private_var 和 __private_method 是私有的,只能在类的内部访问,对于类的外部是不可见的。

现在,我们来测试一下是否能够直接访问这些成员:

obj = MyClass()

# 访问公有成员
print(obj.public_var)        # 输出: "This is a public variable."
print(obj.public_method())   # 输出: "This is a public method."

# 访问受保护成员(不建议这样做,但是语法上是可以的)
print(obj._protected_var)    # 输出: "This is a protected variable."
print(obj._protected_method())  # 输出: "This is a protected method."

# 下面这两行代码会导致错误,因为 __private_var 和 __private_method 是私有成员
# print(obj.__private_var)
# print(obj.__private_method)

虽然在Python中语法上是可以直接访问受保护的成员和私有成员的,但是通常建议遵循访问控制的原则,不要在类的外部直接访问受保护和私有成员。应该使用类提供的公共接口(公有方法)来访问和操作类的成员,这样可以更好地控制访问权限,提高代码的安全性和可维护性。
这是一个简单的面向对象编程入门指南。掌握这些基本概念将使你能够更好地利用Python的面向对象编程特性,创建复杂且结构良好的程序。

截图 2023-07-19 20-16-47.png

复习一下Python面向对象编程,构建一个简单的ATM类,实现ATM自助取款机的模拟
这是一组渐进式的练习,从最简单的ATM类,到持久性数据保存,构成一系列适合初学者的练习
ATM - Automatic Trasaction Machine
简化模拟,只需要实现下面的一些功能:
1. 登录功能(这里简化,不需要实现)
2. 创建账户
3. 存钱
4. 取钱
5. 退出

第一个版本atm_v1.py

构建基本的ATM类,包含几个方法,初始化一个ATM实例,调用其方法

最主要的功能有存储账户信息、存钱、取钱; 账户信息使用Python 字典数据类型
class ATM:
    def __init__(self):
        self.accounts = {}  # 用于存储账户信息的字典

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = initial_balance
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number] += amount
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number] >= amount:
                self.accounts[account_number] -= amount
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在。")

# 测试ATM类
atm = ATM()
atm.create_account("123456789", 1000)
atm.deposit("123456789", 500)
atm.withdraw("123456789", 200)
print(atm.check_balance("123456789"))

第二个版本atm_v2.py

增加菜单,初始化ATM实例,一直运行,直到用户退出菜单,这个比较符合正常使用场景
增加几个方法:一个run方法让ATM一直执行,show_menu菜单

class ATM:
    def __init__(self):
        self.accounts = {}

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = initial_balance
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number] += amount
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number] >= amount:
                self.accounts[account_number] -= amount
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在.")

    def show_menu(self):
        print("===== ATM菜单 =====")
        print("1. 创建账户")
        print("2. 查询余额")
        print("3. 存款")
        print("4. 取款")
        print("0. 退出")

    def run(self):
        while True:
            self.show_menu()
            choice = input("请输入选项数字:")

            if choice == "1":
                account_number = input("请输入账户号码:")
                initial_balance = float(input("请输入初始余额:"))
                self.create_account(account_number, initial_balance)

            elif choice == "2":
                account_number = input("请输入账户号码:")
                balance = self.check_balance(account_number)
                if balance is not None:
                    print(f"账户 {account_number} 的余额为 {balance} 元。")

            elif choice == "3":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入存款金额:"))
                self.deposit(account_number, amount)

            elif choice == "4":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入取款金额:"))
                self.withdraw(account_number, amount)

            elif choice == "0":
                print("感谢使用ATM,再见!")
                break

            else:
                print("无效选项,请重新输入。")

# 实例化ATM对象并运行
atm = ATM()
atm.run()

第三个版本 atm_v3.py

增加了历史记录存储

增加一个list变量 self.history,用来存储操作记录
class ATM:
    def __init__(self):
        self.accounts = {}
        self.history = []

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = initial_balance
            self.history.append(f"创建账户 {account_number},初始余额为 {initial_balance} 元。")
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number] += amount
            self.history.append(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number] >= amount:
                self.accounts[account_number] -= amount
                self.history.append(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在.")
    def show_history(self):
        print("===== 操作历史记录 =====")
        for entry in self.history:
            print(entry)
        print("======================")
    
    def show_menu(self):
        print("===== ATM菜单 =====")
        print("1. 创建账户")
        print("2. 查询余额")
        print("3. 存款")
        print("4. 取款")
        print("5. 显示操作历史记录")
        print("0. 退出")

    def run(self):
        while True:
            self.show_menu()
            choice = input("请输入选项数字:")

            if choice == "1":
                account_number = input("请输入账户号码:")
                initial_balance = float(input("请输入初始余额:"))
                self.create_account(account_number, initial_balance)

            elif choice == "2":
                account_number = input("请输入账户号码:")
                balance = self.check_balance(account_number)
                if balance is not None:
                    print(f"账户 {account_number} 的余额为 {balance} 元。")

            elif choice == "3":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入存款金额:"))
                self.deposit(account_number, amount)

            elif choice == "4":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入取款金额:"))
                self.withdraw(account_number, amount)
            
            elif choice == "5":
                self.show_history()

            elif choice == "0":
                print("感谢使用ATM,再见!")
                break

            else:
                print("无效选项,请重新输入。")

# 实例化ATM对象并运行
atm = ATM()
atm.run()

第四个版本atm_v4.py

每个用户的历史记录单独存储
每个用户保存自己的历史记录,可以学习如何使用嵌套的数据类型,字典里面嵌套字典
将history变量放入账户变量self.accounts里面,这样每个账户单独保存各自的操作记录

class ATM:
    def __init__(self):
        self.accounts = {}

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = {
                "balance": initial_balance,
                "history": []
            }
            self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]["balance"]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number]["balance"] += amount
            self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number]["balance"] >= amount:
                self.accounts[account_number]["balance"] -= amount
                self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在.")

    def show_history(self, account_number):
        if account_number in self.accounts:
            print(f"===== 账户 {account_number} 操作历史记录 =====")
            for entry in self.accounts[account_number]["history"]:
                print(entry)
            print("==============================")
        else:
            print("该账户不存在。")

    def show_menu(self):
        print("[===== ATM菜单 =====]")
        print("1. 创建账户")
        print("2. 查询余额")
        print("3. 存款")
        print("4. 取款")
        print("5. 显示操作历史记录")
        print("0. 退出")

    def run(self):
        while True:
            self.show_menu()
            choice = input("请输入选项数字:")

            if choice == "1":
                account_number = input("请输入账户号码:")
                initial_balance = float(input("请输入初始余额:"))
                self.create_account(account_number, initial_balance)

            elif choice == "2":
                account_number = input("请输入账户号码:")
                balance = self.check_balance(account_number)
                if balance is not None:
                    print(f"账户 {account_number} 的余额为 {balance} 元。")

            elif choice == "3":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入存款金额:"))
                self.deposit(account_number, amount)

            elif choice == "4":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入取款金额:"))
                self.withdraw(account_number, amount)

            elif choice == "5":
                account_number = input("请输入账户号码:")
                self.show_history(account_number)

            elif choice == "0":
                print("感谢使用ATM,再见!")
                break

            else:
                print("无效选项,请重新输入。")

# 实例化ATM对象并运行
atm = ATM()
atm.run()

继续进化...

第五个版本atm_v5.py

使用pickle持久存储数据,将账户信息保存到本地文件里面
pickle的中文资料,百度搜索
import pickle

class ATM:
    def __init__(self):
        self.accounts = {}
        self.load_data()  # 在初始化时加载之前保存的数据

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = {
                "balance": initial_balance,
                "history": []
            }
            self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]["balance"]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number]["balance"] += amount
            self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number]["balance"] >= amount:
                self.accounts[account_number]["balance"] -= amount
                self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在.")

    def show_history(self, account_number):
        if account_number in self.accounts:
            print(f"===== 账户 {account_number} 操作历史记录 =====")
            for entry in self.accounts[account_number]["history"]:
                print(entry)
            print("==============================")
        else:
            print("该账户不存在。")

    def show_menu(self):
        print("[===== ATM菜单 =====]")
        print("1. 创建账户")
        print("2. 查询余额")
        print("3. 存款")
        print("4. 取款")
        print("5. 显示操作历史记录")
        print("0. 退出")

    def load_data(self):
        try:
            with open("accounts_data.pickle", "rb") as file:
                self.accounts = pickle.load(file)
        except FileNotFoundError:
            # 如果文件不存在,可以忽略此错误
            pass

    def save_data(self):
        with open("accounts_data.pickle", "wb") as file:
            pickle.dump(self.accounts, file)

    def run(self):
        while True:
            self.show_menu()
            choice = input("请输入选项数字:")

            if choice == "1":
                account_number = input("请输入账户号码:")
                initial_balance = float(input("请输入初始余额:"))
                self.create_account(account_number, initial_balance)

            elif choice == "2":
                account_number = input("请输入账户号码:")
                balance = self.check_balance(account_number)
                if balance is not None:
                    print(f"账户 {account_number} 的余额为 {balance} 元。")

            elif choice == "3":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入存款金额:"))
                self.deposit(account_number, amount)

            elif choice == "4":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入取款金额:"))
                self.withdraw(account_number, amount)

            elif choice == "5":
                account_number = input("请输入账户号码:")
                self.show_history(account_number)

            elif choice == "0":
                self.save_data()  # 在退出前保存数据
                print("感谢使用ATM,再见!")
                break

            else:
                print("无效选项,请重新输入。")

# 实例化ATM对象并运行
atm = ATM()
atm.run()

第六个版本atm_v4.py

使用加密库,对账户信息文件加密
使用cryptography库
如果没有安装,使用下面命令安装一下:pip install cryptography

from cryptography.fernet import Fernet
import pickle
import cryptography
import os
# 生成密钥并保存到文件中
def generate_key():
    # 密钥文件路径
    key_file_path = "secret.key"

    # 检查文件是否存在,存在就不重新生成key
    if os.path.exists(key_file_path) and os.path.isfile(key_file_path):
        return
    key = Fernet.generate_key()
    with open("secret.key", "wb") as key_file:
        key_file.write(key)

# 加载密钥
def load_key():
    return open("secret.key", "rb").read()

# 加密数据
def encrypt_data(data, key):
    f = Fernet(key)
    return f.encrypt(data)

# 解密数据
def decrypt_data(encrypted_data, key):
    f = Fernet(key)
    return f.decrypt(encrypted_data)

class ATM:
    def __init__(self):
        self.accounts = {}
        self.load_data()  # 在初始化时加载之前保存的数据

    def create_account(self, account_number, initial_balance):
        if account_number not in self.accounts:
            self.accounts[account_number] = {
                "balance": initial_balance,
                "history": []
            }
            self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
            print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
        else:
            print("该账户已存在。")

    def check_balance(self, account_number):
        if account_number in self.accounts:
            return self.accounts[account_number]["balance"]
        else:
            print("该账户不存在。")
            return None

    def deposit(self, account_number, amount):
        if account_number in self.accounts:
            self.accounts[account_number]["balance"] += amount
            self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
        else:
            print("该账户不存在。")

    def withdraw(self, account_number, amount):
        if account_number in self.accounts:
            if self.accounts[account_number]["balance"] >= amount:
                self.accounts[account_number]["balance"] -= amount
                self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
                print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
            else:
                print("余额不足,无法完成取款。")
        else:
            print("该账户不存在.")

    def show_history(self, account_number):
        if account_number in self.accounts:
            print(f"===== 账户 {account_number} 操作历史记录 =====")
            for entry in self.accounts[account_number]["history"]:
                print(entry)
            print("==============================")
        else:
            print("该账户不存在。")

    def show_menu(self):
        print("[===== ATM菜单 =====]")
        print("1. 创建账户")
        print("2. 查询余额")
        print("3. 存款")
        print("4. 取款")
        print("5. 显示操作历史记录")
        print("0. 退出")

    def load_data(self):
        try:
            key = load_key()
            with open("accounts_data.pickle", "rb") as file:
                encrypted_data = file.read()
                decrypted_data = decrypt_data(encrypted_data, key)
                self.accounts = pickle.loads(decrypted_data)
        except (FileNotFoundError, pickle.UnpicklingError, cryptography.fernet.InvalidToken):
            # 如果文件不存在或解密失败,可以忽略此错误
            print("fail to load data")

    def save_data(self):
        key = load_key()
        data_to_save = pickle.dumps(self.accounts)
        encrypted_data = encrypt_data(data_to_save, key)
        with open("accounts_data.pickle", "wb") as file:
            file.write(encrypted_data)

    def run(self):
        while True:
            self.show_menu()
            choice = input("请输入选项数字:")

            if choice == "1":
                account_number = input("请输入账户号码:")
                initial_balance = float(input("请输入初始余额:"))
                self.create_account(account_number, initial_balance)

            elif choice == "2":
                account_number = input("请输入账户号码:")
                balance = self.check_balance(account_number)
                if balance is not None:
                    print(f"账户 {account_number} 的余额为 {balance} 元。")

            elif choice == "3":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入存款金额:"))
                self.deposit(account_number, amount)

            elif choice == "4":
                account_number = input("请输入账户号码:")
                amount = float(input("请输入取款金额:"))
                self.withdraw(account_number, amount)

            elif choice == "5":
                account_number = input("请输入账户号码:")
                self.show_history(account_number)

            elif choice == "0":
                self.save_data()  # 在退出前保存数据
                print("感谢使用ATM,再见!")
                break

            else:
                print("无效选项,请重新输入。")

# 生成密钥(仅需执行一次)
generate_key()

# 实例化ATM对象并运行
atm = ATM()
atm.run()

运行画面

[===== ATM菜单 =====]
1. 创建账户
2. 查询余额
3. 存款
4. 取款
5. 显示操作历史记录
0. 退出
请输入选项数字:

截图 2023-07-19 20-17-07.png

使用pygame的gfxdraw模块实现火焰特效
from pygame import gfxdraw

主要使用了pygame里面的gfxdraw模块,对pixel进行操作

import pygame as pg
import sys
from pygame import gfxdraw
from random import randint

WIN_SIZE = WIDTH, HEIGHT = 640, 480
STEPS_BETWEEN_COLORS = 9
COLORS = ['black', 'red', 'orange', 'yellow', 'white']
PIXEL_SIZE = 3

FIRE_REPS = 4
FIRE_WIDTH = WIDTH // (PIXEL_SIZE * FIRE_REPS)
FIRE_HEIGHT = HEIGHT // PIXEL_SIZE


class MyFire:
    def __init__(self, app):
        self.app = app
        self.palette = self.get_palette()
        self.fire_array = self.get_fire_array()
        self.fire_surf = pg.Surface([PIXEL_SIZE * FIRE_WIDTH, HEIGHT])
        self.fire_surf.set_colorkey('black')

        self.logo = pg.image.load('dazuicheng.jpg').convert_alpha()
        self.logo = pg.transform.scale2x(self.logo)
        self.logo_x, self.logo_y = (WIDTH // 2 - self.logo.get_width() // 2,
                                    HEIGHT // 3 - self.logo.get_height() // 2)
        self.logo_start_y = HEIGHT

    def draw_logo(self):
        if self.logo_start_y > self.logo_y:
            self.logo_start_y -= 5
        self.app.screen.blit(self.logo, (self.logo_x, self.logo_start_y))

    def do_fire(self):
        for x in range(FIRE_WIDTH):
            for y in range(1, FIRE_HEIGHT):
                color_index = self.fire_array[y][x]
                if color_index:
                    rnd = randint(0, 3)
                    self.fire_array[y - 1][(x - rnd + 1) % FIRE_WIDTH] = color_index - rnd % 2
                else:
                    self.fire_array[y - 1][x] = 0

    def draw_fire(self):
        self.fire_surf.fill('black')
        for y, row in enumerate(self.fire_array):
            for x, color_index in enumerate(row):
                if color_index:
                    color = self.palette[color_index]
                    gfxdraw.box(self.fire_surf, (x * PIXEL_SIZE, y * PIXEL_SIZE,
                                                  PIXEL_SIZE, PIXEL_SIZE), color)

        for i in range(FIRE_REPS):
            self.app.screen.blit(self.fire_surf, (self.fire_surf.get_width() * i, 0))

    def get_fire_array(self):
        fire_array = [[0 for i in range(FIRE_WIDTH)] for j in range(FIRE_HEIGHT)]
        for i in range(FIRE_WIDTH):
            fire_array[FIRE_HEIGHT - 1][i] = len(self.palette) - 1
        return fire_array

    def draw_palette(self):
        size = 90
        for i, color in enumerate(self.palette):
            pg.draw.rect(self.app.screen, color, (i * size, HEIGHT // 2, size - 5, size - 5))

    @staticmethod
    def get_palette():
        palette = [(0, 0, 0)]
        for i, color in enumerate(COLORS[:-1]):
            c1, c2 = color, COLORS[i + 1]
            for step in range(STEPS_BETWEEN_COLORS):
                c = pg.Color(c1).lerp(c2, (step + 0.5) / STEPS_BETWEEN_COLORS)
                palette.append(c)
        return palette

    def update(self):
        self.do_fire()

    def draw(self):
        self.draw_logo()
        # self.draw_palette()
        self.draw_fire()


class App:
    def __init__(self):
        self.screen = pg.display.set_mode(size=WIN_SIZE)
        self.clock = pg.time.Clock()
        self.dzc_fire = MyFire(self)

    def update(self):
        self.dzc_fire.update()
        self.clock.tick(60)
        pg.display.set_caption(f'{self.clock.get_fps() :.1f}')

    def draw(self):
        self.screen.fill('black')
        self.dzc_fire.draw()
        pg.display.flip()

    def run(self):
        while True:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    pg.quit()
                    sys.exit()
            self.update()
            self.draw()


if __name__ == '__main__':
    app = App()
    app.run()

效果

截图 2023-07-22 00-26-01.png