같은 방법이 isiterable
있습니까? 내가 지금까지 찾은 유일한 해결책은 전화하는 것입니다
hasattr(myObj, '__iter__')
그러나 이것이 얼마나 바보인지 확실하지 않습니다.
답변
나는이 문제를 꽤 최근에 연구 해왔다. 내 결론은 요즘에 이것이 최선의 접근법이라는 것입니다.
from collections.abc import Iterable # drop `.abc` with Python 2.7 or lower
def iterable(obj):
return isinstance(obj, Iterable)
위의 내용은 이미 이전에 권장되었지만 일반적인 합의는 사용 iter()
이 더 낫다는 것입니다.
def iterable(obj):
try:
iter(obj)
except Exception:
return False
else:
return True
우리는 iter()
이 목적을 위해 코드에서도 사용 했지만 최근에는 __getitem__
반복 가능한 것으로 간주 되는 객체에 점점 더 화가 나기 시작했습니다 . __getitem__
반복 할 수없는 객체 를 가져야하는 유효한 이유가 있으며 위의 코드가 제대로 작동하지 않습니다. 실제 예제로 Faker 를 사용할 수 있습니다 . 위의 코드는 반복 가능하지만 실제로 반복하려고하면 AttributeError
(Faker 4.0.2에서 테스트 됨)을보고합니다.
>>> from faker import Faker
>>> fake = Faker()
>>> iter(fake) # No exception, must be iterable
<iterator object at 0x7f1c71db58d0>
>>> list(fake) # Ooops
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/.../site-packages/faker/proxy.py", line 59, in __getitem__
return self._factory_map[locale.replace('-', '_')]
AttributeError: 'int' object has no attribute 'replace'
를 사용한다면 insinstance()
우연히 Faker 인스턴스 (또는 다른 객체 만 __getitem__
)를 반복 할 수 있다고 생각하지 않습니다 .
>>> from collections.abc import Iterable
>>> from faker import Faker
>>> isinstance(Faker(), Iterable)
False
이전 대답은 사용하는 논평 iter()
에 근거했다 파이썬에서 반복을 구현하는 기존의 방법으로 안전 __getitem__
하고, isinstance()
접근 방식은 감지하지 않을 것입니다. 이것은 오래된 파이썬 버전에서는 사실 일 수 있지만 isinstance()
요즘 철저한 테스트를 기반으로 합니다. isinstance()
작동 iter()
하지 않았지만 UserDict
Python 2 를 사용할 때 와 관련된 유일한 경우입니다. 관련이있는 경우 사용할 isinstance(item, (Iterable, UserDict))
수 있습니다.
답변
-
검사는
__iter__
시퀀스 유형에서 작동하지만 Python 2의 문자열 에서는 실패합니다 . 그때까지 올바른 대답을 알고 싶습니다. 여기에는 문자열에서 작동하는 한 가지 가능성이 있습니다.from __future__ import print_function try: some_object_iterator = iter(some_object) except TypeError as te: print(some_object, 'is not iterable')
iter
위한 내장 검사__iter__
방법 또는 스트링 인 경우__getitem__
방법. -
또 다른 일반적인 pythonic 접근법은 iterable을 가정 한 다음 주어진 객체에서 작동하지 않으면 정상적으로 실패하는 것입니다. 파이썬 용어 :
그 방법 또는 속성 서명 검사를 통해서가 아니라 어떤 종류의 객체 ( “그것이 보이는 경우에 명시 적 관계에 의해 객체의 유형을 결정하는 파이썬 프로그래밍 스타일 오리 와 같은 꽥꽥 오리 , 그것은해야합니다 오리 강조 인터페이스에 의해.”) 잘 설계된 코드는 특정 유형이 아니라 다형성 대체를 허용하여 유연성을 향상시킵니다. 덕 타이핑은 type () 또는 isinstance ()를 사용한 테스트를 피합니다. 대신, 일반적으로 EAFP (권한보다 용서하기 쉬운) 스타일의 프로그래밍을 사용합니다.
…
try: _ = (e for e in my_object) except TypeError: print my_object, 'is not iterable'
-
이
collections
모듈은 몇 가지 추상 기본 클래스를 제공하여 클래스 또는 인스턴스가 특정 기능을 제공하는지 여부를 묻습니다.from collections.abc import Iterable if isinstance(e, Iterable): # e is iterable
그러나이를 통해 반복 가능한 클래스는 확인하지 않습니다
__getitem__
.
답변
오리 타자
try:
iterator = iter(theElement)
except TypeError:
# not iterable
else:
# iterable
# for obj in iterator:
# pass
타입 검사
추상 기본 클래스를 사용하십시오 . 최소한 Python 2.6이 필요하며 새로운 스타일의 클래스에서만 작동합니다.
from collections.abc import Iterable # import directly from collections for Python < 3.3
if isinstance(theElement, Iterable):
# iterable
else:
# not iterable
그러나 설명서에iter()
설명 된 것처럼 조금 더 안정적입니다 .
검사
isinstance(obj, Iterable)
는 Iterable로 등록되었거나__iter__()
메소드 가있는 클래스를 감지하지만 메소드를 반복하는 클래스는 감지하지 않습니다__getitem__()
. 객체의 반복 가능 여부를 확인하는 신뢰할 수있는 유일한 방법은을 호출하는 것iter(obj)
입니다.
답변
나는 조금의 상호 작용에 더 많은 빛 비트 창고 싶습니다 iter
, __iter__
그리고 __getitem__
어떤 커튼 뒤에 발생합니다. 그 지식으로 무장하면 왜 최선을 다할 수 있는지 이해할 수 있습니다.
try:
iter(maybe_iterable)
print('iteration will probably work')
except TypeError:
print('not iterable')
먼저 사실을 나열한 다음 for
파이썬에서 루프 를 사용할 때 발생하는 상황에 대한 간단한 알림과 함께 사실을 설명하기위한 토론을 진행합니다.
사리
-
당신은 어떤 개체에서 반복자를 얻을 수 있습니다
o
호출하여iter(o)
다음 조건 중 하나 이상이 사실이 보유하고있는 경우)를
o
이__iter__
반복자 객체를 반환하는 방법을. 이터레이터는__iter__
및__next__
(Python 2 🙂next
메서드 가있는 객체입니다 .b)
o
갖는__getitem__
방법. -
Iterable
또는 의 인스턴스를Sequence
확인하거나 속성을 확인하는__iter__
것만으로는 충분하지 않습니다. -
객체의 경우
o
구현은__getitem__
아니지만__iter__
,iter(o)
시도로부터 아이템을 취득하는 것을 반복자 구성합니다o
인덱스 0에서 시작하는 정수 인덱스를 반복자는 잡을 것IndexError
제기입니다 (하지만 다른 오류를) 다음 제기StopIteration
자체를. -
가장 일반적인 의미에서, 이터레이터가 리턴 한 반복자
iter
가 시도해 보는 것 외에 제정신 인지 여부를 확인할 수있는 방법이 없습니다 . -
객체가를
o
구현__iter__
하면이iter
함수는에 의해 반환 된 객체__iter__
가 반복자 인지 확인 합니다. 객체가 구현 만하는 경우 온 전성 검사가 없습니다__getitem__
. -
__iter__
이긴다. 객체의 경우o
구현 모두__iter__
하고__getitem__
,iter(o)
호출합니다__iter__
. -
자신의 객체를 반복 가능하게 만들려면 항상
__iter__
메소드를 구현하십시오 .
for
루프
따라 가려면 for
파이썬 에서 루프 를 사용할 때 어떤 일이 발생하는지 이해해야 합니다. 이미 알고 있다면 다음 섹션으로 바로 넘어가십시오.
for item in o
반복 가능한 객체에 사용할 때 o
Python iter(o)
은 반복자 객체를 반환 값으로 호출 하고 기대합니다. 반복자는 __next__
(또는 next
Python 2에서) 메소드와 메소드 를 구현하는 모든 객체입니다 __iter__
.
관례 적으로, __iter__
반복자 의 메소드는 객체 자체를 리턴해야합니다 (예 🙂 return self
. 그런 다음 파이썬 next
은 발생할 때까지 반복자 를 호출 합니다 StopIteration
. 이 모든 것이 암시 적으로 발생하지만 다음 데모를 통해 볼 수 있습니다.
import random
class DemoIterable(object):
def __iter__(self):
print('__iter__ called')
return DemoIterator()
class DemoIterator(object):
def __iter__(self):
return self
def __next__(self):
print('__next__ called')
r = random.randint(1, 10)
if r == 5:
print('raising StopIteration')
raise StopIteration
return r
에 대한 반복 DemoIterable
:
>>> di = DemoIterable()
>>> for x in di:
... print(x)
...
__iter__ called
__next__ called
9
__next__ called
8
__next__ called
10
__next__ called
3
__next__ called
10
__next__ called
raising StopIteration
토론과 삽화
포인트 1과 2에서 : 반복자 및 신뢰할 수없는 검사 받기
다음 수업을 고려하십시오.
class BasicIterable(object):
def __getitem__(self, item):
if item == 3:
raise IndexError
return item
iter
의 인스턴스를 호출 하면 구현 BasicIterable
하기 때문에 아무런 문제없이 반복자를 반환합니다 .BasicIterable
__getitem__
>>> b = BasicIterable()
>>> iter(b)
<iterator object at 0x7f1ab216e320>
그러나 속성이없고 또는 의 인스턴스로 간주 b
되지 않는다는 점에 유의 해야합니다 .__iter__
Iterable
Sequence
>>> from collections import Iterable, Sequence
>>> hasattr(b, '__iter__')
False
>>> isinstance(b, Iterable)
False
>>> isinstance(b, Sequence)
False
이것이 바로 Luciano Ramalho의 Fluent Python 이 객체의 반복 가능 여부를 확인하는 가장 정확한 방법으로 iter
잠재력 TypeError
을 호출 하고 처리 할 것을 권장하는 이유 입니다. 책에서 직접 인용 :
Python 3.4부터 객체
x
가 반복 가능한지 여부를 확인하는 가장 정확한 방법iter(x)
은TypeError
예외가 아닌 경우 예외 를 호출 하고 처리하는 것입니다. 이것은 사용하는 것보다 더 정확isinstance(x, abc.Iterable)
하기 때문에,iter(x)
또한 기존의 생각__getitem__
그동안, 방법을Iterable
ABC는하지 않습니다.
포인트 3 :을 제공 __getitem__
하지만 제공 하지 않는 객체에 대한 반복__iter__
BasicIterable
예상대로 작업 인스턴스를 반복 : Python은 0에서 시작하여 인덱스 IndexError
가 올라올 때까지 인덱스별로 항목을 가져 오려고 시도하는 반복자를 구성합니다 . 데모 객체의 __getitem__
메소드는로 반환 된 반복자 item
가 인수로 제공된 것을 __getitem__(self, item)
반환합니다 iter
.
>>> b = BasicIterable()
>>> it = iter(b)
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
반복자 StopIteration
는 다음 항목을 리턴 할 수없고 제기 된 항목 이 내부적으로 처리 될 때 IndexError
발생합니다 item == 3
. 이상 반복하는 이유입니다 BasicIterable
A를 for
예상대로 루프 작동 :
>>> for x in b:
... print(x)
...
0
1
2
반복자가 리턴 한 iter
항목이 색인으로 항목에 액세스 하는 방법에 대한 개념을 추진하기위한 또 다른 예가 있습니다. WrappedDict
에서 상속받지 않으므로 dict
인스턴스에 __iter__
메소드 가 없습니다 .
class WrappedDict(object): # note: no inheritance from dict!
def __init__(self, dic):
self._dict = dic
def __getitem__(self, item):
try:
return self._dict[item] # delegate to dict.__getitem__
except KeyError:
raise IndexError
대괄호 표기법 __getitem__
에 dict.__getitem__
대한 호출 은 간단히 대표됩니다.
>>> w = WrappedDict({-1: 'not printed',
... 0: 'hi', 1: 'StackOverflow', 2: '!',
... 4: 'not printed',
... 'x': 'not printed'})
>>> for x in w:
... print(x)
...
hi
StackOverflow
!
지점 4와 5 : iter
호출 할 때 반복자를 확인합니다__iter__
.
때 iter(o)
객체에 대해 호출 o
, iter
의 반환 값이 있는지 확인합니다 __iter__
방법이 존재하는 경우, 반복자입니다. 이것은 반환 된 객체가 __next__
(또는 next
Python 2에서) 및을 구현해야 함을 의미합니다 __iter__
. iter
만을 제공하는 개체에 대한 모든 정신 검사를 수행 할 수 __getitem__
는 개체의 항목은 정수 인덱스에 의해 액세스 할 수 있는지 여부를 확인 할 수있는 방법이 없기 때문.
class FailIterIterable(object):
def __iter__(self):
return object() # not an iterator
class FailGetitemIterable(object):
def __getitem__(self, item):
raise Exception
FailIterIterable
인스턴스 에서 반복자를 생성 하면 즉시 실패 FailGetItemIterable
하지만 반복자를 생성 하면 성공하지만에 대한 첫 번째 호출에서 예외가 발생합니다 __next__
.
>>> fii = FailIterIterable()
>>> iter(fii)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: iter() returned non-iterator of type 'object'
>>>
>>> fgi = FailGetitemIterable()
>>> it = iter(fgi)
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/iterdemo.py", line 42, in __getitem__
raise Exception
Exception
포인트 6 : __iter__
승리
이것은 간단합니다. 객체가 구현하는 경우 __iter__
와 __getitem__
, iter
호출합니다 __iter__
. 다음 클래스를 고려하십시오
class IterWinsDemo(object):
def __iter__(self):
return iter(['__iter__', 'wins'])
def __getitem__(self, item):
return ['__getitem__', 'wins'][item]
인스턴스를 반복 할 때의 출력 :
>>> iwd = IterWinsDemo()
>>> for x in iwd:
... print(x)
...
__iter__
wins
포인트 7 : 반복 가능한 클래스는 구현해야합니다. __iter__
충분할 때 메소드를 list
구현하는 것과 같은 대부분의 내장 시퀀스가 왜 필요한지 스스로에게 물어볼 수 있습니다 .__iter__
__getitem__
class WrappedList(object): # note: no inheritance from list!
def __init__(self, lst):
self._list = lst
def __getitem__(self, item):
return self._list[item]
결국, 반복 대표 호출 할 수있는 위 클래스의 인스턴스 이상 __getitem__
에 list.__getitem__
(대괄호 표기법을 사용하여) 잘 작동합니다 :
>>> wl = WrappedList(['A', 'B', 'C'])
>>> for x in wl:
... print(x)
...
A
B
C
커스텀 이터 러블이 구현해야하는 이유 __iter__
는 다음과 같습니다.
- 를 구현
__iter__
하면 인스턴스는 반복 가능한 것으로 간주되어을isinstance(o, collections.abc.Iterable)
반환True
합니다. - 에 의해 반환 된 객체
__iter__
가 반복자가 아닌 경우iter
즉시 실패 하고을 발생TypeError
시킵니다. __getitem__
이전 버전과의 호환성을 위해 특별한 처리가 있습니다. Fluent Python에서 다시 인용 :
그렇기 때문에 모든 파이썬 시퀀스가 반복 가능한 이유는 모두 구현
__getitem__
합니다. 실제로 표준 시퀀스는 또한 구현__iter__
하며,__getitem__
이전 버전과의 호환성을 위해 특수 처리가 존재하며 향후에는 사라질 수 있기 때문에 (당신 이 이것을 쓸 때 사용되지는 않지만) 표준 시퀀스도 구현 해야합니다 .
답변
이것으로 충분하지 않습니다 :에 의해 반환 된 객체 __iter__
는 반복 프로토콜 (즉, next
메소드)을 구현해야합니다 . 설명서 의 관련 섹션을 참조하십시오 .
파이썬에서 좋은 방법은 “확인”대신 “시도하고 확인”하는 것입니다.
답변
파이썬 <= 2.5에서, 당신은 할 수없고해서는 안됩니다-iterable은 “비공식적 인”인터페이스였습니다.
그러나 Python 2.6 및 3.0부터는 collections 모듈에서 사용 가능한 일부 내장 ABC와 함께 새로운 ABC (추상 기본 클래스) 인프라를 활용할 수 있습니다.
from collections import Iterable
class MyObject(object):
pass
mo = MyObject()
print isinstance(mo, Iterable)
Iterable.register(MyObject)
print isinstance(mo, Iterable)
print isinstance("abc", Iterable)
이것이 바람직하든 실제로 작동하든 이제 관습의 문제 일뿐입니다. 보시다시피 반복 불가능한 객체를 Iterable로 등록 할 수 있으며 런타임시 예외가 발생합니다. 따라서 isinstance는 “새로운”의미를 얻습니다. “선언 된”형식 호환성 만 확인하면됩니다. 이는 파이썬으로가는 좋은 방법입니다.
반면에 객체가 필요한 인터페이스를 만족시키지 못하면 어떻게해야합니까? 다음 예제를 보자.
from collections import Iterable
from traceback import print_exc
def check_and_raise(x):
if not isinstance(x, Iterable):
raise TypeError, "%s is not iterable" % x
else:
for i in x:
print i
def just_iter(x):
for i in x:
print i
class NotIterable(object):
pass
if __name__ == "__main__":
try:
check_and_raise(5)
except:
print_exc()
print
try:
just_iter(5)
except:
print_exc()
print
try:
Iterable.register(NotIterable)
ni = NotIterable()
check_and_raise(ni)
except:
print_exc()
print
객체가 기대하는 것을 만족시키지 못하면 TypeError를 던지지 만 적절한 ABC가 등록되면 검사가 유용하지 않습니다. 반대로, 만약 __iter__
메소드가 이용 가능하다면 파이썬은 자동적으로 그 클래스의 객체를 Iterable로 인식합니다.
따라서 반복 가능한 것을 기대하면 반복하고 잊어 버립니다. 반면에 입력 유형에 따라 다른 작업을 수행해야하는 경우 ABC 인프라가 매우 유용 할 수 있습니다.
답변
try:
#treat object as iterable
except TypeError, e:
#object is not actually iterable
오리가 실제로 오리인지 확인하기 위해 수표를 실행하지 말고 오리 처럼 처리하고 그렇지 않은 경우 불평하십시오.
