You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python的__init__()中阻止不符合命名规则的Office对象创建?

解决Office类创建非法名称实例的问题

嘿,我看你在TDD练习Python OOP时遇到了个问题——现在即使传入以数字开头的名称,Office子类还是会创建对象,对吧?咱们来一步步搞定它。

问题根源分析

你当前的Office.__init__方法里,只是在名称以数字开头时跳过了父类初始化和属性赋值,但Python的构造函数__init__默认会返回实例本身,哪怕你没执行那些代码。所以Office('12345')还是会生成一个Office对象,只是它没有name和capacity属性而已,这就是你的测试失败的核心原因。

正确的解决方案:抛出异常

要彻底阻止创建非法实例,正确的做法是在检测到不符合要求的名称时抛出一个异常。这样当用户尝试创建非法Office时,代码会直接报错,而不是生成一个不完整的对象。

修改后的Office类代码

class Room(object):
    """Create general features of a general room
    Each room has a certain capacity depending on its type(an office or a living room)
    """
    def __init__(self):
        super(Room, self).__init__()
        self.capacity = ''

class Office(Room):
    """ Add specific features to make a room an office.
    An office has a name and a space for maximum of 4 people.
    """
    def __init__(self, rname):
        # 检查名称是否以数字开头,是的话抛出异常终止实例创建
        if rname[0].isdigit():
            raise ValueError("Office name cannot start with a digit.")
        # 名称合法时正常初始化
        super(Office,self).__init__()
        self.name = rname # office name
        self.capacity = 4 # number of spaces per office

调整测试用例

原来的测试方式self.assertTrue(self.office1 == None)是错误的,因为非法实例不会是None,而是会触发异常。我们需要用unittest的assertRaises来验证这种异常场景:

import unittest

class OfficeTests(unittest.TestCase):
    def setUp(self):
        self.office = Office('BLUE')
        # 不要在setUp里初始化非法实例,放到对应的测试方法中处理

    def test_office_is_of_class_office(self):
        self.assertTrue(isinstance(self.office, Office), msg = "Should create an object of class Office")

    def test_office_is_of_class_room(self):
        self.assertTrue(isinstance(self.office, Room), msg = "Should create an object of class Office of subclass Room")

    def test_office_capacity_is_4(self):
        self.assertEqual(self.office.capacity, 4, msg= "An office has a maximum of 4 ")

    def test_office_has_a_name(self):
        self.assertEqual(self.office.name,'BLUE', msg = "Should assign name to an office created.")

    def test_office_name_does_not_start_with_a_digit(self):
        # 验证传入数字开头的名称时会抛出预期的ValueError
        with self.assertRaises(ValueError) as context:
            Office('12345')
        # 可选:验证异常提示信息是否符合预期
        self.assertEqual(str(context.exception), "Office name cannot start with a digit.")

    def tearDown(self):
        self.office = None

为什么这样改?

  • 抛出异常是Python中处理非法输入的标准方式,它能明确告知调用者参数不符合要求,避免生成不完整的对象导致后续逻辑出错。
  • 使用assertRaises是unittest框架中测试异常场景的正确做法,能准确验证当输入非法时,代码会触发预期的异常行为。

现在你运行测试的话,所有用例应该都能顺利通过了!

内容的提问来源于stack exchange,提问作者Meshack Mbuvi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:26:08