计算器项目实战
开发一个功能完整的命令行计算器
项目概述
项目目标
开发一个命令行计算器,支持:
- 基本四则运算
- 科学计算功能
- 历史记录
- 表达式计算
技能点
- 函数封装
- 异常处理
- 循环控制
- 字典应用
- 模块化设计
版本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()
本章小结
通过这个项目,你学会了:
- 函数封装:将功能模块化
- 异常处理:处理各种错误情况
- 类的使用:封装状态和行为
- 模块化设计:代码组织
- 文件操作:保存历史记录
下一步
完成计算器项目,下一章开发猜数字游戏。
→ 继续阅读:27-猜数字游戏开发