[python] 변수가 반복 가능하지만 문자열이 아니라는 것을 알려주는 방법

단일 항목 또는 이중 항목이 될 수있는 인수를받는 함수가 있습니다.

def iterable(arg)
    if #arg is an iterable:
        print "yes"
    else:
        print "no"

그래서:

>>> iterable (( "f", "f"))
예

>>> 반복 가능 ([ "f", "f"])
예

>>> iterable ( "ff")
아니

문제는 문자열이 기술적으로 반복 가능하므로 시도 할 때 ValueError를 잡을 수 없다는 것 arg[1]입니다. isinstance ()는 좋은 습관이 아니기 때문에 사용하고 싶지 않습니다.



답변

isinstance 사용 (왜 나쁜 습관인지 모르겠습니다)

import types
if not isinstance(arg, types.StringTypes):

StringTypes 사용에 유의하십시오. 모호한 유형의 문자열을 잊지 않도록합니다.

장점은 파생 된 문자열 클래스에서도 작동합니다.

class MyString(str):
    pass

isinstance(MyString("  "), types.StringTypes) # true

또한이 이전 질문을 살펴볼 수도 있습니다 .

건배.


NB : 행동이 파이썬 3으로 변경 StringTypes하고 basestring더 이상 정의되지 않습니다. 필요에 따라, 당신은에 장착 할 수 isinstance에 의해 str, 또는 부분 집합의 튜플 (str, bytes, unicode)사이 썬 사용자를위한, 예. 으로 @Theron Luhn는 했나요, 당신은 또한 사용할 수 있습니다 six.


답변

2017 년 현재 모든 버전의 Python에서 작동하는 휴대용 솔루션은 다음과 같습니다.

#!/usr/bin/env python
import collections
import six


def iterable(arg):
    return (
        isinstance(arg, collections.Iterable)
        and not isinstance(arg, six.string_types)
    )


# non-string iterables    
assert iterable(("f", "f"))    # tuple
assert iterable(["f", "f"])    # list
assert iterable(iter("ff"))    # iterator
assert iterable(range(44))     # generator
assert iterable(b"ff")         # bytes (Python 2 calls this a string)

# strings or non-iterables
assert not iterable(u"ff")     # string
assert not iterable(44)        # integer
assert not iterable(iterable)  # function


답변

추상 기본 클래스가 도입 된 Python 2.6 이후 isinstance(구체적인 클래스가 아닌 ABC에서 사용됨)는 이제 완벽하게 허용되는 것으로 간주됩니다. 구체적으로 특별히:

from abc import ABCMeta, abstractmethod

class NonStringIterable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is NonStringIterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

이것은 (의 구현 세부 사항 )에 Iterable정의 된 것과 정확히 일치하는 복사본 (클래스 이름 만 변경 )입니다 … 이것이 원하는대로 작동하는 이유 는 그렇지 않지만 후자는 문자열이 이 문 바로 다음에 명시 적 으로 호출하여 반복 가능한 것으로 간주됩니다 ._abcoll.pycollections.pycollections.IterableIterable.register(str)class

물론 정의에서 구체적으로 제외하려는 다른 클래스를 호출 하기 전에 __subclasshook__반환 하여 쉽게 확장 할 수 있습니다.Falseany

어떤 경우에, 당신은이 새로운 모듈을 가져온 후 myiter, isinstance('ciao', myiter.NonStringIterable)False, 그리고 isinstance([1,2,3], myiter.NonStringIterable)될 것입니다 True추상 기본 클래스를 정의 … 파이썬 2.6 이상이 구현 수표에 적절한 방법으로 간주됩니다 – 당신이 요청하는대로, 확인 isinstance하십시오.


답변

나는 이것이 오래된 게시물이라는 것을 알고 있지만 인터넷 후손에 대한 나의 접근 방식을 추가 할 가치가 있다고 생각했습니다. 아래 함수는 대부분의 경우 Python 2와 3 모두에서 작동하는 것 같습니다.

def is_collection(obj):
    """ Returns true for any iterable which is not a string or byte sequence.
    """
    try:
        if isinstance(obj, unicode):
            return False
    except NameError:
        pass
    if isinstance(obj, bytes):
        return False
    try:
        iter(obj)
    except TypeError:
        return False
    try:
        hasattr(None, obj)
    except TypeError:
        return True
    return False

이것은 두 번째 인수가 문자열이나 유니 코드 문자열이 아닐 때 hasattra를 TypeError발생 시키는 내장을 사용하여 (mis)에 의해 문자열이 아닌 이터 러블을 확인 합니다.


답변

이전 답변을 결합하여 다음을 사용합니다.

import types
import collections

#[...]

if isinstance(var, types.StringTypes ) \
    or not isinstance(var, collections.Iterable):

#[Do stuff...]

100 % 어리석은 증거는 아니지만 객체가 반복 가능하지 않은 경우에도 여전히 전달하고 덕 타이핑으로 돌아갈 수 있습니다.


편집 : Python3

types.StringTypes == (str, unicode). Phython3에 해당하는 것은 다음과 같습니다.

if isinstance(var, str ) \
    or not isinstance(var, collections.Iterable):


답변

2.x

나는 제안했을 것이다 :

hasattr(x, '__iter__')

또는 David Charles의 주석이 Python3에 대해 이것을 조정 한 것을 고려하여 다음과 같습니다.

hasattr(x, '__iter__') and not isinstance(x, (str, bytes))

3.x

내장 basestring추상 유형 이 제거되었습니다 . str대신 사용하십시오 . strbytes유형은 공유 기본 클래스를 보증하는 공통 기능 충분하지 않습니다.


답변

올바르게 지적했듯이 단일 문자열은 문자 시퀀스입니다.

그래서 당신이 정말로하고 싶은 것은 argisinstance 또는 type (a) == str을 사용하여 어떤 종류의 시퀀스인지 알아내는 것 입니다.

가변적 인 양의 매개 변수를 사용하는 함수를 구현하려면 다음과 같이해야합니다.

def function(*args):
    # args is a tuple
    for arg in args:
        do_something(arg)

function ( “ff”) 및 function ( “ff”, “ff”)가 작동합니다.

당신과 같은 isiterable () 함수가 필요한 시나리오를 볼 수 없습니다. 나쁜 스타일은 isinstance ()가 아니라 isinstance ()를 사용해야하는 상황입니다.