'How to create a static instance of a class when it would lead to an exception in the constructor?

I have the following code:

class Position:
    def __int__(self, x: int, y: int):
        if out_of_range(x, 0, MAX_INT - 1):
            raise ValueError("[error][{}.{}()] Failed to create position: {}\n".format(__class__,
                                                                                       inspect.stack()[0].function,
                                                                                       "x must be in range [0, MAX_INT)"
                                                                                       ))
        if out_of_range(y, 0, MAX_INT - 1):
            raise ValueError("[error][{}.{}()] Failed to create position: {}\n".format(__class__,
                                                                                       inspect.stack()[0].function,
                                                                                       "y must be in range [0, MAX_INT)"
                                                                                       ))
        self.__x: int = x
        self.__y: int = y

And I want to create a static instance of Position, with x and y both equal to MAX_INT.
How can I write the code in order to be able to do this:

if Position(2, 3) == Position.INVALID:  # INVALID <=> Position(MAX_INT, MAX_INT)
    ...

EDIT:

I have another method in the Position class:

    def to(self, direction: Direction, steps: int = 1) -> 'Position':
        """
        Creates a new position, to the given direction.
        If one of the new coordinates goes below 0, then Position.INVALID is returned.
        A negative 'steps' value inverses the direction. Ex: Position.to(RIGHT, 3) == Position.to(LEFT, -3)
        """
        delta_x, delta_y = DIRECTION_DELTA[direction]
        try:
            return Position(self.__x + delta_x * steps, self.__y + delta_y * steps)
        except ValueError:
            return Position.INVALID

More specifically, my intendend usage would be

if Position(2, 3).to(LEFT, 3) == Position.INVALID:
    do something
else:
    do something else

A 1st aproach would be to add another method which checks if a position is valid.

    def to(self, direction: Direction, steps: int = 1) -> 'Position':
        """
        Creates a new position, to the given direction.
        If one of the new coordinates goes below 0, then Position.INVALID is returned.
        A negative 'steps' value inverses the direction. Ex: Position.to(RIGHT, 3) == Position.to(LEFT, -3)
        """
        delta_x, delta_y = DIRECTION_DELTA[direction]
        try:
            return Position(self.__x + delta_x * steps, self.__y + delta_y * steps)
        except ValueError:
            position: Position = Position(0, 0)
            position.__x = MAX_INT
            position.__y = MAX_INT
            return position
   
    def is_valid() -> bool:
        return not self.__x == self.__y == MAX_INT

But now, Position(MAX_INT, MAX_INT) is no longer a singleton.

A 2nd approach would be to let the method to() throw the error from the constructor and catch it outside of Position.to().



Solution 1:[1]

Not really sure if this is what you need but using the decorator @classmethod and defining __eq__ you can create an instance with x=MAX_INT and compare it with your instance:

class Position:
    def __init__(self, x: int):
        if x > MAX_INT:
            raise ValueError
        self.__x: int = x

    def __eq__(self, other):
        if self.__x == other.__x:
            return True
        return False

    @classmethod
    def INVALID(cls):
        p = Position(0)
        p.__x = MAX_INT
        return p

    def to(self, direction: Direction, steps: int = 1) -> 'Position': 
        delta_x, delta_y = DIRECTION_DELTA[direction]
        try:
            return Position(self.__x + delta_x * steps, self.__y + delta_y * steps)
        except ValueError:
            return Position.INVALID()

if Position(MAX_INT-1) == Position.INVALID():
    print('invalid')
else:
    print('valid')

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1