【问题标题】:How to find out if a Python object is a string?如何判断 Python 对象是否为字符串?
【发布时间】:2010-11-21 03:42:27
【问题描述】:

如何检查 Python 对象是否为字符串(常规或 Unicode)?

【问题讨论】:

  • Jason 指的是鸭子打字(如果它像鸭子一样嘎嘎叫,它可能是鸭子)。在 Python 中,您经常在任何类似字符串的对象上“让您的代码工作”,而无需测试它是字符串还是字符串子类。欲了解更多信息,请参阅:docs.python.org/glossary.html#term-duck-typing
  • 这就是我喜欢 SO 的原因。我通常会问一个问题,但没有人回答,人们告诉我无论如何我都不应该这样做,为什么,我成长为一名程序员。 =)
  • +1:仅仅因为很少需要答案,并不意味着问题无效。虽然,我认为在这里提出警告很好,但我认为不值得将这个问题降级。
  • 这可能是 Python 中类型检查最合理的用法。字符串是可迭代的,因此以任何其他方式将它们与列表区分开来是个坏主意。
  • 在某些情况下肯定有必要将字符串与其他可迭代对象区分开来。例如,查看 pprint 模块中 PrettyPrinter 的源代码。

标签: python string types compatibility


【解决方案1】:

Python 2

isinstance(obj, basestring) 用于测试对象obj

Docs.

【讨论】:

  • 本页所有解决方案均非万无一失。我的意思是 basestringstr 都可以被覆盖,这将使所有这些解决方案无效。
【解决方案2】:

Python 3

在 Python 3.x 中,basestring 不再可用,因为 str 是唯一的字符串类型(具有 Python 2.x 的 unicode 的语义)。

所以 Python 3.x 中的检查只是:

isinstance(obj_to_test, str)

下面是the fix官方2to3转换工具:将basestring转换为str

【讨论】:

  • 这不适用于类似字符串的对象:isinstance(collections.UserString("foe"), str) == False
  • @loutre 感谢您的评论。我之前没有遇到过用户集合(UserStringUserDictUserList)。这些类型早于 Python 2。由于这些类型不继承自内置类型 strdictlist,因此 isinstance 调用将不起作用。仅供参考:因此,不能保证这些类型可以用作替代品。例如。正则表达式模块re 不适用于UserString(至少对于Python 3.8.2)。
【解决方案3】:

Python 2

检查对象o是否是字符串类型的子类的字符串类型:

isinstance(o, basestring)

因为strunicode 都是basestring 的子类。

检查o的类型是否正好是str

type(o) is str

检查ostr 的实例还是str 的任何子类:

isinstance(o, str)

如果您将str 替换为unicode,上述内容也适用于Unicode 字符串。

但是,您可能根本不需要进行显式类型检查。 “鸭子打字”可能适合您的需求。见http://docs.python.org/glossary.html#term-duck-typing

另见What’s the canonical way to check for type in python?

【讨论】:

  • 赋值前引用的局部变量'str'
  • @johnktejik python3 vs python2。你需要在py2中检查basestring
【解决方案4】:

Python 2 和 3

(交叉兼容)

如果您想检查而不考虑 Python 版本(2.x 与 3.x),请使用 six (PyPI) 及其 string_types 属性:

import six

if isinstance(obj, six.string_types):
    print('obj is a string!')

six(一个非常轻量级的单文件模块)中,它只是在做this

import sys
PY3 = sys.version_info[0] == 3

if PY3:
    string_types = str
else:
    string_types = basestring

【讨论】:

  • 或者,您可以使用future (PyPI) 甚至保留名称:from past.builtins import basestring
  • 顺便说一句,Cheat Sheet 是一个很好的 Python 版本兼容性资源。
  • 不使用任何导入怎么办?首先尝试basestring,然后回退到str。例如。 def is_string(obj): try: return isinstance(obj, basestring) # python 2 except NameError: return isinstance(obj, str) # python 3
【解决方案5】:

我发现了更多pythonic:

if type(aObject) is str:
    #do your stuff here
    pass

因为 type 对象是单例的,is 可用于将对象与 str 类型进行比较

【讨论】:

  • 这不是一般推荐的类型测试方法,因为继承:isinstance(obj_to_test, str) 显然是为了测试类型,它的优点是使用与其他相同的过程,非-str 案例。
【解决方案6】:

如果一个人想远离显式类型检查(很好的理由远离它),可能要检查的字符串协议中最安全的部分是:

str(maybe_string) == maybe_string

它不会遍历可迭代对象或迭代器,不会将字符串列表称为字符串,并且会正确地将stringlike 检测为字符串。

当然也有缺点。例如,str(maybe_string) 可能是一个繁重的计算。通常,答案是视情况而定

编辑:作为 cmets 中的 @Tcll points out,该问题实际上要求一种检测 unicode 字符串和字节字符串的方法。在 Python 2 上,此答案将失败,但包含非 ASCII 字符的 unicode 字符串会出现异常,而在 Python 3 上,它将为所有字节字符串返回 False

【讨论】:

  • 在使用表示数据初始化的对象的情况下,这可能无法按预期工作...b = b'test'; r = str(b) == b 其中bstr(b) 拥有相同的数据,但是(作为字节对象)不作为字符串验证。
  • @Tcll 是的,问题实际上是“常规或 Unicode”。我想我没有正确阅读它。
【解决方案7】:

为了检查你的变量是否是你可以这样的东西:

s='Hello World'
if isinstance(s,str):
#do something here,

isistance 的输出将为您提供布尔 True 或 False 值,以便您可以进行相应调整。 您可以通过最初使用以下方式检查您的值的预期首字母缩略词: 类型 这将返回您键入“str”,以便您可以在 isistance 函数中使用它。

【讨论】:

    【解决方案8】:

    很简单,使用下面的代码(我们假设提到的对象是obj)-

    if type(obj) == str:
        print('It is a string')
    else:
        print('It is not a string.')
    

    【讨论】:

      【解决方案9】:

      我可能会像其他人提到的那样以鸭式打字的方式处理这个问题。我怎么知道一个字符串真的是一个字符串?好吧,显然是通过它转换成一个字符串!

      def myfunc(word):
          word = unicode(word)
          ...
      

      如果 arg 已经是字符串或 unicode 类型,real_word 将保持其值不变。如果传递的对象实现了__unicode__ 方法,则用于获取其Unicode 表示。如果传递的对象不能用作字符串,则 unicode 内置函数会引发异常。

      【讨论】:

        【解决方案10】:
        isinstance(your_object, basestring)
        
        如果您的对象确实是字符串类型,则

        将为 True。 'str' 是保留字。

        我很抱歉, 正确的答案是使用 'basestring' 而不是 'str' 以便它包含 unicode 字符串 - 正如上面其他响应者之一所指出的那样。

        【讨论】:

        • 不适用于问题中明确要求的 unicode 对象。
        【解决方案11】:

        今天晚上我遇到了一种情况,我认为我将不得不检查str 类型,但事实证明我没有。

        我解决问题的方法可能适用于许多情况,因此我在下面提供它以防其他阅读此问题的人感兴趣(仅限 Python 3)。

        # NOTE: fields is an object that COULD be any number of things, including:
        # - a single string-like object
        # - a string-like object that needs to be converted to a sequence of 
        # string-like objects at some separator, sep
        # - a sequence of string-like objects
        def getfields(*fields, sep=' ', validator=lambda f: True):
            '''Take a field sequence definition and yield from a validated
             field sequence. Accepts a string, a string with separators, 
             or a sequence of strings'''
            if fields:
                try:
                    # single unpack in the case of a single argument
                    fieldseq, = fields
                    try:
                        # convert to string sequence if string
                        fieldseq = fieldseq.split(sep)
                    except AttributeError:
                        # not a string; assume other iterable
                        pass
                except ValueError:
                    # not a single argument and not a string
                    fieldseq = fields
                invalid_fields = [field for field in fieldseq if not validator(field)]
                if invalid_fields:
                    raise ValueError('One or more field names is invalid:\n'
                                     '{!r}'.format(invalid_fields))
            else:
                raise ValueError('No fields were provided')
            try:
                yield from fieldseq
            except TypeError as e:
                raise ValueError('Single field argument must be a string'
                                 'or an interable') from e
        

        一些测试:

        from . import getfields
        
        def test_getfields_novalidation():
            result = ['a', 'b']
            assert list(getfields('a b')) == result
            assert list(getfields('a,b', sep=',')) == result
            assert list(getfields('a', 'b')) == result
            assert list(getfields(['a', 'b'])) == result
        

        【讨论】:

          【解决方案12】:

          你可以通过连接一个空字符串来测试它:

          def is_string(s):
            try:
              s += ''
            except:
              return False
            return True
          

          编辑

          在 cmets 指出列表失败后更正我的答案

          def is_string(s):
            return isinstance(s, basestring)
          

          【讨论】:

            【解决方案13】:

            我认为可以安全地假设如果repr() 的输出的最后一个字符是'",那么无论它是什么,它都应该被视为某种字符串。

            def isStr(o):
                return repr(o)[-1] in '\'"'
            

            我假设repr 不会做太多繁重的事情,它会返回一个至少包含一个字符的字符串。您可以使用类似的东西来支持空字符串

            repr(o)[-1:].replace('"', "'") == "'"
            

            但这仍然假设 repr 完全返回一个字符串。

            【讨论】:

              【解决方案14】:
              if type(varA) == str or type(varB) == str:
                  print 'string involved'
              

              来自 EDX - 在线课程 MITx:6.00.1x 计算机科学和 Python 编程简介

              【讨论】:

              • 这可能是最糟糕的检查方式。它不仅排除了 unicode 对象,它甚至排除了 str! 的子类!
              【解决方案15】:

              对于类似字符串的很好的鸭式键入方法,它具有同时使用 Python 2.x 和 3.x 的好处:

              def is_string(obj):
                  try:
                      obj + ''
                      return True
                  except TypeError:
                      return False
              

              wisefish 在切换到 isinstance 方法之前与鸭子打字很接近,除了 += 对列表的含义与 + 不同。

              【讨论】:

              • 好吧,你有两个反对票,没有人提供评论。我没有投反对票,但我不喜欢您的解决方案,因为: * 太冗长了。您不需要定义一个函数来执行此操作。 * 昂贵的。捕获异常对性能不利。 * 容易出错。其他对象可能实现 add,看到一个字符串,并引发另一种类型的异常,这不是 TypeError。
              • 这里你也使用了duck-typing方法,这很漂亮,但最终抛出和捕获异常只是为了找出一些东西,这并不漂亮。
              • 这可能是区分类似字符串和其他可迭代字符串的唯一可靠方法。可以查找isalpha 之类的属性,但谁知道查找哪些方法是安全的?
              • realized 认为__str__ 方法加上相等实际上可能是万无一失的。但即使这样也不是没有警告。
              • @santiagobasulto 异常在 Python 中很便宜。如果您预计错误 1% 的时间,try 可以更快。如果你 99% 的时间都期待它,也许不会。性能差异很小,最好是惯用的,除非您分析您的代码并将其识别为实际上很慢。
              猜你喜欢
              • 2010-09-21
              • 1970-01-01
              • 2012-01-02
              • 1970-01-01
              • 2011-05-31
              • 1970-01-01
              • 2020-08-26
              • 2011-07-31
              • 1970-01-01
              相关资源
              最近更新 更多