如何覆盖 python 中的 getattr 或 getattribute 以在惰性递归目录列表中调用其内部的 getattr 或 getattribute

How to override getattr or getattribute in python to call gettattr or getattribute inside itself as in lazy recursive directory listing

例如这样的事情:

class DotTabLoader():
    def __init__(self, basedir, loaderfun):
        self._basedir = pathlib.PosixPath(basedir)
        self._loaderfun = loaderfun
        self._list = list(self._basedir.glob('*/'))
        self._names = [x.name.split('=')[1] for x in self._list]
        self._names_dict = dict(zip(self._names, range(self._names)))
    def __dir__(self):
        return self._names
    def __getattribute__(self, name):
        # how to access self._list etc here?
        return super().__getattribute__(name)
    

无限递归会出错。

更新:

正确的方法是这样的:

class DotTabLoader():
    def __init__(self, basedir, loaderfun):
        self._basedir = pathlib.PosixPath(basedir)
        self._loaderfun = loaderfun
        self._list = list(self._basedir.glob('*/'))
        self._names = [x.name.split('=')[1] for x in self._list]
        self._names_dict = dict(zip(self._names, range(len(self._names))))
    def __dir__(self):
        return self._names + super().__dir__()
    def __getattr__(self, name):
        try:
            ind = self._names_dict[name]
            basedir = self._list[ind]
            return DotTabLoader(basedir, self._loaderfun)
        except KeyError as e:
            return super().__getattribute__(name)

最简单的方法是实现__getattr__,只有在正常查找失败时才调用它。这意味着您可以在 __getattr__ 实现中访问普通属性,而无需执行任何特殊操作,并且不会递归调用它,因为基础 class 查找成功。

    def __getattr__(self, name):
        return self._list[0]  # works fine!

__getattribute__ 更像是一种特殊情况,因为它是无条件调用的,而不是作为正常查找的回退。根据文档 (https://docs.python.org/3/reference/datamodel.html#object.getattribute) 如果你想访问 __getattribute__ 中的属性而不调用你自己覆盖的 __getattribute__ 实现,你需要调用 object 实现:

    def __getattribute__(self, name):
        return object.__getattribute__(self, '_list')[0]