[英]Is avoiding expensive __init__ a good reason to use __new__?
在我的项目中,我们有一个基于集合的类。 它可以从字符串或字符串的可迭代(例如元组)或其他自定义类初始化。 当使用可迭代方法初始化时,如果尚未将每个项目转换为特定的自定义类,则将其转换为一个特定的自定义类。
因为可以从各种数据结构中初始化它,所以在该类上运行的许多方法(例如__and__
)在接受内容上都是自由的,只需将其参数转换为此类(即初始化一个新实例)即可。 当参数已经是该类的实例并且有很多成员时,我们发现它相当慢(正在遍历所有成员并检查它们是否是正确的类型)。
我当时想避免这种情况,我们可以在类中添加__new__
方法,并且即使传入的参数已经是该类的实例,也可以直接将其返回。 这是对__new__
的合理使用吗?
添加 __new__
方法不会解决您的问题。 从__new__
的文档中:
如果
__new__()
返回cls
的实例,则将调用新实例的__init__()
方法,就像__init__(self[, ...])
,其中self
是新实例,其余参数与传递给__new__()
。
换句话说,返回相同的实例不会阻止python调用__init__
。 您可以很容易地验证这一点:
In [20]: class A:
...: def __new__(cls, arg):
...: if isinstance(arg, cls):
...: print('here')
...: return arg
...: return super().__new__(cls)
...: def __init__(self, values):
...: self.values = list(values)
In [21]: a = A([1,2,3])
In [22]: A(a)
here
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-c206e38274e0> in <module>()
----> 1 A(a)
<ipython-input-20-5a7322f37287> in __init__(self, values)
6 return super().__new__(cls)
7 def __init__(self, values):
----> 8 self.values = list(values)
TypeError: 'A' object is not iterable
您可以来完成这项工作,如果你没有实现__init__
可言,但只有__new__
。 我相信这就是tuple
所做的。
同样,只有当您的类是不可变的时,这种行为才是可以接受的(例如, tuple
这样做),因为结果是明智的。 如果它是可变的,则要求隐藏的错误。
一种更明智的方法是执行set
操作: __*__
操作仅对 set
s进行操作,但是set
还提供了可与任何可迭代方法一起使用的命名方法:
In [30]: set([1,2,3]) & [1,2]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-dfd866b6c99b> in <module>()
----> 1 set([1,2,3]) & [1,2]
TypeError: unsupported operand type(s) for &: 'set' and 'list'
In [31]: set([1,2,3]) & set([1,2])
Out[31]: {1, 2}
In [32]: set([1,2,3]).intersection([1,2])
Out[32]: {1, 2}
这样,用户可以在API的速度和灵活性之间进行选择。
unutbu提出了一种更简单的方法:在执行操作时,使用isinstance
而不是duck-typing。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.