使用 __getattr__ 和 __slots__ 进行组合时避免 Pycharm __dict__ 查找

Avoid Pycharm __dict__ lookup when using __getattr__ and __slots__ for composition

假设我有一个 class:

class Example:
    __slots__ = ("_attrs", "other_value")
    
    def __init__(self):
       self._attrs = OrderedDict()
       self.other_value = 1
       self.attribute = 0
    
    def __setattr__(self, key, value):
       if key in self.__slots__:
            return super().__setattr__(key, value)
       else:
           self._attrs[key] = value
     
    def __getattr__(self, key):
         return self._attrs[key]

目标是让示例有两个插槽:

要获取属性,代码应该:

对于这个问题,我希望错误能够模拟如果对象的属性不存在时通常会发生的情况。当前,当 运行 代码时,我在 self._attrs 上收到一个关键错误。虽然这很好,但最好将这种细微差别隐藏起来。更烦人的是,如果我在 Pycharm 中调试,自动完成会在我按下回车之前尝试查看 dict 时抛出一个大错误:

Example().abc # hit tab in pycharm

# returns the error:
Traceback (most recent call last):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 1464, in do_it
    def do_it(self, dbg):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 159, in generate_completions_as_xml
    def generate_completions_as_xml(frame, act_tok):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 77, in complete
    def complete(self, text):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_completer.py", line 119, in attr_matches
    def attr_matches(self, text):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py", line 165, in generate_imports_tip_for_module
    def generate_imports_tip_for_module(obj_to_complete, dir_comps=None, getattr=getattr, filter=lambda name:True):
  File "/Users/xxxxxxxxx/", line 46, in __getattr__
    def __getattr__(self, key: str) -> None:
KeyError: '__dict__'

有没有办法通过编写不同的代码来抑制这种情况?

您可以通过实施 __dir__ on the class, so it has a canonical source of names that can be completed:

来使其工作
def __dir__(self):
    return 'other_value', *self._attrs.keys()

我不能保证 PyCharm 如何实现他们的 tab-completion,所以不能保证它有效,但这是为一个类型定义一组可枚举属性的方法,希望PyCharm 将在可用时使用它,而不是去 __dict__.

另一种方法(无论如何这可能是个好主意)确保在 __getattr__ 失败时引发正确的错误,因此 PyCharm 知道问题是缺少属性,而不是某些属性与 dict 无关的问题:

def __getattr__(self, key):
    try:
        return self._attrs[key]
    except KeyError:
        raise AttributeError(key)