【问题标题】:How can I tell if a python variable is a string or a list?如何判断 python 变量是字符串还是列表?
【发布时间】:2009-05-07 18:53:26
【问题描述】:

我有一个将字符串列表作为参数的例程,但我想支持传入单个字符串并将其转换为一个字符串列表。例如:

def func( files ):
    for f in files:
        doSomethingWithFile( f )

func( ['file1','file2','file3'] )

func( 'file1' ) # should be treated like ['file1']

我的函数如何判断传入的是字符串还是列表?我知道有一个type 函数,但有没有“更pythonic”的方式?

【问题讨论】:

    标签: python list duck-typing


    【解决方案1】:
    isinstance(your_var, basestring)
    

    【讨论】:

    • 这个解决方案需要一些解释,一些上下文。 your_var 和 basestring 都不在 OP 的帖子中。
    • 这在 Python 3 中不起作用。使用 isinstance(your_var, str)
    • 其他 cmets 也很搞笑也不起作用。导入 6 并检查它是否是一个字符串,用于 python2 和 3 的兼容性以及 python2 中的 utf 字符串支持
    【解决方案2】:

    好吧,检查类型并没有什么不合时宜的。话虽如此,如果您愿意给调用者增加一点负担:

    def func( *files ):
        for f in files:
             doSomethingWithFile( f )
    
    func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
    func( 'file1' )
    

    我认为这更像是 Pythonic,因为“显式优于隐式”。当输入已经是列表形式时,调用者至少可以识别。

    【讨论】:

    • 当然更“明确”的方法是要求用户在列表中传递单个文件?像 func(['file1'])
    • 我同意这是明确的,但我不明白它是如何更明确的。两种技术都使用相同的逻辑;一个是另一个的相反。我碰巧觉得上面说的稍微直观一点,因为它强调的是列表中的文件而不是列表本身与func相关。
    【解决方案3】:

    就我个人而言,我不太喜欢这种行为——它会干扰鸭子打字。有人可能会争辩说,它不遵守“显式胜于隐式”的口头禅。为什么不使用可变参数语法:

    def func( *files ):
        for f in files:
            doSomethingWithFile( f )
    
    func( 'file1', 'file2', 'file3' )
    func( 'file1' )
    func( *listOfFiles )
    

    【讨论】:

    • “我个人不太喜欢这种行为”,具体指的是什么?
    • @nemo 我认为他的意思是原始问题,这可以解释为要求一个函数,其参数是字符串或字符串列表,其中函数调用没有提及哪种类型的参数是通过了。我同意这一点。
    • FWIW,varargs 仅在没有其他 args 时才有效:func(file, someflag),如果不将 someflag 转换为关键字 arg,则无法转换为 func(*files, someflag)
    【解决方案4】:

    我会说最 Python 的方式是让用户总是传递一个列表,即使其中只有一个项目。这很明显func() 可以获取文件列表

    def func(files):
        for cur_file in files:
            blah(cur_file)
    
    func(['file1'])
    

    正如 Dave 所建议的,您可以使用 func(*files) 语法,但我从不喜欢这个功能,而且只需要一个列表似乎更明确(“显式优于隐式”)。它还将您的特殊情况(使用单个文件调用 func)转换为默认情况,因为现在您必须使用额外的语法来使用列表调用 func..

    如果您确实想为作为字符串的参数设置特殊情况,请使用isinstance() builtin,并与basestringstr()unicode() 均源自)进行比较,例如:

    def func(files):
        if isinstance(files, basestring):
            doSomethingWithASingleFile(files)
        else:
            for f in files:
                doSomethingWithFile(f)
    

    真的,我建议只需要一个列表,即使只有一个文件(毕竟,它只需要两个额外的字符!)

    【讨论】:

    • 问题在于,如果你在这里只依赖duck 输入,那么字符串 被视为带有duck 输入的列表,并且不会做正确的事情。 python 不会将其视为单个项目,而是将字符串视为字符列表。呜呜呜。
    • 请注意,Python 3 没有basestring。使用str,除非你指的是一个字节对象(你绝对不应该在这个用例中使用它)。
    【解决方案5】:
    if hasattr(f, 'lower'): print "I'm string like"
    

    【讨论】:

    • 一个非常简单的解决方案,非常适合我。谢谢!
    • 直到有人将带有lower 方法的集合传递给您之前有效:-/
    • ^ 例如数学对象,或与现实世界功能(例如升高或降低机械控制的窗户)交互的对象。 :)
    • casefold 方法可能更像字符串
    • 这可能不像其他人指出的那样最健壮,但它确实非常适合鸭子打字。
    【解决方案6】:
    def func(files):
        for f in files if not isinstance(files, basestring) else [files]:
            doSomethingWithFile(f)
    
    func(['file1', 'file2', 'file3'])
    
    func('file1')
    

    【讨论】:

    • POP 8 似乎更喜欢 isinstance(u'abc', basestring) 而不是使用 types 模块。
    • @mdorseif:我已编辑答案以使用 basestring 而不是 types 模块。
    【解决方案7】:

    如果您对呼叫者有更多控制权,那么其他答案之一会更好。在我的情况下,我没有那么奢侈,所以我选择了以下解决方案(带有警告):

    def islistlike(v):
       """Return True if v is a non-string sequence and is iterable. Note that
       not all objects with getitem() have the iterable attribute"""
       if hasattr(v, '__iter__') and not isinstance(v, basestring):
           return True
       else:
           #This will happen for most atomic types like numbers and strings
           return False
    

    这种方法适用于您正在处理一组已知的满足上述条件的类似列表的类型的情况。但是会遗漏一些序列类型。

    【讨论】:

      【解决方案8】:

      Varargs 让我很困惑,所以我在 Python 中对其进行了测试,以便自己解决。

      首先,可变参数的 PEP 是 here

      这里是示例程序,基于 Dave 和 David Berger 的两个答案,后面是输出,只是为了澄清。

      def func( *files ):
          print files
          for f in files:
              print( f )
      
      if __name__ == '__main__':
          func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
          func( 'onestring' )
          func( 'thing1','thing2','thing3' )
          func( ['stuff1','stuff2','stuff3'] )
      

      以及由此产生的输出;

      ('file1', 'file2', 'file3')
      file1
      file2
      file3
      ('onestring',)
      onestring
      ('thing1', 'thing2', 'thing3')
      thing1
      thing2
      thing3
      (['stuff1', 'stuff2', 'stuff3'],)
      ['stuff1', 'stuff2', 'stuff3']
      

      希望这对其他人有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-22
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        • 2012-07-05
        • 1970-01-01
        • 2010-11-06
        • 2012-08-29
        相关资源
        最近更新 更多