python判断一个对象是否可迭代_python - 在Python中,如何确定对象是否可迭代? - includeStdio...
有沒有像isiterable?我目前找到的唯一解決方案就是打電話
hasattr(myObj, '__iter__')
但我不確定這是多么的愚蠢。
檢查__iter__序列類型的工作,但是它會(huì)在例如Python 2中的字符串上失敗。我想知道正確的答案,在那之前,這里有一種可能性(也可以在字符串上工作):
try:some_object_iterator=iter(some_object)
except TypeError aste:
printsome_object, 'is not iterable'
該方法的iter內(nèi)置檢查__iter__或字符串__getitem__方法的內(nèi)置檢查。
另一種普遍的pythonic方法是假設(shè)一個(gè)可迭代的,然后優(yōu)雅地失敗,如果它不能在給定的對(duì)象上工作。Python詞匯表:
Pythonic編程風(fēng)格通過檢查它的方法或?qū)傩院灻皇峭ㄟ^與某些類型對(duì)象的顯式關(guān)系來確定對(duì)象的類型(“如果它看起來像鴨子和鴨子一樣,它肯定是鴨子。”)通過強(qiáng)調(diào)接口而不是特定類型,精心設(shè)計(jì)的代碼通過允許多態(tài)替代來提高其靈活性。鴨子鍵入避免使用type()或isinstance()進(jìn)行測試。相反,它通常采用EAFP(容易提出寬恕而不是權(quán)限)編程風(fēng)格。
…
try:_= (eforeinmy_object)
except TypeError:
printmy_object, 'is not iterable'
該collections模塊提供了一些抽象基類,它允許詢問類或?qū)嵗欠裉峁┨囟üδ?#xff0c;例如:
importcollectionsifisinstance(e,collections.Iterable):
# e is iterable
但是,這并不檢查可迭代的類__getitem__。
鴨子打字
try:iterator=iter(theElement)
except TypeError:
# not iterable
else:
# iterable
# for obj in iterator:
# pass
類型檢查
使用抽象基類。他們至少需要Python 2.6,并且僅適用于新式類。
importcollectionsifisinstance(theElement,collections.Iterable):
# iterable
else:
# not iterable
但是,iter()如文檔所述,它更可靠一些:
檢查isinstance(obj, Iterable)檢測到已注冊(cè)為Iterable或具有__iter__()方法的類,但未檢測到與該__getitem__()?方法重復(fù)的類。確定對(duì)象是否可迭代的唯一可靠方法是調(diào)用iter(obj)。
我想闡明的相互多一點(diǎn)光iter,__iter__并__getitem__會(huì)發(fā)生什么窗簾后面。有了這些知識(shí),你就能明白為什么你能做的最好
try:iter(maybe_iterable)
print('iteration will probably work')
except TypeError:
print('not iterable')
我將首先列出事實(shí),然后快速提醒您for在Python中使用循環(huán)時(shí)會(huì)發(fā)生什么,然后進(jìn)行討論以說明事實(shí)。
事實(shí)
如果滿足以下至少一個(gè)條件o,則可以調(diào)用任何對(duì)象的迭代器iter(o):
a)返回一個(gè)迭代器對(duì)象o的__iter__方法。迭代器是帶有__iter__和__next__(Python 2?:)方法的任何對(duì)象next。
b)o有一個(gè)__getitem__方法。
檢查Iterableor?的實(shí)例Sequence或檢查屬性__iter__是不夠的。
如果一個(gè)對(duì)象o只實(shí)現(xiàn)__getitem__,但不是__iter__,iter(o)將構(gòu)建嘗試從取物品的迭代器o由整數(shù)索引,開始于索引0。迭代器將捕獲任何IndexError被提升(但沒有其他錯(cuò)誤),然后使StopIteration本身。
從最一般意義上說,沒有辦法檢查返回的迭代器是否iter理智,而不是嘗試它。
如果一個(gè)對(duì)象o實(shí)現(xiàn)__iter__,該iter函數(shù)將確保返回的對(duì)象__iter__是一個(gè)迭代器。如果一個(gè)對(duì)象只實(shí)現(xiàn),沒有理智檢查__getitem__。
__iter__勝。如果一個(gè)對(duì)象o同時(shí)實(shí)現(xiàn)了__iter__和__getitem__,iter(o)將調(diào)用__iter__。
如果您想讓自己的對(duì)象可迭代,請(qǐng)始終實(shí)施該__iter__方法。
for?循環(huán)
為了跟隨,您需要了解for在Python中使用循環(huán)時(shí)會(huì)發(fā)生什么。如果您已經(jīng)知道,請(qǐng)隨意跳到下一節(jié)。
當(dāng)你使用for item in o某個(gè)可迭代對(duì)象時(shí)o,Python會(huì)調(diào)用iter(o)并期待一個(gè)迭代器對(duì)象作為返回值。迭代器是實(shí)現(xiàn)__next__(或next在Python 2中)方法和__iter__方法的任何對(duì)象。
按照慣例,__iter__迭代器的方法應(yīng)該返回對(duì)象本身(即return self)。Python然后調(diào)用next迭代器直到StopIteration被引發(fā)。所有這些都隱含地發(fā)生,但下面的演示使其可見:
importrandomclass DemoIterable(object):
def__iter__(self):
print('__iter__ called')
return DemoIterator()
class DemoIterator(object):
def__iter__(self):
returnselfdef__next__(self):
print('__next__ called')r=random.randint(1, 10)
ifr== 5:
print('raising StopIteration')
raise StopIteration
returnr
迭代遍歷DemoIterable:
>>>di= DemoIterable()
>>> forxindi:
... print(x)
...__iter__ called
__next__ called9__next__ called8__next__ called10__next__ called3__next__ called10__next__ called
raisingStopIteration
討論和插圖
在第1點(diǎn)和第2點(diǎn):獲得迭代器和不可靠的檢查
考慮以下課程:
class BasicIterable(object):
def__getitem__(self,item):
ifitem== 3:
raise IndexError
returnitem
調(diào)用iter一個(gè)實(shí)例BasicIterable將會(huì)返回一個(gè)沒有任何問題的迭代器,因?yàn)锽asicIterableimplements?__getitem__。
>>>b= BasicIterable()
>>>iter(b)
但是,重要的是要注意,b它沒有__iter__屬性,并且不被視為Iterable或的一個(gè)實(shí)例Sequence:
>>> fromcollectionsimport Iterable, Sequence
>>>hasattr(b, '__iter__')
False
>>>isinstance(b, Iterable)
False
>>>isinstance(b, Sequence)
False
這就是為什么Luciano Ramalho的Fluent Python推薦調(diào)用iter和處理潛在性,TypeError作為檢查對(duì)象是否可迭代的最準(zhǔn)確的方法。直接從書中引用:
從Python 3.4開始,檢查對(duì)象x是否可迭代的最準(zhǔn)確的方法是調(diào)用iter(x)并處理TypeError異常(如果不是)。這比使用更準(zhǔn)確isinstance(x, abc.Iterable),因?yàn)樗黫ter(x)也考慮了傳統(tǒng)__getitem__方法,而IterableABC則沒有。
在第3點(diǎn):迭代只提供的對(duì)象__getitem__,但不是__iter__
BasicIterable按照期望對(duì)工作實(shí)例進(jìn)行迭代:Python構(gòu)造一個(gè)迭代器,它嘗試通過索引從零開始提取項(xiàng)目,直到IndexError引發(fā)為止。演示對(duì)象的__getitem__方法只是返回由返回的迭代器item提供的參數(shù)。__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 "",line1, in
StopIteration
需要注意的是,迭代器拋出StopIteration時(shí),它不能返回的下一個(gè)項(xiàng)目,而且IndexError它提高了item == 3內(nèi)部處理。這就是為什么在循環(huán)BasicIterable使用for循環(huán)按預(yù)期工作:
>>> forxinb:
... print(x)
...
0
1
2
下面是另一個(gè)例子,以便iter通過索引來訪問迭代器返回的概念。WrappedDict不從繼承dict,這意味著實(shí)例不會(huì)有__iter__方法。
class WrappedDict(object): # note: no inheritance from dict!
def__init__(self,dic):self._dict=dicdef__getitem__(self,item):
try:
returnself._dict[item] # delegate to dict.__getitem__
except KeyError:
raise IndexError
請(qǐng)注意,調(diào)用__getitem__是委托給dict.__getitem__的,方括號(hào)表示法只是簡寫。
>>>w= WrappedDict({-1: 'not printed',
... 0: 'hi', 1: 'StackOverflow', 2: '!',
... 4: 'not printed',
... 'x': 'not printed'})
>>> forxinw:
... print(x)
...hiStackOverflow
!
在第4點(diǎn)和第5點(diǎn):iter它調(diào)用時(shí)檢查迭代器__iter__:
何時(shí)iter(o)調(diào)用對(duì)象o,iter將確保返回值(__iter__如果方法存在)是迭代器。這意味著返回的對(duì)象必須實(shí)現(xiàn)__next__(或next在Python 2中)和__iter__。iter不能對(duì)僅提供的對(duì)象執(zhí)行任何理智檢查__getitem__,因?yàn)樗鼰o法檢查對(duì)象的項(xiàng)是否可以通過整數(shù)索引訪問。
class FailIterIterable(object):
def__iter__(self):
returnobject() # not an iterator
class FailGetitemIterable(object):
def__getitem__(self,item):
raise Exception
請(qǐng)注意,從FailIterIterable實(shí)例構(gòu)造一個(gè)迭代器會(huì)立即失敗,同時(shí)從FailGetItemIterable成功構(gòu)建一個(gè)迭代器,但會(huì)在第一次調(diào)用時(shí)拋出一個(gè)Exception?__next__。
>>>fii= FailIterIterable()
>>>iter(fii)
Traceback (most recent call last):
File "",line1, in
TypeError:iter()returned non-iterator of type'object'
>>>
>>>fgi= FailGetitemIterable()
>>>it=iter(fgi)
>>>next(it)
Traceback (most recent call last):
File "",line1, in
File "/path/iterdemo.py",line42, in__getitem__raise Exception
Exception
在第6點(diǎn):__iter__勝利
這一個(gè)很簡單。如果一個(gè)對(duì)象實(shí)現(xiàn)__iter__和__getitem__,iter將調(diào)用__iter__。考慮以下課程
class IterWinsDemo(object):
def__iter__(self):
returniter(['__iter__', 'wins'])
def__getitem__(self,item):
return ['__getitem__', 'wins'][item]
以及循環(huán)實(shí)例時(shí)的輸出:
>>>iwd= IterWinsDemo()
>>> forxiniwd:
... print(x)
...__iter__
wins
在第7點(diǎn):你的迭代類應(yīng)該實(shí)現(xiàn)?__iter__
你可能會(huì)問自己,為什么大多數(shù)內(nèi)建序列像是在足夠的時(shí)候list實(shí)現(xiàn)一種__iter__方法__getitem__。
class WrappedList(object): # note: no inheritance from list!
def__init__(self,lst):self._list=lstdef__getitem__(self,item):
returnself._list[item]
畢竟,在重復(fù)上面的類,它代表調(diào)用的情況下__getitem__,以list.__getitem__(使用方括號(hào)),將正常工作:
>>>wl= WrappedList(['A', 'B', 'C'])
>>> forxinwl:
... print(x)
...A
B
C
你的自定義迭代應(yīng)該實(shí)現(xiàn)的原因__iter__如下:
如果你實(shí)現(xiàn)了__iter__,實(shí)例將被認(rèn)為是可迭代的,并且isinstance(o, collections.Iterable)會(huì)返回True。
如果返回的對(duì)象__iter__不是迭代器,iter將立即失敗并引發(fā)一個(gè)TypeError。
__getitem__出于向后兼容性的原因存在特殊處理。從Fluent Python再次引用:
這就是為什么任何Python序列都是可迭代的:它們都實(shí)現(xiàn)了__getitem__。實(shí)際上,標(biāo)準(zhǔn)序列也可以實(shí)現(xiàn)__iter__,而且你也應(yīng)該這樣做,因?yàn)開_getitem__為了向后兼容的原因存在特殊的處理,并且可能在將來消失(盡管在我寫這篇文章時(shí)不會(huì)棄用)。
總結(jié)
以上是生活随笔為你收集整理的python判断一个对象是否可迭代_python - 在Python中,如何确定对象是否可迭代? - includeStdio...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android手机上使用Socks5全局
- 下一篇: python的线程组怎么写_Python