跳到主要内容

计算器项目实战

开发一个功能完整的命令行计算器

项目概述

项目目标

开发一个命令行计算器,支持:

  • 基本四则运算
  • 科学计算功能
  • 历史记录
  • 表达式计算

技能点

  • 函数封装
  • 异常处理
  • 循环控制
  • 字典应用
  • 模块化设计

版本1:基础计算器

代码实现

# calculator_v1.py
"""基础计算器 - 版本1"""

def add(a, b):
"""加法"""
return a + b

def subtract(a, b):
"""减法"""
return a - b

def multiply(a, b):
"""乘法"""
return a * b

def divide(a, b):
"""除法"""
if b == 0:
return "错误:除数不能为0"
return a / b

def main():
print("=" * 30)
print(" 简易计算器 v1.0")
print("=" * 30)

while True:
print("\n选择运算:")
print("1. 加法")
print("2. 减法")
print("3. 乘法")
print("4. 除法")
print("5. 退出")

choice = input("\n请选择(1-5):")

if choice == "5":
print("感谢使用,再见!")
break

if choice not in ["1", "2", "3", "4"]:
print("无效选择,请重试")
continue

try:
num1 = float(input("请输入第一个数:"))
num2 = float(input("请输入第二个数:"))
except ValueError:
print("错误:请输入有效的数字")
continue

if choice == "1":
result = add(num1, num2)
operator = "+"
elif choice == "2":
result = subtract(num1, num2)
operator = "-"
elif choice == "3":
result = multiply(num1, num2)
operator = "×"
elif choice == "4":
result = divide(num1, num2)
operator = "÷"

print(f"\n结果:{num1} {operator} {num2} = {result}")

if __name__ == "__main__":
main()

版本2:增加科学计算

代码实现

# calculator_v2.py
"""科学计算器 - 版本2"""

import math

# 基本运算
def add(a, b):
return a + b

def subtract(a, b):
return a - b

def multiply(a, b):
return a * b

def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b

def power(a, b):
"""幂运算"""
return a ** b

def modulo(a, b):
"""取余"""
if b == 0:
raise ValueError("除数不能为0")
return a % b

# 科学运算
def square_root(a):
"""平方根"""
if a < 0:
raise ValueError("负数无法开平方根")
return math.sqrt(a)

def factorial(n):
"""阶乘"""
if n < 0:
raise ValueError("负数没有阶乘")
if not isinstance(n, int) and not n.is_integer():
raise ValueError("阶乘只支持整数")
return math.factorial(int(n))

def logarithm(a, base=10):
"""对数"""
if a <= 0:
raise ValueError("真数必须大于0")
return math.log(a, base)

def sin(angle):
"""正弦(角度)"""
return math.sin(math.radians(angle))

def cos(angle):
"""余弦(角度)"""
return math.cos(math.radians(angle))

def tan(angle):
"""正切(角度)"""
return math.tan(math.radians(angle))

def main():
print("=" * 40)
print(" 科学计算器 v2.0")
print("=" * 40)

while True:
print("\n===== 主菜单 =====")
print("1. 基本运算")
print("2. 科学运算")
print("3. 退出")

main_choice = input("请选择:")

if main_choice == "3":
print("感谢使用!")
break

elif main_choice == "1":
print("\n--- 基本运算 ---")
print("1. 加法 2. 减法 3. 乘法")
print("4. 除法 5. 幂运算 6. 取余")

choice = input("选择运算:")

try:
a = float(input("输入第一个数:"))
b = float(input("输入第二个数:"))

operations = {
"1": (add, "+"),
"2": (subtract, "-"),
"3": (multiply, "×"),
"4": (divide, "÷"),
"5": (power, "^"),
"6": (modulo, "%")
}

if choice in operations:
func, op = operations[choice]
result = func(a, b)
print(f"\n结果:{a} {op} {b} = {result}")
else:
print("无效选择")

except ValueError as e:
print(f"错误:{e}")

elif main_choice == "2":
print("\n--- 科学运算 ---")
print("1. 平方根 2. 阶乘 3. 对数")
print("4. 正弦 5. 余弦 6. 正切")

choice = input("选择运算:")

try:
if choice == "1":
n = float(input("输入数字:"))
print(f"√{n} = {square_root(n)}")
elif choice == "2":
n = float(input("输入整数:"))
print(f"{int(n)}! = {factorial(n)}")
elif choice == "3":
n = float(input("输入真数:"))
base = float(input("输入底数(默认10):") or "10")
print(f"log_{base}({n}) = {logarithm(n, base)}")
elif choice == "4":
angle = float(input("输入角度:"))
print(f"sin({angle}°) = {sin(angle):.6f}")
elif choice == "5":
angle = float(input("输入角度:"))
print(f"cos({angle}°) = {cos(angle):.6f}")
elif choice == "6":
angle = float(input("输入角度:"))
print(f"tan({angle}°) = {tan(angle):.6f}")
else:
print("无效选择")

except ValueError as e:
print(f"错误:{e}")

if __name__ == "__main__":
main()

版本3:增加历史记录

代码实现

# calculator_v3.py
"""带历史记录的计算器 - 版本3"""

import math
from datetime import datetime

class Calculator:
"""计算器类"""

def __init__(self):
self.history = []

def add_to_history(self, expression, result):
"""添加历史记录"""
timestamp = datetime.now().strftime("%H:%M:%S")
self.history.append({
"time": timestamp,
"expression": expression,
"result": result
})

def show_history(self):
"""显示历史记录"""
if not self.history:
print("暂无历史记录")
return

print("\n===== 计算历史 =====")
for i, record in enumerate(self.history, 1):
print(f"{i}. [{record['time']}] {record['expression']} = {record['result']}")

def clear_history(self):
"""清空历史"""
self.history.clear()
print("历史已清空")

def calculate(self, expression):
"""计算表达式"""
try:
# 安全的eval替代方案
allowed_names = {
"sqrt": math.sqrt,
"sin": lambda x: math.sin(math.radians(x)),
"cos": lambda x: math.cos(math.radians(x)),
"tan": lambda x: math.tan(math.radians(x)),
"log": math.log10,
"ln": math.log,
"pi": math.pi,
"e": math.e,
"abs": abs,
"pow": pow
}

result = eval(expression, {"__builtins__": {}}, allowed_names)
self.add_to_history(expression, result)
return result

except ZeroDivisionError:
return "错误:除数不能为0"
except Exception as e:
return f"错误:{e}"

def main():
calc = Calculator()

print("=" * 40)
print(" 高级计算器 v3.0")
print("=" * 40)
print("支持:+, -, *, /, **, sqrt(), sin(), cos(), tan()")
print(" log(), ln(), pi, e")
print("输入 'history' 查看历史,'clear' 清空历史")
print("输入 'quit' 退出")
print("=" * 40)

while True:
expression = input("\n计算 > ").strip()

if not expression:
continue
elif expression.lower() == "quit":
print("再见!")
break
elif expression.lower() == "history":
calc.show_history()
elif expression.lower() == "clear":
calc.clear_history()
else:
result = calc.calculate(expression)
print(f"= {result}")

if __name__ == "__main__":
main()

版本4:模块化设计

项目结构

calculator/
├── __init__.py
├── basic.py
├── scientific.py
├── history.py
└── main.py

basic.py

"""基本运算模块"""

def add(a, b):
return a + b

def subtract(a, b):
return a - b

def multiply(a, b):
return a * b

def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b

def power(a, b):
return a ** b

def modulo(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a % b

scientific.py

"""科学运算模块"""
import math

def square_root(n):
if n < 0:
raise ValueError("负数无法开平方根")
return math.sqrt(n)

def factorial(n):
if n < 0:
raise ValueError("负数没有阶乘")
return math.factorial(int(n))

def log10(n):
if n <= 0:
raise ValueError("真数必须大于0")
return math.log10(n)

def ln(n):
if n <= 0:
raise ValueError("真数必须大于0")
return math.log(n)

def sin_deg(angle):
return math.sin(math.radians(angle))

def cos_deg(angle):
return math.cos(math.radians(angle))

def tan_deg(angle):
return math.tan(math.radians(angle))

history.py

"""历史记录模块"""
from datetime import datetime
import json

class HistoryManager:
def __init__(self, filename="calc_history.json"):
self.filename = filename
self.records = []
self.load()

def add(self, expression, result):
record = {
"time": datetime.now().isoformat(),
"expression": expression,
"result": str(result)
}
self.records.append(record)
self.save()

def show(self, n=10):
if not self.records:
print("暂无历史记录")
return
for record in self.records[-n:]:
print(f"[{record['time'][:19]}] {record['expression']} = {record['result']}")

def clear(self):
self.records.clear()
self.save()

def save(self):
with open(self.filename, "w") as f:
json.dump(self.records, f)

def load(self):
try:
with open(self.filename, "r") as f:
self.records = json.load(f)
except FileNotFoundError:
self.records = []

测试代码

# test_calculator.py
"""测试计算器功能"""

from basic import add, subtract, multiply, divide
from scientific import square_root, factorial

def test_basic():
assert add(2, 3) == 5
assert subtract(5, 3) == 2
assert multiply(4, 3) == 12
assert divide(10, 2) == 5
print("基本运算测试通过!")

def test_scientific():
assert square_root(16) == 4
assert factorial(5) == 120
print("科学运算测试通过!")

if __name__ == "__main__":
test_basic()
test_scientific()

本章小结

通过这个项目,你学会了:

  1. 函数封装:将功能模块化
  2. 异常处理:处理各种错误情况
  3. 类的使用:封装状态和行为
  4. 模块化设计:代码组织
  5. 文件操作:保存历史记录

下一步

完成计算器项目,下一章开发猜数字游戏。

→ 继续阅读:27-猜数字游戏开发