python 中的 __pre_init__ 功能?

Pie*_*aar 5 python

我想让字符串比较不区分大小写。为此,我想创建一个只有一个字符串字段的不可变类。在构造函数中,我想在将值分配给字段之前调用 lower() 。

我想尽可能多地使用标准类,如命名元组或数据类。使用该__post_init__函数(参见例如如何在Python中的数据类中使用__post_init__方法)感觉就像是一种黑客攻击。这也让我想知道在我在函数中更改它后该字段是否仍然冻结__post_init__

但是,我找不到__pre_init__功能。有没有更好的办法?

Pie*_*aar 5

事实证明,数据类没有提供我正在寻找的功能。然而 Attrs 确实:

from attr import attrs, attrib


@attrs(frozen=True)
class Name:
    name: str = attrib(converter=str.lower)
Run Code Online (Sandbox Code Playgroud)


pro*_*ico 0

这应该是最简单的方法之一,你提到的字段是内部的 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)