python小项目编程-初级(1、计算器)

发布于:2025-02-10 ⋅ 阅读:(40) ⋅ 点赞:(0)

1. 需求分析

1.1 功能需求

1)支持基本的四则运算:加法(+)、减法(-)、乘法(*)、除法(/);2)支持多步运算,例如 1 + 2 * 3;3)不支持括号,但运算符优先级遵循数学规则(先乘除,后加减)

1.3 非功能需求

1)提供简单的错误处理,例如除零错误或非法运算表达式输入;2)通过单元测试确保代码的正确性并人工测试保证可用性。

2、设计

2.1 总体设计

1、输入:用户通过命令行输入一个字符串表达式,例如1+2*2,

2、解析输入:将字符串解析为数字和操作符的列表,例如 [1, '+', 2, '*', 2]

3、计算:先计算乘法和除法(优先级高)再计算加法和减法(优先级低)

4、结果:返回最终的计算结果。

2.2 模块设计

1、parse_expression模块:将输入的字符串解析为数字和操作符的列表。使用正则表达式提取数字和操作符

2、calculate模块:按照运算符优先级计算表达式先处理乘和法,再处理加和减。

3、main模块:接收用户输入,处理输入异常,调用解析和计算模块,输出结果
 

2.3 数据结构

使用列表存储解析后的表达式,例如 [1, '+', 2, '*', 3]

2.4 错误处理

检查除零错误。检查非法输入进行输入规则校验保证合法输入,对非法输入抛出异常。使用正则表达式pattern来验证输入的表达式格式。正则表达式的规则确保了表达式只包含数字、运算符和括号,并且遵循正确的格式。如果输入不符合规则,抛出ValleError异常,并给出相应的错误提示。

实现

3.1 代码实现

import re

def parse_expression(expression):
    """
    将表达式字符串解析为数字和操作符的列表。
    例如:"1+2*3" -> [1, '+', 2, '*', 3]
    """
    # 使用正则表达式匹配数字和操作符
    tokens = re.findall(r'\d+\.\d+|\d+|[+\-*/]', expression)
    # 将数字转换为整数或浮点数
    for i, token in enumerate(tokens):
        if token not in {'+','-','*','/'}:
            if '.' in token:
                tokens[i]=float(token)
            else:
                tokens[i] = int(token)
    print(tokens)
    return tokens

def calculate(tokens):
    """
    计算解析后的表达式列表。
    处理乘法和除法的优先级。
    """
    # 先处理乘法和除法
    i = 0
    while i < len(tokens):
        if tokens[i] == '*':
            tokens[i - 1] = tokens[i - 1] * tokens[i + 1]
            del tokens[i:i + 2]
        elif tokens[i] == '/':
            if tokens[i + 1] == 0:
                raise ValueError("除零错误")
            tokens[i - 1] = tokens[i - 1] / tokens[i + 1]
            del tokens[i:i + 2]
        else:
            i += 1

    # 再处理加法和减法
    result = tokens[0]
    i = 1
    while i < len(tokens):
        if tokens[i] == '+':
            result += tokens[i + 1]
        elif tokens[i] == '-':
            result -= tokens[i + 1]
        i += 2
    return result
def main_process():
    
    print("支持的运算:加(+)、减(-)、乘(*)、除(/)")
    print("输入 'exit' 退出计算器")
    pattern = r'^\s*[\d]+(\.\d+)?(\s*[\+\-\*\/]\s*[\d]+(\.\d+)?)*\s*$'
    
    while True:
        expression = input("请输入表达式(例如 1+2*3):")
        if expression.lower() == 'exit':
            print("感谢使用,再见!")
            break
        try:
            if not re.match(pattern, expression):
                raise ValueError("输入格式错误,请确保只包含数字、运算符,并遵循正确的格式。")
            tokens = parse_expression(expression)
            result = calculate(tokens)
            print(f"结果: {result}")
        except Exception as e:
            print(f"输入错误:{e}")
if __name__ == "__main__":
    main_process()

测试:

测试用例

测试样例 测试结果 预期
1+1 2 2   PASS
2*3+6 12 12 PASS
10 - 4/2 8.0 8.0 PASS
1+2*3 7 7 PASS
1+3*2.8 9.4 9.399999999 PASS
10/0 输入错误:除零错误 输入错误:除零错误 PASS
1+a 输入错误 输入错误 PASS

UT单元测试

import unittest
from calculator import parse_expression, calculate

class TestCalculator(unittest.TestCase):
    def test_parse_expression(self):
        self.assertEqual(parse_expression("1+2*3"), [1, '+', 2, '*', 3])
        self.assertEqual(parse_expression("10-4/2"), [10, '-', 4, '/', 2])

    def test_calculate(self):
        self.assertEqual(calculate([1, '+', 2, '*', 3]), 7)
        self.assertEqual(calculate([10, '-', 4, '/', 2]), 8.0)
        with self.assertRaises(ValueError):
            calculate([10, '/', 0])

if __name__ == "__main__":
    unittest.main()

pytest

import pytest
from calculator import parse_expression, calculate 
def test_parse_expression():
    assert parse_expression("1+2*3") == [1, '+', 2, '*', 3]
    assert parse_expression("10 - 5 / 2") == [10, '-', 5, '/', 2]
    assert parse_expression("3.5 + 2.5") == [3.5, '+', 2.5]
    assert parse_expression("4*5 - 6 + 7") == [4, '*', 5, '-', 6, '+', 7]
    assert parse_expression("100/25") == [100, '/', 25]

def test_calculate():
    assert calculate([1, '+', 2, '*', 3]) == 7  # 1 + (2 * 3)
    assert calculate([10, '-', 5, '/', 2]) == 7.5  # 10 - (5 / 2)
    assert calculate([3.5, '+', 2.5]) == 6.0  # 3.5 + 2.5
    assert calculate([4, '*', 5, '-', 6, '+', 7]) == 21  # (4 * 5) - 6 + 7
    assert calculate([100, '/', 25]) == 4.0  # 100 / 25

def test_calculate_with_priority():
    assert calculate([1, '+', 2, '*', 3]) == 7  # 1 + (2 * 3)
    assert calculate([2, '*', 3, '+', 4]) == 10  # (2 * 3) + 4
    assert calculate([10, '-', 5, '*', 2]) == 0  # 10 - (5 * 2)

def test_calculate_division_by_zero():
    with pytest.raises(ValueError, match="除零错误"):
        calculate([10, '/', 0])

if __name__ == "__main__":
    pytest.main()


网站公告

今日签到

点亮在社区的每一天
去签到