465

これは、入力がlist/ tuple-であるが、ではないことを確認するために私が通常行うことstrです。関数が誤ってオブジェクトを渡すバグに何度も遭遇したためstr、ターゲット関数はそれが実際にはまたはであるとfor x in lst想定します。lstlisttuple

assert isinstance(lst, (list, tuple))

私の質問は:これを達成するためのより良い方法はありますか?

4

19 に答える 19

332

Python 2のみ(Python 3ではない):

assert not isinstance(lst, basestring)

実際にはあなたが望むものです。さもなければ、リストのように機能するが、listまたはのサブクラスではない多くのものを見逃してしまいますtuple

于 2009-12-02T18:56:51.637 に答える
174

Pythonでは「ダックタイピング」を使用したいことを忘れないでください。したがって、リストのように機能するものはすべてリストとして扱うことができます。したがって、リストのタイプをチェックするのではなく、リストのように機能するかどうかを確認してください。

しかし、文字列もリストのように機能し、多くの場合、それは私たちが望んでいることではありません。それも問題になることがあります!したがって、文字列を明示的にチェックしますが、ダックタイピングを使用します。

これが私が楽しみのために書いた関数です。repr()これは、任意のシーケンスを山かっこ('<'、'>')で印刷する特別なバージョンです。

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

これは全体的にクリーンでエレガントです。しかし、そのisinstance()チェックはそこで何をしているのでしょうか?それは一種のハックです。しかし、それは不可欠です。

この関数は、リストのように機能するものに対して再帰的に自分自身を呼び出します。文字列を特別に処理しなかった場合、リストのように扱われ、一度に1文字ずつ分割されます。しかし、再帰呼び出しは各文字をリストとして処理しようとします-そしてそれは機能します!1文字の文字列でもリストとして機能します!関数は、スタックがオーバーフローするまで再帰的に呼び出し続けます。

このような関数は、実行する作業を分解する各再帰呼び出しに依存し、特殊なケースの文字列を使用する必要があります。これは、1文字の文字列、さらには1文字の文字列のレベルより下の文字列を分解できないためです。 -文字列はリストのように機能します。

注:try/exceptは、私たちの意図を表現するための最もクリーンな方法です。しかし、このコードが何らかの形でタイムクリティカルである場合は、それをある種のテストに置き換えて、argがシーケンスであるかどうかを確認することをお勧めします。タイプをテストするのではなく、おそらく動作をテストする必要があります。メソッドがある場合.strip()は文字列なので、シーケンスとは見なさないでください。それ以外の場合、インデックス可能または反復可能である場合、それはシーケンスです。

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

編集:私はもともと上記をチェックして書いたが、モジュールのドキュメントで興味深い方法は;__getslice__()であることに気づいた。これは理にかなっています、それはあなたがオブジェクトにインデックスを付ける方法です。それはそれよりも根本的なように思われるので、私は上記を変更しました。collections__getitem__()__getslice__()

于 2009-12-02T19:30:13.903 に答える
124
H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.
于 2014-02-03T08:48:45.470 に答える
95

Python 3:

import collections.abc

if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
    print("`obj` is a sequence (list, tuple, etc) but not a string or a dictionary.")

バージョン3.3で変更:「CollectionsAbstractBaseClasses」のグローバル名前空間をabcからcollections.abcモジュールに移動しました。下位互換性のために、バージョン3.8で動作が停止するまで、このモジュールでも引き続き表示されます。

Python 2:

import collections

if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
    print "`obj` is a sequence (list, tuple, etc) but not a string or unicode or dictionary."
于 2016-06-15T17:46:47.047 に答える
38

PHPフレーバーのPython:

def is_array(var):
    return isinstance(var, (list, tuple))
于 2011-05-11T23:30:04.550 に答える
11

一般的に言って、オブジェクトを反復処理する関数が文字列だけでなくタプルやリストでも機能するという事実は、バグよりも機能です。あなたは確かに引数をチェックするためにタイピングを使うかダックタイピングすることができisinstanceます、しかしなぜあなたはそうするべきですか?

それは修辞的な質問のように聞こえますが、そうではありません。「なぜ引数の型をチェックする必要があるのか​​」に対する答え。おそらく、知覚された問題ではなく、実際の問題の解決策を提案するでしょう。文字列が関数に渡されるときにバグになるのはなぜですか?また、文字列がこの関数に渡されたときのバグである場合、他の非リスト/タプルの反復可能オブジェクトがこの関数に渡された場合のバグでもありますか?なぜ、またはなぜそうではないのですか?

この質問に対する最も一般的な答えは、作成する開発者f("abc")が、関数が作成したかのように動作することを期待していることだと思いf(["abc"])ます。文字列内の文字を反復処理するユースケースをサポートするよりも、開発者を自分自身から保護する方が理にかなっている状況がおそらくあります。しかし、私は最初にそれについて長くそして一生懸命に考えるでしょう。

于 2009-12-02T20:33:02.363 に答える
10

読みやすさとベストプラクティスのためにこれを試してください。

Python2- isinstance()

import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
    # Do something

Python3- isinstance()

import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
    # Do something

それが役に立てば幸い。

于 2018-01-01T07:03:03.620 に答える
5

オブジェクトに属性strがありません__iter__

>>> hasattr('', '__iter__')
False 

だからあなたはチェックをすることができます

assert hasattr(x, '__iter__')

そして、これはAssertionError他の反復不可能なオブジェクトにも良い結果をもたらします。

編集: ティムがコメントで述べているように、これはpython 2.xでのみ機能し、3.xでは機能しません

于 2009-12-02T19:15:52.710 に答える
5

これはOPに直接回答することを意図したものではありませんが、いくつかの関連するアイデアを共有したいと思いました。

上記の@stevehaの回答に非常に興味がありました。これは、ダックタイピングが壊れているように見える例を示しているようです。しかし、考え直してみると、彼の例は、ダックタイピングに準拠するのが難しいことを示唆していますが、特別な処理に値することを示唆していません。str

結局のところ、非str型(たとえば、いくつかの複雑な再帰構造を維持するユーザー定義型)は、@stevehasrepr関数に無限の再帰を引き起こす可能性があります。確かにこれはかなりありそうもないことですが、この可能性を無視することはできません。したがって、特別なケースstrではなく、無限再帰が発生したときにsrepr何をしたいのかを明確にする必要があります。srepr

srepr合理的なアプローチの1つは、その瞬間に再帰を単純に中断することであるように思われるかもしれませんlist(arg) == [arg]。これは、実際にはstr、を使用せずに、を使用して問題を完全に解決しますisinstance

ただし、非常に複雑な再帰構造では、発生しlist(arg) == [arg]ない無限ループが発生する可能性があります。したがって、上記のチェックは便利ですが、それだけでは不十分です。再帰の深さを厳しく制限するようなものが必要です。

私のポイントは、任意の引数タイプを処理することを計画している場合、strダックタイピングによる処理は(理論的に)遭遇する可能性のあるより一般的なタイプを処理するよりもはるかに簡単であるということです。したがって、strインスタンスを除外する必要があると感じた場合は、代わりに、引数が明示的に指定した数少ないタイプの1つのインスタンスであることを要求する必要があります。

于 2012-10-29T07:42:20.650 に答える
5

私はtensorflowでis_sequenceという名前のそのような関数を見つけました。

def is_sequence(seq):
  """Returns a true if its input is a collections.Sequence (except strings).
  Args:
    seq: an input sequence.
  Returns:
    True if the sequence is a not a string and is a collections.Sequence.
  """
  return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))

そして、私はそれがあなたのニーズを満たしていることを確認しました。

于 2017-05-19T09:39:17.840 に答える
2

私は自分のテストケースでこれを行います。

def assertIsIterable(self, item):
    #add types here you don't want to mistake as iterables
    if isinstance(item, basestring): 
        raise AssertionError("type %s is not iterable" % type(item))

    #Fake an iteration.
    try:
        for x in item:
            break;
    except TypeError:
        raise AssertionError("type %s is not iterable" % type(item))

発電機でテストされていないので、発電機に渡された場合、次の「歩留まり」にとどまると思います。これは、下流で物事を台無しにする可能性があります。しかし、繰り返しになりますが、これは「ユニットテスト」です

于 2013-02-02T00:25:26.443 に答える
2

「ダックタイピング」のやり方で、どうですか

try:
    lst = lst + []
except TypeError:
    #it's not a list

また

try:
    lst = lst + ()
except TypeError:
    #it's not a tuple

それぞれ。isinstanceこれにより、 /hasattrイントロスペクションが回避されます。

逆もまた同様です。

try:
    lst = lst + ''
except TypeError:
    #it's not (base)string

すべてのバリアントは実際には変数の内容を変更しませんが、再割り当てを意味します。状況によっては、これが望ましくないかどうかはわかりません。

興味深いことに、「インプレース」割り当てでは、がリストタプルではない)の場合、どのような場合でも+=noが発生します。そのため、割り当てはこのように行われます。多分誰かがそれがなぜであるかを明らかにすることができます。TypeErrorlst

于 2018-07-18T14:25:33.373 に答える
2

文字列のようなオブジェクトを他のシーケンスのようなオブジェクトから区別するのに役立つダックタイピングの別のバージョン。

文字列のようなオブジェクトの文字列表現は文字列自体であるため、strコンストラクタから等しいオブジェクトが返されるかどうかを確認できます。

# If a string was passed, convert it to a single-element sequence
if var == str(var):
    my_list = [var]

# All other iterables
else: 
    my_list = list(var)

これは、互換性のあるすべてのオブジェクトstrおよびすべての種類の反復可能なオブジェクトに対して機能するはずです。

于 2019-12-12T00:48:48.260 に答える
1

最も簡単な方法...とを使用anyしてisinstance

>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
于 2017-12-01T09:27:19.413 に答える
0

Python3にはこれがあります:

from typing import List

def isit(value):
    return isinstance(value, List)

isit([1, 2, 3])  # True
isit("test")  # False
isit({"Hello": "Mars"})  # False
isit((1, 2))  # False

したがって、リストとタプルの両方をチェックするには、次のようになります。

from typing import List, Tuple

def isit(value):
    return isinstance(value, List) or isinstance(value, Tuple)
于 2018-08-03T20:31:37.163 に答える
0
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"
于 2019-04-17T08:39:11.717 に答える
-1

これを行うだけ

if type(lst) in (list, tuple):
    # Do stuff
于 2017-06-12T19:07:49.307 に答える
-3

Pythonで>3.6

import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False
于 2020-03-11T13:10:21.160 に答える
-6

私はこれを行う傾向があります(私が本当にそうしなければならなかった場合):

for i in some_var:
   if type(i) == type(list()):
       #do something with a list
   elif type(i) == type(tuple()):
       #do something with a tuple
   elif type(i) == type(str()):
       #here's your string
于 2009-12-02T19:59:42.467 に答える