Recursion error with class inheritance

2019-09-17 04:26发布

问题:

I have a file containing classes which I want to use to store API endpoints. The reason I want to use classes, is so that I can access the endpoints by typing api.level2.resources.

Here is what the file looks like, with API as the main class and SubEntries the 'child':

class API(object):
    """
    A class for logging to stdout and/or a file. Supports color output for different log kinds.
    """

    def __init__(self):
        """
        :param log_to_file: Bool - Whether to log to a file or only to stdout (False)
        :param s: String - Log file name without extension for success logs
        :param e: String - Log file name without extension for error logs
        :param prefix: Bool - Whether to show the prefix or not
        :param timestamp: Bool - Whether to show the timestamp or not
        :param debug: Bool - Whether to show debug messages or not
        """
        self.login = '/login'
        self.logout = '/logout'
        self.sysRequest = '/sysReq'
        self.level2 = SubEntries()


class SubEntries(API):

    def __init__(self):
        super().__init__()
        self.host_info = '/info'
        self.resources = '/resources'

But, when I try and use it like this:

from src import API

api = API()
print(api.level2.resources)

I get the following error:

Traceback (most recent call last):
  File "D:/_projects/pynap/new.py", line 4, in <module>
    api = API()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
  ...
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
  File "D:\_projects\pynap\src\QAPI.py", line 24, in __init__
    super().__init__()
  File "D:\_projects\pynap\src\QAPI.py", line 18, in __init__
    self.level2 = SubEntries()
RecursionError: maximum recursion depth exceeded while calling a Python object

I am pretty sure the solution is simple, I am just not sure how to structure the class to be able to use it like I want.

回答1:

As I've said in my comment, you're quite explicitly creating a circular reference here so at one point it hits Python's recursion limit. There are a lot of ways to avoid recursion of similar-typed objects. The simplest is to have a common parent, for example:

class BaseAPI(object):
    # place here whatever you want common for all API/SubEntry objects
    pass

class API(BaseAPI):

    def __init__(self):
        self.login = '/login'
        self.logout = '/logout'
        self.sysRequest = '/sysReq'
        self.level2 = SubEntries()

class SubEntries(BaseAPI):

    def __init__(self):
        super(BaseAPI, self).__init__()
        self.host_info = '/info'
        self.resources = '/resources'

You can also override __getattr__()/__setattr__()/__delattr__() methods in your BaseAPI class and then have every property access dynamically evaluated. You can also pass an 'endpoints' dict to your BaseAPI class and have it update its self.__dict__ to get endpoints from a passed dict...

Your question lacks specificity to suggest what would be the best approach.