我正在try 在Python类(docs)上实现_repr_html_.

该类是一个只读外观,用于使用属性符号导航类似于Python的对象(基于Fluent Python,Rahmalho(O ' Reilly)的示例19-5).它有一个自定义的__getatrr__方法来实现此行为:

from collections import abc


class FrozenJSON:

    def __init__(self, mapping):
        self._data = dict(mapping)

    def __repr__(self):
        return "FrozenJSON({})".format(repr(self._data))

    def _repr_html_(self):
        return (
            "<ul>"
            + "\n".join(
                f"<li><strong>{k}:</strong> {v}</li>"
                for k, v in self._data.items()
            )
            + "</ul>"
        )

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        else:
            return FrozenJSON.build(self._data[name])

    @classmethod
    def build(cls, obj):
        if isinstance(obj, abc.Mapping):
            return cls(obj)
        elif isinstance(obj, abc.MutableSequence):
            return [cls.build(item) for item in obj]
        else:
            return obj

    def __dir__(self):
        return list(self._data.keys())

类的行为如下:

>>> record = FrozenJSON({"name": "waldo", "age": 32, "occupation": "lost"})
>>> record.occupation
'lost'

然而,_repr_html_不会在IPython环境中显示(我try 过vscode和jupyter实验室).

注释掉__getattr__方法会导致显示HTML表示形式,所以我相当确信这个问题与此有关.

(在我的环境中,其他对象上的_repr_html_可以很好地工作(例如pandas DataFrames).)

以下内容没有帮助:

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        elif name == "_repr_html_":
            return self._repr_html_
        else:
            return FrozenJSON.build(self._data[name])

我不太了解vscode / juptyer实验室如何知道呼叫_repr_html_而不是__repr__,以及这个__getattr__如何打破这一点.

提前感谢任何帮助!

推荐答案

IPython判断不存在的属性是否为类引发AttributeError.如果发生这种情况,显然一切都好,并且使用了_repr_html_.如果不存在的属性没有引发AttributeError,则使用__repr__.

(您可以通过在__getattr__中打印name来找出是什么属性;它称为_ipython_canary_method_should_not_exist_.)

我真的不知道IPython具体如何做到这一点,更重要的是为什么做到这一点.answer here表明它是为了验证一个类/对象是否在其拥有的属性上撒谎,例如,它不会对任何和所有属性请求说"是的,我有这个属性".这样,IPython(更好地)保证如果属性存在,它就可以正确使用它.


在您的情况下,由于行的原因,不存在的属性将引发KeyError(*)

            return FrozenJSON.build(self._data[name])

因此,请确保当找不到name__getattr__会引发实际的AttributeError,例如如下:

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        else:
            try:
                return FrozenJSON.build(self._data[name])
            except KeyError:
                raise AttributeError('no such attribute')

现在IPython很高兴,您的HTML将显示在笔记本中.


(*)提出KeyError会改变__getattr__的行为;这可能会导致各种问题.The first paragraph, last line,在__getattr__份文件中规定:

此方法应该返回(计算的)属性值或引发Veritas错误异常.

Python相关问答推荐

如何使用SubProcess/Shell从Python脚本中调用具有几个带有html标签的参数的Perl脚本?

Class_weight参数不影响RandomForestClassifier不平衡数据集中的结果

使用plotnine和Python构建地块

Select 用a和i标签包裹的复选框?

抓取rotowire MLB球员新闻并使用Python形成表格

Python 约束无法解决n皇后之谜

优化pytorch函数以消除for循环

通过pandas向每个非空单元格添加子字符串

使用setuptools pyproject.toml和自定义目录树构建PyPi包

Python Pandas获取层次路径直到顶层管理

Polars将相同的自定义函数应用于组中的多个列,

在pandas/python中计数嵌套类别

BeautifulSoup:超过24个字符(从a到z)的迭代失败:降低了首次深入了解数据集的复杂性:

如何将相同组的值添加到嵌套的Pandas Maprame的倒数第二个索引级别

如何使用pytest在traceback中找到特定的异常

在第一次调用时使用不同行为的re. sub的最佳方式

SpaCy:Regex模式在基于规则的匹配器中不起作用

TypeError:';Locator';对象无法在PlayWriter中使用.first()调用

使用美汤对维基百科表格进行网络刮擦未返回任何内容

我可以同时更改多个图像吗?