且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《Python Cookbook(第2版)中文版》——1.3 测试一个对象是否是类字符串

更新时间:2022-09-09 23:40:51

本节书摘来自异步社区《Python Cookbook(第2版)中文版》一书中的第1章,第1.3节,作者[美]Alex Martelli , Anna Martelli Ravenscrof , David Ascher ,高铁军 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.3 测试一个对象是否是类字符串

任务

有时候需要测试一个对象,尤其是当你在写一个函数或者方法的时候,经常需要测试传入的参数是否是一个字符串(或者更准确地说,这个对象是否具有类似于字符串的行为模式)。
解决方案

下面给出一个利用内建的isinstance和basestring来简单快速地检查某个对象是否是字符串或者Unicode对象的方法,如下:

def isAString(anobj):
       return isinstance(anobj, basestring)

讨论

很多遇到这个问题的程序员第一反应是进行类型测试:

def isExactlyAString(anobj):
       return type(anobj) is type('')

然而,这种方法非常糟糕,因为它破坏了Python强大力量的源泉—平滑的、基于签名的多态机制。很明显Unicode对象无法通过这个测试,用户自己编写的str的子类也不行,甚至任何一种行为表现类似于字符串的用户自定义类型的实例都无法通过测试。

本节推荐的内建函数isinstance则要好很多。内建类型basestring的存在使得这个方法成为可能。basestring是str和unicode类型的共同基类,任何类字符串的用户自定义类型都应该从基类basestring派生,这样能保证isinstance的测试按照预期工作。本质上basestring是一个“空”的类型,就像object,所以从它派生子类并没有什么开销。

不幸的是,这个似乎完美的isinstance检查方案,对于Python标准库中的UserString模块提供的UserString类的实例,完全无能为力。而UserString对象是非常明显的类字符串对象,只不过它不是从basestring派生的。如果想支持这种类型,可以直接检查一个对象的行为是否真的像字符串一样,比如:

def isStringLike(anobj):
       try: anobj + ''
       except: return False
       else: return True

这个isStringLike函数比方案中给出的isAString函数慢且复杂得多,但它的确适用于UserString(以及其他的类字符串的类型)的实例,也适用于str和unicode。

Python中通常的类型检查方法是所谓的鸭子判断法:如果它走路像鸭子,叫声也像鸭子,那么对于我们的应用而言,就可以认为它是鸭子了。IsStringLike函数只不过检查了叫声部分,那其实还不够。如果需要检查anobj对象的更多的类字符串特征,可以改造try子句,让它检查更多细节,比如:

try: anobj.lower( ) + anobj + ''

根据我的经验,isStringLike函数的测试通常就已经满足需要了。

进行类型验证(或者任何验证任务)的最具Python特色的方法是根据自己的预期去执行任务,在此过程中检测并处理由于不匹配产生的所有错误和异常。这是一个著名的处理方式,叫做“获得事后原谅总是比事先得到许可要容易得多(It's easier to ask forgiveness than permission)”,或简称EAFP。try/except是保证EAFP处理风格的关键工具。有时,像本节中的例子一样,可以选择一个简单的判断方法,比如拼接一个空字符串,作为对一系列属性的集合(字符串对象提供的各种操作和方法)的一个替代性判断。