【问题标题】:How to prevent object creation in __init__() python [duplicate]如何防止在__init__()python中创建对象[重复]
【发布时间】:2018-01-06 12:52:36
【问题描述】:

我正在使用 TDD 练习 python OOP。以下代码正在创建子教室的班级办公室对象,即使给定以数字开头的名称。我该如何预防?谢谢大家帮忙

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):

        #create object if name does not start with a digit
        if not (rname[0].isdigit()):
            super(Office,self).__init__()
            self.name = rname #office name
            self.capacity = 4 #number of spaces per office

这是测试用例:

class OfficeTests(unittest.TestCase):

def setUp(self):
    self.office = Office('BLUE')
    self.office1 = Office('12345')

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):
    print(self.office1, self.office)
    self.assertTrue(self.office1 == None, msg = "Office name can only start with a letter.")

def tearDown(self):
    self.office = None

以及测试用例的结果

....(<room.Office object at 0x7fa84dc96a10>, <room.Office object at 0x7fa84dc968d0>)

F...

【问题讨论】:

  • 抛出异常。
  • 当名称以数字开头时可以引发异常
  • 引发异常是唯一的解决方案吗?
  • @MeshackMbuvi 不,您可以使用__new__ 阻止创建对象。

标签: python oop init


【解决方案1】:

读了很多,已经有了答案。 在对象创建期间,newinit 之前被调用。因此通过覆盖 new 可以控制对象的创建。 就我而言,我只想创建名称以字母开头的房间(办公室)。这就是所做的:

def __new__(cls,rname):

    '''We need this method since creation of an office object is depended on the first character of its name'''
    if not rname[0].isdigit():
        return Room.__new__(cls, rname)

    else:
        return None #don't create object here. __init__() is not called too.

【讨论】:

  • 糟糕的解决方案,exception 是更好的解决方案
  • 但为什么这是一个糟糕的解决方案?
  • @AmphotericLewisAcid 我不会说“坏”,我会说它在 Python 中不好。异常是为处理错误而设计的。
  • @AmphotericLewisAcid 如果它抛出了一个RoomNameStartsWithNumer 异常,它非常明确,并且在__init__ 和创建对象的位置都清楚地显示了代码。 except RoomNameStartsWithNumer as err:if room_obj is None: 要清楚得多。此外,您可以在异常中返回一些消息(例如错误的房间名称)。
  • @AmphotericLewisAcid 实际上在 C++ 中你可以做类似的事情 (new (nothrow)),它返回一个空指针而不是抛出异常。但是 C++ 是关于性能的,返回一个指针在汇编中比倒回堆栈更有性能。恕我直言,这个解决方案非常有用(我非常喜欢它!),但不是 Pythonish。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 2013-06-23
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
相关资源
最近更新 更多