构造方法中调用__setattr__或__getattr__ 方法造成的最大递归深度问题

Posted liuyinzhou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造方法中调用__setattr__或__getattr__ 方法造成的最大递归深度问题相关的知识,希望对你有一定的参考价值。

问题抛出

 1 class Local(object):
 2     """
 3         实现的功能:
 4             不同的线程使用同一个变量,没有使用thread_local,但却做到了变量之间数据的独立性
 5     """
 6     def __init__(self):
 7         # 维护着创建的每个线程id和及其value
 8         self.storage = {}
 9         self.get_ident = get_ident
10 
11     def __setattr__(self, key, value):
12         # 设置一次值就会获取当前线程id
13         ident = self.get_ident()
14         origin = self.storage.get(ident)
15         if not origin:
16             origin = {key:value}
17         origin[key] = value
18         self.storage[ident] = origin
19 
20     def __getattr__(self, item):
21         # 获取当前线程id
22         ident = self.get_ident()
23         origin = self.storage.get(ident)
24         if not origin:
25             return None
26         return origin.get(item)
27 
28 
29 local_values = Local()
 1 "D:Program FilesPython36python.exe" D:/Demo/s8/flaskdemo/threading_local.py
 2 Traceback (most recent call last):
 3   File "D:/Demo/s8/flaskdemo/threading_local.py", line 162, in <module>
 4     local_values = Local()
 5   File "D:/Demo/s8/flaskdemo/threading_local.py", line 141, in __init__
 6     self.storage = {}
 7   File "D:/Demo/s8/flaskdemo/threading_local.py", line 146, in __setattr__
 8     ident = self.get_ident()
 9   File "D:/Demo/s8/flaskdemo/threading_local.py", line 155, in __getattr__
10     ident = self.get_ident()
11   File "D:/Demo/s8/flaskdemo/threading_local.py", line 155, in __getattr__
12     ident = self.get_ident()
13   File "D:/Demo/s8/flaskdemo/threading_local.py", line 155, in __getattr__
14     ident = self.get_ident()
15   [Previous line repeated 326 more times]
16 RecursionError: maximum recursion depth exceeded
17 
18 Process finished with exit code 1

原因分析

  技术分享图片

类似的超过递归深度的示例还有:

技术分享图片

 

 解决方案

 1 class Local(object):
 2     """
 3         实现的功能:
 4             不同的线程使用同一个变量,没有使用thread_local,但却做到了变量之间数据的独立性
 5     """
 6     def __init__(self):
 7         # 维护着创建的每个线程id和及其value
 8         # self.storage = {}
 9         # self.get_ident = get_ident
10         object.__setattr__(self, storage, {})
11         object.__setattr__(self, ident_func, get_ident)
12 
13     def __setattr__(self, key, value):
14         # 设置一次值就会获取当前线程id
15         ident = self.get_ident()
16         origin = self.storage.get(ident)
17         if not origin:
18             origin = {key:value}
19         origin[key] = value
20         self.storage[ident] = origin
21 
22     def __getattr__(self, item):
23         # 获取当前线程id
24         ident = self.get_ident()
25         origin = self.storage.get(ident)
26         if not origin:
27             return None
28         return origin.get(item)
29 
30 
31 local_values = Local()

实现的原理:

  在构造方法中不调用自身实例的__setattr__或者__getattr__,而调用object类的这两个方法即可避免最大递归深度的问题。

以上是关于构造方法中调用__setattr__或__getattr__ 方法造成的最大递归深度问题的主要内容,如果未能解决你的问题,请参考以下文章

python自定义属性访问__setattr__, __getattr__, __setattribute__

Python魔法方法(13):__setattr __(self, key, value) 方法

Python魔法方法(13):__setattr __(self, key, value) 方法

Python魔法方法(13):__setattr __(self, key, value) 方法

python 自定义属性访问 __setattr__, __getattr__,__getattribute__, __call__

python常用魔术方法概览