1

我想编写一个 Python 函数,它遍历输入参数的行,但可以接受字符串或类似文件的对象。有没有办法做到这一点?

def myfunc(x):
   for line in x:
       doSomething(line)

上面的代码适用于类似文件的对象,但不适用于字符串,我宁愿只写一个函数而不是两个,因为我的实际任务比上面的要复杂得多。

4

6 回答 6

4

使用鸭子打字:

def myfunc(x):
    try:
        lines = x.split('\n')
    except AttributeError:
        lines = x
    for line in lines:
        doSomething(line)

如果您愿意,还可以检查类型:

def myfunc(x):
    if isinstance(x, basestring):  # will work in Python >=2.3, <3.x
        lines = x.split('\n')
    else:
        lines = x
    for line in lines:
        doSomething(line)
于 2012-11-29T17:23:57.157 回答
2

您可以在这里使用大约一百万种变体try-except

def myfunc(x):
    try:
       x = x.splitlines(True)
    except AttributeError:
       pass #likely a file

    for line in x:
       doSomething(line)

另一个版本(稍微不那么宽松——见评论):

try:
   from cStringIO import StringIO
except ImportError:   #python 3
   from io import StringIO

def myfunc(x):
    try:
       x.seek(0)
    except AttributeError: #likely a string
       x = StringIO(x)

    for line in x:
       doSomething(line)
于 2012-11-29T17:24:24.400 回答
1

它也适用于字符串,但它会逐个字符地迭代字符串。用户应该使用字符串列表来调用您的函数。

如果您明确希望支持传入一个字符串,然后将其解释为一行,则必须对此进行测试:

def myfunc(x):
    if isinstance(x, basestring):
        # Interpret argument as one line
        x = [x]
    for line in x:
        doSomething(line)

或者,您可以在换行符上拆分字符串:

def myfunc(x):
    if hasattr(x, 'splitlines'):
        # Interpret argument as multiple lines:
        x = x.splitlines()
    for line in x:
        doSomething(line)
于 2012-11-29T17:23:09.783 回答
1

如果您只接受类似文件的对象,则可以指示调用者将字符串参数包装在StringIO

myfunc(StringIO(s))
于 2012-11-29T17:24:22.227 回答
0

isinstance(var, str) 检查 var 是否为 str 类型。

我不记得手头文件的类型,但您可以通过文件 var 找出答案。它将显示在 < ... >

你可以使用:

def myfunc(x):
   for line in x:
       if isinstance(line, str):
           print line
       else:
           # Its a file so do file things
于 2012-11-29T17:26:06.403 回答
0

一种方法是使用类似 isinstance 的方法来确定 x 是否为字符串。如果是,您可以将其传递给 StringIO(或 cStringIO)以使其成为像对象一样的文件,然后按照您的意愿进行操作。我没有对此进行测试,但它看起来大致如下:

def myfunc(x):
   if isinstance(x, str):
      x = StringIO.StringIO(x)
   for line in x:
      doSomething(line)
于 2012-11-29T17:48:16.117 回答