pythongetter-setterinfinite-recursion

Property setter triggers infinite recursion, why?


Using the @property + setter encapsulation, I need a class that raises an exception when someone tries to change the account_number. However, in the __init__ function, I need to set the value. This is the code, it generates recursion.

class SingleBankAccount:
    
    def __init__(self, account_number, account_balance):
        self.account_number = account_number
        self.account_balance = account_balance
        
    @property
    def account_number(self):
        return self.account_number
        
    @account_number.setter
    def account_number(self, number):
    # if there is a number already, raise exception, otherwise set it
        if self.account_number:
            raise AccountException("Someone tried to change the account number!")
        else:
            self.account_number = number

This is the error:

File "main.py", line 17, in account_number

    if self.account_number:

  File "main.py", line 13, in account_number

    return self.account_number

  File "main.py", line 13, in account_number

    return self.account_number

  File "main.py", line 13, in account_number

    return self.account_number

  [Previous line repeated 993 more times]

RecursionError: maximum recursion depth exceeded

Plz help me understand why.


Solution

  • You are setting the self.account_number property within the setter. The proper pythonic way is to use a "private" property:

    class SingleBankAccount:
        
        def __init__(self, account_number, account_balance):
            self.account_number = account_number
            self.account_balance = account_balance
            
        @property
        def account_number(self):
            return self._account_number
            
        @account_number.setter
        def account_number(self, number):
        # if there is a number already, raise exception, otherwise set it
            if hasattr(self, "_account_number"):
                raise AccountException("Someone tried to change the account number!")
            else:
                self._account_number = number
    

    hasattr is to avoid issues with the property not being set.