[Python] Why am I getting this RecursionError?

Discussão em 'Python' iniciado por Stack, Agosto 4, 2025.

  1. Stack

    Stack Membro Participativo

    I'm working on making a program to read a chart of accounts and turn it into a tree of Account objects, which I will be doing stuff with later. The chart of accounts in question has several levels of sub-accounts, with the name of each account being indented three spaces more than its parent account. For example:

    Current Assets
    Cash
    1000000.00 - Cash
    1000010.00 - Bank Account #1
    ...
    Other Current Assets
    Receivables
    100800.00 - Accounts Receivable
    ...


    I've created a class to represent an account, as follows:

    class Account:
    parent = None
    num: int | None
    name: str # Name after stripping whitespace and splitting off account number
    raw: str # Name prior to ^
    ... # Assorted irrelevant class variables
    acct_type: str | None
    detail_type: str | None
    _header: bool = False # Flags whether an account's a header account
    descendants: list = list() # Holds account's children. Should be empty if _header == False.

    def __init__(self, instr: str, parent=None, acct_type: str = None, detail_type: str = None):
    ''' Initialize an Account.

    - parent: Account. `None` if top-level.
    - instr: raw string from ACS CoA.
    - acct_type: QBO Account Type
    - detail_type: QBO Detail Type
    '''
    self.raw = instr
    self.parent = parent
    self.acct_type = acct_type
    self.detail_type = detail_type
    stripped = instr.strip()
    ... # Assorted initialization code, incl. manipulating stripped
    # to get values for self.num and self.name
    ... # Assorted irrelevant methods
    def is_header(self) -> bool:
    return self._header
    def depth(self) -> int:
    return (len(self.raw) - len(self.raw.strip())) / 3 # self.raw
    def add_descendant(self, instr, acct_t: str = None, detail: str = None):
    '''Add descendant to account.

    If `acct_type` and `detail_type` are supplied, will override parent account type.
    '''
    if len(self.descendants) > 0:
    if calc_depth(instr) > self.descendants[-1].depth():
    self.descendants[-1].add_descendant(instr, acct_t = acct_t, detail = detail)
    else:
    self.descendants.append(Account(
    instr,
    parent=self,
    acct_type = self.acct_type if acct_t is None else acct_t,
    detail_type = self.detail_type if detail is None else detail
    ))
    else:
    self.descendants.append(Account(
    instr,
    parent=self,
    acct_type = self.acct_type if acct_t is None else acct_t,
    detail_type = self.detail_type if detail is None else detail
    ))
    return

    if __name__ == "__main__":
    accounts: list[Account] = list()
    for (acs_name, account_type, detail_type) in get_data(): # Gets data as list[tuple[str, str, str]]
    d = len(acs_name) - len(acs_name.lstrip())) / 3 # Depth of current row's account
    if d == 0: # Overall header
    accounts.append(Account(acs_name, parent=None, acct_type=account_type, detail_type=detail_type))
    else:
    if account_type is not None:
    # Account metadata supplied in CoA spreadsheet
    accounts[-1].add_descendant(
    acs_name,
    acct_t = account_type,
    detail = detail_type)
    else:
    # Impute account metadata from parent
    accounts[-1].add_descendant(acs_name)



    However, when I run this, I get a rather nasty RecursionError:

    Exception has occurred: RecursionError
    maximum recursion depth exceeded
    KeyError: 'C:\\Users\\...\\Account.py'

    During handling of the above exception, another exception occurred:

    KeyError: 'C:\\Users\\...\\Account.py'

    During handling of the above exception, another exception occurred:

    KeyError: 'C:\\Users\\...\\Account.py'

    During handling of the above exception, another exception occurred:

    KeyError: 'C:\\Users\\...\\Account.py'

    During handling of the above exception, another exception occurred:

    File "C:\Users\...\Account.py", line 104, in add_descendant
    self.descendants[-1].add_descendant(instr, acct_t = acct_t, detail = detail)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\...\Account.py", line 104, in add_descendant
    self.descendants[-1].add_descendant(instr, acct_t = acct_t, detail = detail)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\...\Account.py", line 104, in add_descendant
    self.descendants[-1].add_descendant(instr, acct_t = acct_t, detail = detail)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    [Previous line repeated 980 more times]
    File "C:\Users\...\Account.py", line 155, in <module>
    acs_name,
    ^^^^^^^^^
    ...<3 lines>...
    detail=detail_type

    RecursionError: maximum recursion depth exceeded


    I've spent the last 1.5 hours trying to fix this, but to no avail. Looking in my debugger, it appears that while the first two levels get added properly, that second level makes itself its own descendant ad infinitum. For example, in my most recent debugging run the tree looks like this:

    <__main__.Account object at 0x0000015631511BE0> # Current Assets
    <__main__.Account object at 0x0000015631796710> # Cash
    <__main__.Account object at 0x0000015631796710> # Cash
    <__main__.Account object at 0x0000015631796710> # Yet more Cash
    ... # 980-ish more Cash


    For reference, it should actually look like this:

    <__main__.Account object at 0x0000015631511BE0> # Current Assets
    <__main__.Account object at 0x0000015631796710> # Cash
    <__main__.Account object at 0x0000015631XXXXXX> # 1000000.00 - Cash


    What am I doing wrong? As far as I can tell, there isn't anywhere where I am adding self to self.descendants.

    (As a final note, this isn't my full code; irrelevant bits have been omitted or simplified.)

    Continue reading...

Compartilhe esta Página