格式化 Python 字符串既不使用 repr 也不使用 str - 发生了什么?
Formatted Python string uses neither repr nor str - what is happening?
我有一个从 namedtuple
和 Enum
继承的枚举 ResourceType
,我不会在任何地方覆盖 __str__
或 __repr__
。当我格式化该枚举的实例时,我意外地得到了未修饰的值,而不是 repr()
或 str()
。这怎么可能?叫什么?
枚举详细信息(简体):
from enum import Enum, auto
from collections import namedtuple
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
输出:
>>> repr(ResourceType.RGB)
"<ResourceType.RGB: ResourceType(value=<enum.auto object at 0x7f44b7d48d30>, ext='.png', required=True)>"
>>> str(ResourceType.RGB)
'ResourceType.RGB'
>>> f"{ResourceType.RGB}"
"ResourceType(value=<enum.auto object at 0x7f44b7d48d30>, ext='.png', required=True)"
最后一个值既不是 repr()
也不是 str()
,所以即使 namedtuple
提供了那个字符串,为什么它不也提供 str/repr?
当您以这种方式将对象插入 f 字符串时,它会调用 __format__
方法。
from enum import Enum, auto
from collections import namedtuple
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
def __repr__(self):
return "REPR"
def __str__(self):
return "STR"
def __format__(self, format_spec):
return "FORMAT"
print(repr(ResourceType.RGB))
print(str(ResourceType.RGB))
print(f"{ResourceType.RGB}")
给出
的输出
REPR
STR
FORMAT
正在调用什么?
Enum.__format__
enum.py 中的文档字符串声明它
Returns format using actual value type unless __str__
has been
overridden.
现在 Kemp 和 Daweo 已经指出魔术是通过 __format__
发生的,我能够更深入地挖掘,并且确实在 Enum
class 中我们发现:
def __format__(self, format_spec):
# mixed-in Enums should use the mixed-in type's __format__, otherwise
# we can get strange results with the Enum name showing up instead of
# the value
# pure Enum branch
if self._member_type_ is object:
cls = str
val = str(self)
# mix-in branch
else:
cls = self._member_type_
val = self._value_
return cls.__format__(val, format_spec)
ResourceType
由于继承了 namedtuple
也是一个混合枚举,因此对于 __format__
的情况,调用被重定向到 'ResourceType' namedtuple
仅包含枚举实例的值,由 convention/implementation.
存储在 _value_
中
在我的例子中,我希望 ResourceType
枚举在外部尽可能像枚举一样出现,尽管它也是一个命名元组,所以我现在将其更改为:
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
def __format__(self, format_spec):
return str.__format__(str(self), format_spec)
这完全等同于在 Enum.__format__
实现中强制执行 'pure Enum branch'。
我有一个从 namedtuple
和 Enum
继承的枚举 ResourceType
,我不会在任何地方覆盖 __str__
或 __repr__
。当我格式化该枚举的实例时,我意外地得到了未修饰的值,而不是 repr()
或 str()
。这怎么可能?叫什么?
枚举详细信息(简体):
from enum import Enum, auto
from collections import namedtuple
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
输出:
>>> repr(ResourceType.RGB)
"<ResourceType.RGB: ResourceType(value=<enum.auto object at 0x7f44b7d48d30>, ext='.png', required=True)>"
>>> str(ResourceType.RGB)
'ResourceType.RGB'
>>> f"{ResourceType.RGB}"
"ResourceType(value=<enum.auto object at 0x7f44b7d48d30>, ext='.png', required=True)"
最后一个值既不是 repr()
也不是 str()
,所以即使 namedtuple
提供了那个字符串,为什么它不也提供 str/repr?
当您以这种方式将对象插入 f 字符串时,它会调用 __format__
方法。
from enum import Enum, auto
from collections import namedtuple
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
def __repr__(self):
return "REPR"
def __str__(self):
return "STR"
def __format__(self, format_spec):
return "FORMAT"
print(repr(ResourceType.RGB))
print(str(ResourceType.RGB))
print(f"{ResourceType.RGB}")
给出
的输出REPR
STR
FORMAT
正在调用什么?
Enum.__format__
enum.py 中的文档字符串声明它
Returns format using actual value type unless
__str__
has been overridden.
现在 Kemp 和 Daweo 已经指出魔术是通过 __format__
发生的,我能够更深入地挖掘,并且确实在 Enum
class 中我们发现:
def __format__(self, format_spec):
# mixed-in Enums should use the mixed-in type's __format__, otherwise
# we can get strange results with the Enum name showing up instead of
# the value
# pure Enum branch
if self._member_type_ is object:
cls = str
val = str(self)
# mix-in branch
else:
cls = self._member_type_
val = self._value_
return cls.__format__(val, format_spec)
ResourceType
由于继承了 namedtuple
也是一个混合枚举,因此对于 __format__
的情况,调用被重定向到 'ResourceType' namedtuple
仅包含枚举实例的值,由 convention/implementation.
_value_
中
在我的例子中,我希望 ResourceType
枚举在外部尽可能像枚举一样出现,尽管它也是一个命名元组,所以我现在将其更改为:
class ResourceType(namedtuple('ResourceType', 'value ext required'), Enum):
RGB = auto(), '.png', True
def __format__(self, format_spec):
return str.__format__(str(self), format_spec)
这完全等同于在 Enum.__format__
实现中强制执行 'pure Enum branch'。