__repr__ 和 __str__ 在动态 class 构造中不起作用
__repr__ and __str__ not working in dynamic class construction
我正在 Python 控制台中构建一个交互式文件资源管理器,这样当我传入一个路径时,我得到一个对象,然后用一个点 .
开始自动完成建议路径的内容,然后我再次执行此操作以获取子文件夹的内容,依此类推,直到我找到文件并且它 returns 路径。
我已经实现了我的目标,除了这个小烦人的事情:我想要 __repr__
方法,但它从来没有奏效。
这是我的代码:
import os
from glob import glob
path = r'C:\Users\eng_a\Downloads'
def browse(path):
my_dict = {'_path': path}
tmp = os.listdir(path)
key_contents = []
for akey in tmp:
key_contents.append(akey.replace(".", "_").replace(" ", "_").replace("-", "_"))
val_paths = glob(path + '//*')
for akey, avalue in zip(key_contents, val_paths):
if os.path.isfile(avalue):
my_dict[akey] = avalue
else:
my_dict[akey] = browse(avalue)
def func(self):
return self._path
my_dict["__repr__"] = func
my_dict["__str__"] = func
obj = type(os.path.basename(path), (), dict(zip(my_dict.keys(), my_dict.values())))
return obj
>>> b = browse(path)
>>> b
不幸的是,它一直在打印 __main__
。
如评论中所述,obj
是 class,不是实例。它包含一个函数 __repr__
,该函数将在您创建实例后立即绑定到该实例。
一个简单而优雅的解决方案是将函数 browse
替换为同名的 class。调用 class 会创建一个实例(除非你真的搞砸了 metaclasses 或 __new__
),所以你现在拥有的接口不必更改。然而,在内部,您将为您深入研究的每个目录实例化您的 class。
这将允许您做的另一件事是拥有一个真正动态的解决方案。现在你实际上递归到你的根的所有 children 。这在时间和内存方面都非常昂贵。理想情况下,您只想列出当前目录,并仅在被要求时递归到 children。
from os import listdir
from os.path import isdir, join
import re
class browse:
def __init__(self, path, directory=True):
# Create an attribute in __dict__ for each child
self.__path__ = path
if directory:
for file in listdir(path):
full = join(path, file)
key = re.sub(r'^(?=\d)|\W', '_', file)
setattr(self, key, full if isdir(full) else browse(full, False))
def __getattribute__(self, name):
if name == '__path__':
return super().__getattribute__(name)
d = super().__getattribute__('__dict__')
if name in d:
child = d[name]
if isinstance(child, str):
child = browse(child)
setattr(self, name, child)
return child
return super().__getattribute__(name)
def __repr__(self):
return self.__path__
def __str__(self):
return self.__path__
此解决方案确实为根路径中的每个条目添加了一个属性。文件记录为 browse
objects,而目录记录为字符串。覆盖 __getattribute__
允许您即时交换完整 browse
objects 的字符串,而不必预先展开所有文件夹。
考虑到预期的用例,可能的改进是删除行 setattr(self, name, child)
。这样,您就不会保留对您不小心浏览到的目录的不必要引用,例如。
我正在 Python 控制台中构建一个交互式文件资源管理器,这样当我传入一个路径时,我得到一个对象,然后用一个点 .
开始自动完成建议路径的内容,然后我再次执行此操作以获取子文件夹的内容,依此类推,直到我找到文件并且它 returns 路径。
我已经实现了我的目标,除了这个小烦人的事情:我想要 __repr__
方法,但它从来没有奏效。
这是我的代码:
import os
from glob import glob
path = r'C:\Users\eng_a\Downloads'
def browse(path):
my_dict = {'_path': path}
tmp = os.listdir(path)
key_contents = []
for akey in tmp:
key_contents.append(akey.replace(".", "_").replace(" ", "_").replace("-", "_"))
val_paths = glob(path + '//*')
for akey, avalue in zip(key_contents, val_paths):
if os.path.isfile(avalue):
my_dict[akey] = avalue
else:
my_dict[akey] = browse(avalue)
def func(self):
return self._path
my_dict["__repr__"] = func
my_dict["__str__"] = func
obj = type(os.path.basename(path), (), dict(zip(my_dict.keys(), my_dict.values())))
return obj
>>> b = browse(path)
>>> b
不幸的是,它一直在打印 __main__
。
如评论中所述,obj
是 class,不是实例。它包含一个函数 __repr__
,该函数将在您创建实例后立即绑定到该实例。
一个简单而优雅的解决方案是将函数 browse
替换为同名的 class。调用 class 会创建一个实例(除非你真的搞砸了 metaclasses 或 __new__
),所以你现在拥有的接口不必更改。然而,在内部,您将为您深入研究的每个目录实例化您的 class。
这将允许您做的另一件事是拥有一个真正动态的解决方案。现在你实际上递归到你的根的所有 children 。这在时间和内存方面都非常昂贵。理想情况下,您只想列出当前目录,并仅在被要求时递归到 children。
from os import listdir
from os.path import isdir, join
import re
class browse:
def __init__(self, path, directory=True):
# Create an attribute in __dict__ for each child
self.__path__ = path
if directory:
for file in listdir(path):
full = join(path, file)
key = re.sub(r'^(?=\d)|\W', '_', file)
setattr(self, key, full if isdir(full) else browse(full, False))
def __getattribute__(self, name):
if name == '__path__':
return super().__getattribute__(name)
d = super().__getattribute__('__dict__')
if name in d:
child = d[name]
if isinstance(child, str):
child = browse(child)
setattr(self, name, child)
return child
return super().__getattribute__(name)
def __repr__(self):
return self.__path__
def __str__(self):
return self.__path__
此解决方案确实为根路径中的每个条目添加了一个属性。文件记录为 browse
objects,而目录记录为字符串。覆盖 __getattribute__
允许您即时交换完整 browse
objects 的字符串,而不必预先展开所有文件夹。
考虑到预期的用例,可能的改进是删除行 setattr(self, name, child)
。这样,您就不会保留对您不小心浏览到的目录的不必要引用,例如。