如何在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
相关产品推荐
相关产品推荐

