61

文字列のリストをパラメータとして受け取るルーチンがありますが、単一の文字列を渡して、それを1つの文字列のリストに変換することをサポートしたいと思います。例えば:

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

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

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

文字列またはリストが渡されたかどうかを関数はどのように判断できますか?関数があることは知っていtypeますが、「もっとpythonic」な方法はありますか?

4

8 に答える 8

40
isinstance(your_var, basestring)
于 2009-05-07T18:57:40.530 に答える
37

さて、タイプをチェックすることについて非Python的なことは何もありません。そうは言っても、発信者に小さな負担をかける気がある場合は、次のようにします。

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

func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
func( 'file1' )

これは、「暗黙的よりも明示的の方が優れている」という点で、よりPython的であると私は主張します。ここでは、入力がすでにリスト形式になっている場合、少なくとも発信者の側で認識があります。

于 2009-05-07T18:58:29.903 に答える
32

個人的には、この種の行動はあまり好きではありません。ダックタイピングの妨げになります。「明示的は暗黙的よりも優れている」というマントラに従わないと主張する人もいるかもしれません。varargs構文を使用しないのはなぜですか。

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

func( 'file1', 'file2', 'file3' )
func( 'file1' )
func( *listOfFiles )
于 2009-05-07T18:58:58.810 に答える
16

Pythonの最も良い方法は、アイテムが1つしかない場合でも、ユーザーが常にリストを渡すようにすることです。それは本当にfunc()ファイルのリストを取ることができることを明らかにします

def func(files):
    for cur_file in files:
        blah(cur_file)

func(['file1'])

Daveが提案したように、構文を使用することもできますfunc(*files)が、私はこの機能が好きではありませんでした。単にリストを要求する方が明示的(「明示的は暗黙的よりも優れている」)のようです。また、リストfuncを使用して呼び出すには追加の構文を使用する必要があるため、特殊なケース(単一のファイルで呼び出す)がデフォルトのケースに変わります。func

引数が文字列であるという特殊なケースを作成したい場合は、isinstance()組み込みのを使用して、たとえば次のように比較しますbasestring(両方ともstr()派生unicode())。

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

実際には、ファイルが1つしかない場合でも、リストを要求することをお勧めします(結局、余分な文字は2つしか必要ありません!)

于 2009-05-07T19:24:29.747 に答える
13
if hasattr(f, 'lower'): print "I'm string like"
于 2009-05-07T23:42:28.300 に答える
11
def func(files):
    for f in files if not isinstance(files, basestring) else [files]:
        doSomethingWithFile(f)

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

func('file1')
于 2009-05-08T02:25:58.503 に答える
6

発信者をより細かく制御できる場合は、他の回答の1つが適しています。私の場合、そのような贅沢はないので、次の解決策に決めました(注意が必要です)。

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

このアプローチは、上記の基準を満たすリストのようなタイプの既知のセットを処理している場合に機能します。ただし、一部のシーケンスタイプは見落とされます。

于 2012-06-19T17:46:39.093 に答える
3

Varargsは私にとって混乱を招いたので、Pythonでテストして、自分で解決しました。

まず、varargsのPEPはここにあります。

これは、明確にするために、DaveとDavid Bergerからの2つの回答に基づいたサンプルプログラムと、それに続く出力です。

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']

これが他の誰かに役立つことを願っています。

于 2009-05-08T01:24:14.203 に答える