我正在将遗留代码库从Python 2.7移植到Python 3.6。在该代码库中,我有许多例子:
class EntityName(unicode):
@staticmethod
def __new__(cls, s):
clean = cls.strip_junk(s)
return super(EntityName, cls).__new__(cls, clean)
def __init__(self, s):
self._clean = s
self._normalized = normalized_name(self._clean)
self._simplified = simplified_name(self._clean)
self._is_all_caps = None
self._is_all_lower = None
super(EntityName, self).__init__(self._clean)
可能会这样调用:
EntityName("Guy DeFalt")
将此代码移植到Python 3时,上述代码失败,因为unicode
不再是可以扩展的类(至少,如果有一个我找不到的等效类)。鉴于str
现在是unicode,我试图只交换str
,但是父init不接受我试图传递的字符串值:
TypeError: object.__init__() takes no parameters
这是有道理的,因为str
没有__init__
方法 - 这似乎不是使用此类的惯用方式。所以我的问题有两个主要分支:
str
是合适的,我应该如何修改__init__
函数的惯用行为?答案 0 :(得分:0)
在Python 3中子类化字符串或另一个不可变类的正确方法与Python 2中相同:
class MyString(str):
def __new__(cls, initial_arguments): # no staticmethod
desired_string_value = get_desired_string_value(initial_arguments)
return super(MyString, cls).__new__(cls, desired_string_value)
# can be shortened to super().__new__(...)
def __init__(self, initial_arguments): # arguments are unused
self.whatever = whatever(self)
# no need to call super().__init__(), but if you must, do not pass arguments
您的示例有几个问题。首先,为什么__new__
是@staticmethod
?它是@classmethod
,尽管您不需要指定它。其次,该代码似乎在这样的假设下运行:当您调用超类的__new__
时,它也会以某种方式调用您的__init__
。我是通过查看应该如何设置self._clean
来得出的。不是这种情况。当您致电MyString(arguments)
时,会发生以下情况:
__new__
)和cls
调用arguments
。 __new__
必须返回类实例。为此,它可以像我们一样创建它,或者做其他事情。例如它可能会返回一个现有的,或者实际上是任何东西。__init__
接收到的实例(此参数通常称为__new__
)和相同的self
调用arguments
。__init__
返回的不是所传递类的子类,Python不会调用__new__
。) Python使用类层次结构来查看要调用的__new__
和__init__
。正确选择参数并在这两种方法中使用正确的超类调用取决于您。