Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Partially setting the honor_existing option #102

Open
ChenMoFeiJin opened this issue Dec 29, 2023 · 4 comments
Open

Feature: Partially setting the honor_existing option #102

ChenMoFeiJin opened this issue Dec 29, 2023 · 4 comments

Comments

@ChenMoFeiJin
Copy link

ChenMoFeiJin commented Dec 29, 2023

我不确定这是不是个普遍的场景,还是算作特殊的需求。如下面的代码所示,我想用 objprint 来打印 Struct 类型的变量。但是因为 dataclass 已经有了 __str__ 的实现,我只能把 honor_existing 参数设为 False。可是这样 pathlib.Path 中 parent 属性会让 objprint 在输出时陷入无限递归,直到 depth。然而实际上我不需要对 pathlib.Path 的 honor_existing 设为 False。

from dataclasses import dataclass
from pathlib import Path

from objprint import objprint


@dataclass
class Struct:
    path: Path = Path("~")


if __name__ == "__main__":
    objprint(Struct(), honor_existing=False, depth=5)

image


我当前是通过加上自定义的 Formatter 实现上面的需求

from dataclasses import dataclass
from pathlib import Path

from objprint import objprint


@dataclass
class Struct:
    path: Path = Path("~")


if __name__ == "__main__":
    objprint.register_formatter(Path, str)
    objprint(Struct(), honor_existing=False, depth=5)
    objprint.unregister_formatter(Path)

image

@gaogaotiantian
Copy link
Owner

这里是无限递归么?看起来每个path都有一个不同的parent啊。有若干种方式解决这个问题,formatter是个挺clean的方案,把parent给exclude掉也可以。你设想的使用方式是什么呢?在op这个函数下的honor_exist必然是对所有object生效的,如果你想config它就需要一个基本同样复杂的filter。还有一个方案是直接在Struct上add_objprint,应该会覆盖它的str

@ChenMoFeiJin
Copy link
Author

ChenMoFeiJin commented Dec 30, 2023

使用 formatter 确实已经很简便了,但是这是一个全局的配置,如果其它地方有另外的设置的话可能会打架,而 honor_exist 是一次性的,没有什么副作用;exclude 的问题是如果刚好有另一个也叫 parent 的字段的话就没法操作了;add_objprint 的话,因为只是使用 objprint 来作为 debug 的工具,并不能将 objprint 嵌入项目代码中,而且对于众多的 dataclass 这样也不是很方便。

我的想法是,对于大部分情况来说,在同一次打印中,对于相同的类型,使用的打印策略应该是相同的,所以我想到的方案 1 和 2,如果要极致的自定义的话可能可以使用方案 3:

  1. 将 honor_existing 的类型修改为 Union[bool, Set[type]],当为 bool 是按原来的策略处理,为 Set[type] 时判断是否在集合中,如果在则按 True 处理,不在则按 False 处理;
  2. 将 honor_existing 的类型修改为 Union[bool, Callable[[type], bool]],当为 bool 时则自动转换为 lambda _: honor_existing, 在判断时则将对应类型传入 honor_existing;
  3. 将 honor_existing 的类型修改为 Union[bool, Dict[str, Union[bool, Recursion...]],该设置与对象同步递归,如果不存在则默认为 True。

@gaogaotiantian
Copy link
Owner

这几个方案都不理想,Union[bool, Set]这种东西就不太应该存在,尤其考虑到config其实是**kwargs,没有提示的。我觉得在argument里应该尽可能避免这种情况。一个可能的方案是增加一个formatter参数,作为一个一次性的formatter,这样和register_formatter可以保持一致。

@happytree718
Copy link
Contributor

如果是一次性的formatter的话,可不可以在objprint() 里加一个argument,类似于这种:
objprint(Struct(), honor_existing=False, depth=5, one_time_formatter=str)
这样会不会更简洁,实现起来也更简单。
因为如果只是一次性的话,在额外加一个register_formatter(Path, str, one_time=true) 这类的call使用起来感觉会更复杂,而如果要在同一个scope里反复使用的话,register_formatter()unregister_formatter() 应该已经够用了?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants