在 set 的子类上调用 super().__repr__() 时出现意外行为?
Unexpected behavior when calling super().__repr__() on a subclass of set?
请参阅下面的编辑以了解此行为的解释(在 CPython 中)
在 Python 3.9.5 中,我创建了两种自定义集合类型,一种继承自 list
,另一种继承自 set
。我希望他们有自定义 __repr__
方法。简单示例:
class MyList(list):
def __repr__(self) -> str:
return f'MyList({super().__repr__()})'
class MySet(set):
def __repr__(self) -> str:
return f'MySet({super().__repr__()})'
请注意 __repr__()
定义除了初始字符串前缀外是相同的。但是当我打印它们时,我得到了不同的结果:
ml = MyList('abc')
print(ml) # MyList(['a', 'b', 'c'])
ms = MySet('abc')
print(ms) # MySet(MySet({'c', 'a', 'b'}))
MyList
的显示是我所期望的。但是由于某种原因 MySet
被打印了两次,就好像 __repr__
被递归调用一样。有谁知道发生了什么,或者如何最好地让它显示 MySet({'c', 'a', 'b'})
,而不是 MySet(MySet({'c', 'a', 'b'}))
?
[编辑]
从 3.9.5 开始,在 https://github.com/python/cpython/blob/main/Objects/setobject.c 函数 set_repr
中有代码:
if (!PySet_CheckExact(so))
result = PyUnicode_FromFormat("%s({%U})",
Py_TYPE(so)->tp_name,
listrepr);
else
result = PyUnicode_FromFormat("{%U}", listrepr);
换句话说,set
是硬编码的,如果类型恰好是 set
且集合非空,则其 __repr__
会省略 class 名称, 但以其他方式显示 class 名称。但是 dict
和 list
出于某种原因不这样做。
这是set
的默认打印,它打印class名字。如果您删除您添加的 format
,它就会完全按照您的意愿出现。
class MySet(set):
def __repr__(self) -> str:
return super().__repr__()
if __name__ == '__main__':
ms = MySet('abc')
print(ms)
MySet.__name__ = 'New_name'
print(ms)
输出:
MySet({'b', 'c', 'a'})
New_name({'b', 'c', 'a'})
请参阅下面的编辑以了解此行为的解释(在 CPython 中)
在 Python 3.9.5 中,我创建了两种自定义集合类型,一种继承自 list
,另一种继承自 set
。我希望他们有自定义 __repr__
方法。简单示例:
class MyList(list):
def __repr__(self) -> str:
return f'MyList({super().__repr__()})'
class MySet(set):
def __repr__(self) -> str:
return f'MySet({super().__repr__()})'
请注意 __repr__()
定义除了初始字符串前缀外是相同的。但是当我打印它们时,我得到了不同的结果:
ml = MyList('abc')
print(ml) # MyList(['a', 'b', 'c'])
ms = MySet('abc')
print(ms) # MySet(MySet({'c', 'a', 'b'}))
MyList
的显示是我所期望的。但是由于某种原因 MySet
被打印了两次,就好像 __repr__
被递归调用一样。有谁知道发生了什么,或者如何最好地让它显示 MySet({'c', 'a', 'b'})
,而不是 MySet(MySet({'c', 'a', 'b'}))
?
[编辑]
从 3.9.5 开始,在 https://github.com/python/cpython/blob/main/Objects/setobject.c 函数 set_repr
中有代码:
if (!PySet_CheckExact(so))
result = PyUnicode_FromFormat("%s({%U})",
Py_TYPE(so)->tp_name,
listrepr);
else
result = PyUnicode_FromFormat("{%U}", listrepr);
换句话说,set
是硬编码的,如果类型恰好是 set
且集合非空,则其 __repr__
会省略 class 名称, 但以其他方式显示 class 名称。但是 dict
和 list
出于某种原因不这样做。
这是set
的默认打印,它打印class名字。如果您删除您添加的 format
,它就会完全按照您的意愿出现。
class MySet(set):
def __repr__(self) -> str:
return super().__repr__()
if __name__ == '__main__':
ms = MySet('abc')
print(ms)
MySet.__name__ = 'New_name'
print(ms)
输出:
MySet({'b', 'c', 'a'})
New_name({'b', 'c', 'a'})