PEP 661 - Sentinel值

2021-06-10 13:20:12

独特的占位符值,广泛称为" Sentinel值",对于几件事是有用的inpython程序,例如默认值的默认值,其中none是有效输入值。这些案件是用于实施此类&#34的若干成语的常用;哨兵"多年来举行的艾西哥犬,但足够罕见的是,有足够的' t' t明确需要持续的。然而,常见的实施包括一些在历史上,遭受了几种显着的缺点。

此PEP建议添加用于定义Sentinel值的实用程序,以使用STDLIB并以STDLIB的一部分公开可用。

注意:不需要更改待实施的STDLIB中的所有现有哨兵,并且是必要的,以及是否留下了每个维护者的自由裁量权。

在2021年5月,在Python-dev邮件列表[1]上提出了一个问题,了解如何更好地实现Traceback.print_exception的Sentinel值。现有实现使用常见的成语:

但是,这个对象具有不知情的和过于冗长的Rep,导致Function' S签名要多久且难以阅读:

>>>帮助(traceback.print_exception)在模块追踪中的函数print_exception中的帮助:print_exception(exc,/,value =< object对象at0x000002825df09650> tb =<对象对象0x000002825df09650>,limit = none,file = none )

不具有不同类型,因此不可能将stricttype签名与哨兵函数定义为默认值

由于正在创建的独立途径并且因此使用正在失败的比较,因此在被复制或未划分之后的不正确行为

在随后的讨论中,Victor Stinner在Python标准库中提供了当前使用的使用者值的列表[2]。这表明,对于哨兵的需求是相当常见的,即使在STDLIB中也使用了令人存在的实施方法,并且许多这些都存在这种情况从上述至少一个缺点。

讨论没有关于是否需要或理想的标准拼接方法的任何明确共识,是否提到了缺点是重大的重要性,也是良好的实施方式。

在讨论中创建了一个民意调查.Python.org [3]以获得更清晰的社区感和意见。投票'结果没有得出决定,40%的投票为"状态 - quo很好/无需一致性的Inthis"但大多数选民投票给一个或多个标准化解决方案。 37%的选民选择了"一致使用新的专家专用店出厂/课堂/梅塔类,也在历史上公开提供;

通过如此混合的意见,这个PEP是为了促进主题的作出决定而设计。

sentinel对象应该按照sentinel对象的预期行事:当使用IS运算符时,应始终被视为自身,但从未到任何其他对象。

Sentinel对象应每个都有一个不同的类型,可用于定义严格型签名的类型。

在研究现有的习语和实现之后,并经过许多多种可能的实现,写入了这些标准的满足(参见参考实施)的实现。

一个新的Sentinel函数将被添加到新的Sentinels module.it将接受一个必需的参数,sentinel对象的名称,以及一个可选参数,对象的'对象的'。

第三个可选参数,存在Sentinel ISDEFINED的模块的名称,以用于通过检查堆栈帧来找到模型内找到的案例。这与CollectionS.namedTuple使用的图案相同。 (已被用于为新的Sentinel生成的类的类的唯一名称,该模块的名称被设置为Sentinels模块的属性。)

def sentinel(姓名,'nec = none):"""创建一个唯一的哨兵对象。""" Repr = RePr或F'< {name}>' module = _get_parent_frame()。f_globals.get(' __名称__'' __ main __')class_name = _get_class_name(name,module)class_namespace = {' __ Repre __&#39 ;: lambda self :Rep,} cls = type(class_name,(),class_namespace)cls .__ module__ = __name__ globals()[class_name] = cls sentinel = cls()cls .__ new__ = lambda cls:sentinel returnededef _get_class_name(sentinel_qualname,module_name):返回' __' .join([' _sentinel_type' module_name.replace('' _' _'),sentinel_qualname.replace( '&#39 ;,' _')])

由于这样的价值可以用于各个地方的各种各样的东西,因此并不总是有信心在某些USECASE中永远不会是一个有效的价值。另一方面,专用和独特的哨兵值可以自信地使用,而无需考虑潜在的边缘情况。

此外,能够提供有意义的名称和重新重新使用Sentinel值是有用的,具体到使用它的上下文。

最后,这是民意调查中的一个非常不受欢迎的选择[3],只有12%的投票投票。

这不是省略号的原始预期用途,尽管它已经易于使用它来定义空型或功能块而不是使用通过。

此外,类似于潜在的新单个哨兵价值,省略号可以'在所有情况下自信地使用,与专用,不同的价值不同。

除了过度重复之外,ROP是过长的:< notgiventype.notgiven:' notgiven'&gt ;.可以定义一个较短的rep,以比特更多的代码和更多的重复。

最后,此选项是民意调查[3]中的九个选项中最不流行的,这是唯一无法获得投票的选项。

虽然这允许一个非常简单明了的实现,但界面太冗长,重复,难以记住。

由于类是固有的单例,使用一个类作为Sentinel Valuemakes感,并且允许简单的实现。

然而,所有这样的实施方式都没有用于Thesentinel的专用类型,这被认为是理想的。可以创建一个专用类型,Meta类或类装饰器,但在这一点上,实现将使实现更复杂并失去对Choshimplementation的优势。

最常见的退出习语具有显着的缺点。 到目前为止,没有发现任何形象,在避免这些缺点时明确而简洁。 此外,在对该主题的民意调查中[3],建议艾迪摩的选项不受欢迎,最高投票的选择仅投票25%的选民。 在模块中定义时,对复制/解击工作的支持范围(可能嵌套)类' s范围。 请注意,在后一种情况下,名称可以作为第一个参数的名称必须是模块中最不明确的完全限定名称: 本文档放在公共领域或在TheCC0-1.0-Universal License下,以允许更为允许。 来源:https://github.com/python/peps/blob/master/pep-0661.rst.