繁体   English   中英

避免使用昂贵的__init__是使用__new__的充分理由吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM