我想让字符串比较不区分大小写。为此,我想创建一个只有一个字符串字段的不可变类。在构造函数中,我想在将值分配给字段之前调用 lower() 。
我想尽可能多地使用标准类,如命名元组或数据类。使用该__post_init__函数(参见例如如何在Python中的数据类中使用__post_init__方法)感觉就像是一种黑客攻击。这也让我想知道在我在函数中更改它后该字段是否仍然冻结__post_init__。
但是,我找不到__pre_init__功能。有没有更好的办法?
事实证明,数据类没有提供我正在寻找的功能。然而 Attrs 确实:
from attr import attrs, attrib
@attrs(frozen=True)
class Name:
name: str = attrib(converter=str.lower)
Run Code Online (Sandbox Code Playgroud)
这应该是最简单的方法之一,你提到的字段是内部的 data(从类继承UserString):
from collections import UserString
class LowerStr(UserString):
def __init__(self, value):
super().__init__(value)
self.data = self.data.lower()
s1 = LowerStr("ABC")
print("s1: {}".format(s1))
print("s1 class: {}".format(s1.__class__))
print("s1 class mro: {}".format(s1.__class__.mro()))
Run Code Online (Sandbox Code Playgroud)
输出:
s1: abc
s1 class: <class '__main__.LowerStr'>
s1 class mro: [<class '__main__.LowerStr'>, <class 'collections.UserString'>, <class 'collections.abc.Sequence'>, <class 'collections.abc.Reversible'>, <class 'collections.abc.Collection'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Iterable'>, <class 'collections.abc.Container'>, <class 'object'>]
Run Code Online (Sandbox Code Playgroud)
这为您提供了所有方法str,您可以随意自定义它们。
如果您更喜欢子类化,那么就没有内部data属性:
class InsensitiveStr(str):
def __new__(cls, value):
if isinstance(value, str):
return super().__new__(cls, value.lower())
else:
raise ValueError
s1 = InsensitiveStr("ABC")
print(s1)
print(type(s1))
print(s1.__class__)
print(s1.__class__.__mro__)
Run Code Online (Sandbox Code Playgroud)
注意 mro 中的差异。
输出
abc
<class '__main__.InsensitiveStr'>
<class '__main__.InsensitiveStr'>
(<class '__main__.InsensitiveStr'>, <class 'str'>, <class 'object'>)
Run Code Online (Sandbox Code Playgroud)