1

我在 PyCharm 中调试时遇到问题(也许这个问题在其他 IDE 中也可以观察到):

如果您采用以下代码:

class Test1:
    def __init__(self):
        self.arg1 = 'abc'
        self.arg2 = 'def'
        self.some_other_class = SomeOtherClass()
        return

    def __getattr__(self, item):
        print(item)
        if callable(getattr(self.some_other_class, 'blabla')):
            abc = 123
        return

x = Test1()

我的断点在self.arg1 = 'abc',会发生以下情况:

只有在调试模式下才会查找__len__未找到的实例变量 --> 然后__getattr__ 调用。(我看到这是因为print(item)-Statement 中的__getattr__)。然后self.some_other_class是抬头。这没有找到:递归地深入__getattr__等等,直到 RecursionError 发生。

因为我需要调试,我能对这种行为做些什么吗?

4

1 回答 1

0

简短的回答:

要么定义一个__len__方法,要么检查是否'some_other_class'存在于self.__dict__.keys().


长答案:

递归发生在

  1. 你试图从一个类中获取一个不存在的属性并且
  2. __getattr__在那个类中有一个方法,并且
  3. __getattr__您尝试从同一类中获取不存在的属性的方法中

递归错误例如可以在以下示例中获得,其中self.some_other_class未定义:

class Test1:
    def __init__(self):
        self.arg1 = 'abc'
        self.arg2 = 'def'
        return

    def __getattr__(self, item):
        print(item)
        self.some_other_class
        return

x = Test1()
x.test

当 x.test 被调用时,__getattr__方法被调用,它调用self.some_other_class,它再次调用__getattr__方法,它再次调用self.some_other_class,等等。

当然在你的情况下self.some_other_class定义,然后没有递归:

class SomeOtherClass:
    def __init__(self):
        pass

class Test1:
    def __init__(self):
        self.arg1 = 'abc'
        self.arg2 = 'def'
        self.some_other_class = SomeOtherClass
        return

    def __getattr__(self, item):
        print(item)
        self.some_other_class
        return

x = Test1()
x.test

但是,在 PyCharm 的调试模式下,可能会__len__在手动运行文件中的一行后调用类的属性。在示例中,这意味着在Test1.__init__方法中的前两行之后self.some_other_class还没有定义,也Test1.__len__没有定义。因此调用该__len__属性将导致递归错误。

有两种可能的解决方案:

  1. 定义__len__方法:

    class Test1:
        ...
        def __len__(self):
            return 1
    
  2. 检查__getattr__传递的项目是否存在于类中:

    class Test1:
        ...
        def __getattr__(self, item):
            print(item)
            if 'some_other_class' in self.__dict__:
                if hasattr(self.some_other_class, 'blabla')):
                    abc = 123
                return
    

    请注意,仅调用getattr(self.some_other_class, 'blabla')hasattr(self.some_other_class, 'blabla')不进行签入self.__dict__也会触发该__getattr__方法。

于 2021-03-05T22:31:05.953 回答