花猫语:在上篇《Python 为什么能支持任意的真值判断? 》文章中,我们分析了Python在判断真值方面的底层实现。可见,Python在处理布尔值时,采取了比较宽泛的态度。当局对此有何看法?下面这篇文章是我刚刚由Python之父GuidovanRossum翻译的PEP-285。这个PEP意义重大。Python的bool类型就是从它引入的,我在上篇文章中分析的很多问题,在十几年前的这篇文档中都能得到解释!此外,它还回应了一些典型的争议,值得理解。PEP原文:https://www.python.org/dev/peps/pep-0285/PEPtitle:PEP285--AddingabooltypePEP作者:GuidovanRossum创建日期:2002-03-08合并版本:2.3译者:猫下的豌豆花@Python猫公众号PEP翻译计划:https://github.com/chinesehua...总结本PEP提议引入一个新的内置类型bool,它将包含两个常量False和真的。bool类型是int类型的直接子类型(在C中),它的值False和True在除了repr()和str()之外的大多数方面表现得像0和1(例如,False==0和True==1均为真)。所有在概念上返回布尔结果的内置操作都将更改为返回False或True而不是0或1,例如比较操作、“非”操作和断言方法,例如isinstance()。审查我收集了很多反馈,因此我宣布审查期正式结束。我今天吃了中国菜,我的幸运饼干上写着:“强词夺理,言无不尽”。让我想起了一些反对这个PEP的帖子...:-)(译注:1,Fortunecookies就是fortunecookies,这是美国文化的一个特点,在美国的中餐馆流行给顾客一些带有写在上面的幸运字,通常是祝福。2.那个标志是维克多·雨果的,意思是:作恶者言辞激烈)不管怎样,这些是我的BDFL声明。(执行摘要:我不会改变任何东西;所有其他提案都将被拒绝。)1.这个PEP应该被接受吗?=>是的。有很多反对此PEP的论点。大多数是因为误解。我试图在下面的PEP文本中澄清一些最常见的误解。对我来说唯一值得考虑的是新手倾向于写“ifx==True”,但“ifx”就足够了。下面还有更多关于它的信息。我认为这不足以拒绝此PEP。2.str(True)应该返回“True”还是“1”?“1”可能会减少向后兼容性问题,但看起来很奇怪。(repr(True)将始终返回“True”。)=>“True”。几乎所有评论家都同意这一点。3.常量应该命名为“True”和“False”(如None)还是“true”和“false”(如C++、Java和C99)?=>对与错。大多数审阅者都认为Python内部的一致性比与其他语言的一致性更重要。4.布尔值上的非布尔运算是否应该通过适当的警告消除,例如True+1最终(在Python3000中)变得非法?=>应该不会有一小群非常直言不讳的人希望看到一个“教科书”的布尔类型,即完全不支持算术运算,但大多数评论者都同意我的观点,布尔类型应该支持算术运算。5.operator.truth(x)应该返回int还是bool?=>布尔。TimPeters认为应该返回一个整数,但几乎所有其他评论者都认为应该返回一个布尔值。我的推理:operator.truth()旨在强制其参数使用布尔类型上下文(它调用CAPIPyObject_IsTrue())。结果是int还是bool是次要的;如果你有布尔值,就没有理由不使用它。(在此PEP下,operator.truth()成为bool()的别名;这也很好。)6.bool应该从int继承吗?=>是的。理想情况下,bool将实现为支持执行混合算术运算的单独整数类型。然而,从int继承bool将大大简化实现(部分原因是所有调用PyInt_Check()的C代码都是兼容的——它为int的子类返回true)。此外,我认为这符合可替换性的概念:当您的代码中需要一个int时,您可以提供一个bool,它相当于0或1。当您的代码中需要一个bool时分配一个int可能不会像预期的;例如,3&4的计算结果为0,但当3和4被视为真值时它们都为真。7.“bool”的名字应该改变吗?=>不。一些评论者提倡使用boolean而不是bool,因为它更容易理解(新人可能听说过布尔代数,但可能对bool不感兴趣),或者因为他们讨厌缩写。我的观点:Python明智地使用缩写(例如'def'、'int'、'dict'),我认为这不是理解的负担。对于新手来说,叫waffle还是bool并不重要;这只是一个新词,他们很快就会明白它的意思。(译注:waffle,我们一般都知道是“wafflebiscuit”的意思,但也有“无意义的、无关紧要的、随意的词”的意思)某评论者认为可以称之为“真相”。我觉得这个名字没有吸引力,实际上更喜欢保留这个术语(在文档中)来指代Python中已经存在的真值的具体概念。例如:“当将容器解释为真值时,空容器被认为是假的,非空容器被认为是真”。8.如果将来要求布尔运算符(如“if”、“and”和“not”)使用布尔值作为参数,例如要使“if[]:”不合法,则必须是写成“如果布尔([]):”???=>不!!!有人争辩说,这就是具有教科书布尔类型的语言应该如何做到的。因为提出来了,别人担心我会不会同意。我在此明确表明我的立场:这不是这个PEP的动机,我无意改变它。(另请参阅下面的“澄清”部分。)基本原理大多数语言最终都会演化出布尔类型,即使是C99(C标准的新改进版本,尚未广泛采用)也有。(译注:C99标准诞生于1999年,本PEP写于2002年,时过境迁,现在C99标准基本落伍了)含歉意。我见过很多模块在顶部定义常量“False=0”和“True=1”(或类似的),并使用它们。问题是每个人的做法都不一样。例如,您应该使用“FALSE”、“false”、“False”、“F”还是“f”?另外,false值应该是0还是None,或者其他打印“true”或“false”的布尔值?向语言添加标准布尔类型可以解决这些问题。一些外部库(例如数据库和RPC相关的包)需要能够区分布尔值和整数值,虽然通常可以制定解决方案,但如果语言本身提供标准的布尔类型会更容易。这也适用于Jython:一些Java类具有分别用于int和boolean参数的重载方法或构造函数。布尔类型可用于选择布尔变量。(显然,某些COM接口也是如此。)标准的bool类型还作为一种强制将值解释为布尔值的方式,可用于标准化布尔值。当一个布尔值需要归一化为两个值之一时,bool(x)比“notnotx”更清晰,也比这个更简洁:ifx:return1else:return0这是从TeachingPython中获得的一些经验。我认为在交互式终端中向人们显示比较运算符时有点难看:>>>a=13>>>b=12>>>a>b1>>>如果是这样:>>>a>bTrue>>>每次思考打印的0或1的时间都会减少一毫秒。还有一个问题(它甚至困扰着已经远离Python一段时间的有经验的人):>>>cmp(a,b)1>>>cmp(a,a)0>>>你可能倾向于认为那cmp()也是返回一个布尔值,但实际上它可以返回三个不同的值(-1,0,1)。如果不(通常)使用整数来表示布尔结果,那么这可以更清楚地表达其他含义。(译注:只用True/False表示布尔值,整数表示其他含义时不会出现歧义)下面的Python代码指定了新类型的大部分属性:classbool(int):def__new__(cls,val=0):#这个构造函数总是返回一个存在的实例ifval:returnTrueelse:returnFalsedef__repr__(self):ifself:return"True"else:return"False"__str__=__repr__def__and__(self,other):ifisinstance(other,bool):returnbool(int(self)&int(other))else:returnint.__and__(self,other)__rand__=__and__def__or__(self,other):ifisinstance(other,bool):返回bool(int(self)|int(other))else:returnint.__or__(self,other)__ror__=__or__def__xor__(self,other):ifisinstance(other,bool):returnbool(int(self)^int(other))else:returnint.__xor__(self,other)__rxor__=__xor__#BootstraptruthhvaluesthroughsheerwillpowerFalse=int.__new__(bool,0)True=int.__new__(bool,1)False和True将是单例,如None因为这种类型有两个值,也许应该称它们为“doubletons”?实际实现将不允许创建bool的其他实例。True和False将被正确序列化和打包,例如pickle.loads(pickle.dumps(True))将返回True,marshal.loads(marshal.dumps(True))也将返回True。根据定义返回布尔结果的所有内置操作都将更改为返回False或True而不是0或1。具体来说,这会影响比较操作(<、<=、==、!=、>、>=、是,isnot,in,notin),一元运算符'not',内置函数callable(),hasattr(),isinstance()andissubclass(),字典方法has_key(),字符串和unicode方法endswith()、isalnum()、isalpha()、isdigit()、islower()、isspace()、istitle()、isupper()和startswith()、unicode方法isdecimal()和isnumeric(),以及“封闭”文件对象的属性。operator模块中的断言方法也已更改为返回布尔值,包括operator.truth()。由于bool继承自int,True+1有效且等于2,依此类推。这对于向后兼容性很重要:由于比较等操作当前返回整数值,因此无法确定现有应用程序如何使用这些值。预计随着时间的推移,标准库将更新为在适当的时候使用False和True(但在以前允许使用int的情况下,不需要bool参数类型)。此更改不应导致本PEP中未指定的其他问题。CAPI“boolobject.h”头文件定义布尔类型的CAPI。它包含在“Python.h”中,因此无需再次包含它。现有名称Py_False和Py_True指代唯一的布尔对象False和True(以前,它们分别指代值为0和1的静态整数对象,是许多整数中的一个)。一个新的APIPyObject*PyBool_FromLong(long)接受一个Clong参数并返回对Py_False(当参数为零时)或Py_True(当非零时)的新引用。要检查对象是否为布尔值,可以使用宏PyBool_Check()。布尔实例的类型是PyBoolObject*。布尔类型对象可用作PyBool_Type。阐明了此PEP不会改变几乎任何类型的对象都可以用作true或false值的事实。例如,在if语句中使用时,空列表为假,非空列表为真;这不会改变,也不打算改变。唯一改变的是返回或赋值时用于表示true或false的首选值。以前,这些首选的true和false值是1和0;此PEP将首选值更改为True和False,并修改内置操作以返回这些首选值。兼容性由于向后兼容,布尔类型具有一些松散的属性。例如,允许使用布尔参数的算术运算,将False视为0,将True视为1。此外,布尔值可用作序列对象的索引。我不认为这是一个问题,也不想朝这个方向发展语言。我认为对“布尔性”的更严格解释不会使语言更清晰。兼容性要求的另一个结果是表达式“Trueand6”的计算结果为6,类似地,表达式“FalseorNone”的计算结果为None。“and”和“or”运算符旨在返回决定结果的第一个参数,这一点不会改变;特别是,它们不强制结果为布尔类型。当然,如果两个参数都是布尔值,那么结果一定是布尔值。也可以通过编写“bool(xandy)”轻松将其强制转换为布尔值。已修复问题(另请参阅上面的“审查”部分。)由于bool值repr()或str()与int值不同,一些代码(例如,基于doctest的单元测试,并且可能依赖于“%s”%真相的数据库代码)可能是错误的。解决这个问题很容易(无需显式引用bool类型),预计这只会影响非常少量的代码,这些代码很容易修复。其他语言(C99、C++、Java)以小写形式命名常量“false”和“true”。对于Python,我更喜欢遵循现有内置常量的约定,它们都是驼峰式的:None、Ellipsis、NotImplemented(以及所有内置异常)。Python的内置命名空间对函数和类型使用全部小写字母。如前所述,为了满足用户期望,表达式x==True对于在布尔上下文中被认为是真的每个x都应该为真,同样,如果x被认为是假,则x==False也应该为真。那些刚接触布尔变量的人可能会写:ifx==True:...而不是正确的形式:ifx:...很多人乍一看对后一种形式感到不舒服,心理和语言似乎有很强的理由,但我认为解决办法应该是教育而不是弱化语言。毕竟,==通常被认为是可传递的,这意味着a==c可以从a==b和b==c推导出来。但是,如果与True相比,一个数字等于True,那么像6==True==7这样的暴行将成立,从而可以推断出错误的6==7。这是不可接受的。(此外,它会破坏向后兼容性。但即使没有,我仍然会出于上述原因反对它。)还应该提醒新手,没有理由写:ifbool(x):...因为bool隐含在“if”中。在这里显式并不比隐式好,因为添加的词汇会损害可重用性并限制解释器的解释行为。(译注:《Python之禅》认为“显式优于隐式”,但这里Guido认为隐式更好,所以在原文档中将“不”加粗)不过,有时候也有写的理由:b=bool(x)当不需要保留对任意x对象的引用时,或者当出于某些其他原因需要规范化时,这很有用。有时这样写也是合适的:i=int(bool(x))将布尔值转换为整数0或1。传达将值用作int的意图。完整的C实现已上传到SourceForge补丁管理器:https://bugs.python.org/issue...它将很快合并到python2.3a0的CVS中。版权本文档已进入公共领域。源文档:https://github.com/python/pep...更多PEP中文翻译内容可在Github上找到:https://github.com/chinesehua...
