web-dev-qa-db-ja.com

python変数が文字列であるかリストであるかをどのように確認できますか?

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

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

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

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

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

61
Graeme Perrow

まあ、型をチェックすることについて何も異常なことはありません。そうは言っても、もしあなたが発信者に小さな負担をかけたければ、

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

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

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

37
David Berger
isinstance(your_var, basestring)
43
Ayman Hourieh

個人的に、私はこの種の振る舞いは本当に好きではありません-それはアヒルのタイピングを妨げます。 「明示的なものは暗黙的なものよりも優れている」というマントラに従わないと主張することができます。 varargs構文を使用しない理由:

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

func( 'file1', 'file2', 'file3' )
func( 'file1' )
func( *listOfFiles )
32
Dave

Pythonの一番の方法は、リストに項目が1つしかない場合でも、ユーザーに常にリストを渡すようにすることです。 func()がファイルのリストを取ることができることを本当に明白にします

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

func(['file1'])
_

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

引数が文字列である特殊なケースを作成したい場合は、 isinstance() builtin を使用し、basestring(両方ともstr()およびunicode()は、例えば)から派生します):

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

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

16
dbr
def func(files):
    for f in files if not isinstance(files, basestring) else [files]:
        doSomethingWithFile(f)

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

func('file1')
11
jfs
if hasattr(f, 'lower'): print "I'm string like"
11
limscoder

発信者をより細かく制御できる場合は、他の回答のいずれかが優れています。私の場合、そんな贅沢はないので、次の解決策に注意しました(注意事項があります):

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

このアプローチは、上記の条件を満たすリストのようなタイプの既知のセットを扱う場合に有効です。ただし、一部のシーケンスタイプは失われます。

6
Dana the Sane

Varargsは私を混乱させていたので、Pythonでテストして、自分で解決できるようにしました。

まず、可変引数のPEPは here です。

以下に、DaveとDavid Bergerの2つの回答に基づいたサンプルプログラムを示します。

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

if __== '__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']

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

3
James McMahon