Search code examples
pythonfunctionreturn-value

Python function returns value while debug, but None while run


I have a function that works correctly when run from a debugger, but returns None otherwise.

class HotelRoom(object):
    def __init__(self, guestlst=[]):
        self.guestlst = guestlst
    def __repr__(self):
        if self.guestlst == []:
            self.guestlst.append("empty")
        return 'HotelRoom(guestlst=%r)' % self.guestlst
    def maybeFill(self, newGuests):
        # return new guestlist on success; return None on failure
        if self.guestlst == ["empty"]:
            self.guestlst = newGuests
            return self.guestlst
        return None

if __name__ == "__main__":
    h = HotelRoom()
    print(h.maybeFill(["Nathan"]))

If I step through with a debugger, this works fine, and it has the expected output of ["Nathan"].

If I just run it, the output is None.

Why does the function's output depend on whether it is being run in a debugger?


Solution

  • This happens because your __repr__ function changes the value it's supposed to be printing. When you're in the debugger, the act of the debugger trying to display the representation of the value to you changes that value, by changing [] to ['empty'].

    Because the maybeFill function compares the list to ['empty'], it returns false when the actual value is [], which it always will be if repr() was never called.

    A less-surprising __repr__ will only display the value, but never change it. Consider, then, leaving the empty value as [] instead of ever transforming it to ['empty']:

    class HotelRoom(object):
        def __init__(self, guestlst=[]):
            self.guestlst = guestlst
        def __str__(self):
            if self.guestlst:
                return 'Hotel room, with guests: %s' % ', '.join(self.guestlst)
            return 'Empty hotel room'
        def __repr__(self):
            return 'HotelRoom(guestlst=%r)' % self.guestlst
        def maybeFill(self, newGuests):
            # return new guestlist on success; return None on failure
            if self.guestlst == []:
                self.guestlst = newGuests
                return self.guestlst
            return None
    
    if __name__ == "__main__":
        h = HotelRoom()
        if h.maybeFill(["Nathan", "John"]) == None:
            print("If you see this, the problem is not solved")
        print(h)
    

    As you can see in the online interpreter at https://ideone.com/drlN6w, the above works even when no debugger is causing __repr__ or __str__ to be called early.