පයිතන්හිදී, වස්තුවක් නැවත ක්‍රියාත්මක කළ හැකි දැයි තීරණය කරන්නේ කෙසේද?


1113

වැනි ක්‍රමයක් isiterableතිබේද? මා මෙතෙක් සොයාගෙන ඇති එකම විසඳුම ඇමතීමයි

hasattr(myObj, '__iter__')

නමුත් මෙය කෙතරම් මෝඩකමක්දැයි මට විශ්වාස නැත.


19
__getitem__වස්තුවක් නැවත සැකසීමට ද ප්‍රමාණවත් වේ
කොස්

4
FWIW: iter(myObj)සාර්ථක වුවහොත් එය සාර්ථක වේ isinstance(myObj, dict), එබැවින් ඔබ s හෝ myObjඅනුක්‍රමයක් විය හැකි එකක් දෙස බලන්නේ නම් , ඔබ අවස්ථා දෙකේදීම සාර්ථක වනු ඇත. අනුක්‍රමයක් යනු කුමක්ද සහ නැති දේ දැන ගැනීමට ඔබට අවශ්‍ය නම් වැදගත් වන සියුම් බවක්. (පයිතන් 2 හි)dictdict
බෙන් මෝෂර්

8
__getitem__වස්තුවක් පුනරාවර්තනය කිරීමට ද එය ප්‍රමාණවත් වේ ... එය ශුන්‍ය දර්ශකයෙන් ආරම්භ වන්නේ නම් .
කාලෝස් ඒ. ගොමෙස්

Answers:


57

මම මේ ගැටලුව ගැන ටිකක් ඉගෙන ගත්තා. ඒ මත පදනම්ව මගේ නිගමනය නම් වර්තමානයේ මෙය හොඳම ප්‍රවේශය බවයි:

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__ලබා ගත නොහැකි වස්තුවක් සඳහා වලංගු හේතු ඇති අතර ඒවා සමඟ ඉහත කේතය හොඳින් ක්‍රියා නොකරයි. සැබෑ ජීවිත උදාහරණයක් ලෙස අපට ෆේකර් භාවිතා කළ හැකිය . ඉහත කේතය වාර්තා කරන්නේ එය නැවත ක්‍රියාත්මක කළ හැකි නමුත් ඇත්ත වශයෙන්ම එය නැවත සැකසීමට උත්සාහ කිරීම AttributeError(ෆේකර් 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(), අපි අහම්බෙන් ෆේකර් සිද්ධීන් (හෝ වෙනත් වස්තූන් පමණක් ඇති __getitem__) නැවත ක්‍රියාත්මක කළ හැකි යැයි නොසිතන්නෙමු.

>>> from collections.abc import Iterable
>>> from faker import Faker
>>> isinstance(Faker(), Iterable)
False

iter()පයිතන් හි පුනරාවර්තනය ක්‍රියාත්මක කිරීම සඳහා පැරණි ක්‍රමය භාවිතා කිරීම වඩා ආරක්ෂිත බව මීට පෙර පිළිතුරු වලින් අදහස් වූ __getitem__අතර isinstance()ප්‍රවේශය එය හඳුනා නොගනී. පැරණි පයිතන් අනුවාදයන් සමඟ මෙය සත්‍යයක් විය හැකි නමුත් මගේ පරිපූර්ණ පරීක්‍ෂණය මත පදනම්ව isinstance()වර්තමානයේ එය ඉතා හොඳින් ක්‍රියාත්මක වේ. පයිතන් 2 භාවිතා කරන විට isinstance()ක්‍රියා නොකළ නමුත් iter()කළ එකම අවස්ථාව එයයි. UserDictඑය අදාළ නම්, එය isinstance(item, (Iterable, UserDict))ආවරණය කිරීම සඳහා භාවිතා කළ හැකිය.


1
typing.Dictවිසින් iterable සැලකේ iter(Dict)නමුත් list(Dict)දෝෂය සමඟ අසමත් TypeError: Parameters to generic types must be types. Got 0.. අපේක්ෂිත isinstance(Dict, Iterable)ප්‍රතිලාභ අසත්‍යය.
Pekka Klärck

1
මම එකම නිගමනයකට ආ නමුත් විවිධ හේතු නිසා. භාවිතා කරමින් iter, අනවශ්ය ලෙස ප්රමාද කිරීමට "පූර්ව-ගබඩා" භාවිතා කරන අපගේ කේතය ඇතැම් විය. නම් __iter__කේතය මන්දගාමී වේ, එසේ ඉල්ලා ඇත iter... ඔබ යමක් iterable නම් බලන්න ඕන ඕනෑම අවස්ථාවක.
thorwhalen

පයිතන් 2 තවදුරටත් ඩිව්ස් විසින් සක්‍රීයව සහාය නොදක්වන බවත්, පයිතන් 3 විකල්පයක් නම් නව කේත සඳහා භාවිතා නොකළ යුතු බවත් සඳහන් කරමින්, එම අන්තිම බිටුවට සටහනක් එක් කිරීම වටී ද?
ග්ලෝයි

844
  1. __iter__අනුක්‍රමික වර්ගවල වැඩ සඳහා පරික්ෂා කිරීම , නමුත් එය පයිතන් 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__ක්රමය.

  2. තවත් පොදු පයිතොනික් ප්‍රවේශයක් නම්, නැවත ලබා ගත හැකි යැයි උපකල්පනය කිරීම, දී ඇති වස්තුව මත ක්‍රියා නොකරන්නේ නම් එය අසාර්ථක වීමයි. පයිතන් ටීකාව:

    සමහර වර්ගය වස්තුවකට වඩා එහි ක්රමය හෝ විශේෂණය අත්සන පරීක්ෂා විසින් පැහැදිලි සම්බන්ධතාවයක් මගින් වස්තුවක ගණය තීරණය බව Pythonic වැඩසටහන් ශෛලිය ( "එය වගේ නම් තාරාවන් හා සමාන හොර වෛද්යවරුන් තාරා , එය විය යුතුය තාරා .") අතුරු මුහුණත් අවධාරණය කිරීම නිශ්චිත වර්ගවලට වඩා හොඳින් සැලසුම් කරන ලද කේතයක් බහුමාමක ආදේශනයට ඉඩ දීමෙන් එහි නම්‍යශීලී බව වැඩි දියුණු කරයි. තාරා-ටයිප් කිරීම වර්ගය () හෝ සමස්ථානික () භාවිතා කරමින් පරීක්ෂණ වළක්වයි. ඒ වෙනුවට, එය සාමාන්‍යයෙන් EAFP (අවසරයට වඩා සමාව ඉල්ලීමට පහසු) ක්‍රමලේඛය භාවිතා කරයි.

    ...

    try:
       _ = (e for e in my_object)
    except TypeError:
       print my_object, 'is not iterable'
  3. මෙම collectionsමොඩියුලය උදාහරණයක් ලෙස, ඔවුන් විශේෂයෙන් පහසුකම් ලබා නම් පංති හෝ අවස්ථා අහන්න ඉඩ දෙන සමහර වියුක්ත පදනම පන්ති, සපයයි:

    from collections.abc import Iterable
    
    if isinstance(e, Iterable):
        # e is iterable

    කෙසේ වෙතත්, මෙය නැවත ලබා ගත හැකි පන්ති සඳහා පරික්ෂා නොකරයි __getitem__.


34
[e for e in my_object]වෙනත් හේතූන් මත ව්‍යතිරේකයක් මතු කළ හැකිය, එනම් my_objectනිර්වචනය නොකළ හෝ my_objectක්‍රියාත්මක කිරීමේදී ඇතිවිය හැකි දෝෂ .
නික් දන්ඩෝලාකිස්

37
නූලක් යනු අනුක්‍රමයක් ( isinstance('', Sequence) == True) වන අතර ඕනෑම අනුක්‍රමයක් ලෙස එය නැවත ක්‍රියාත්මක කළ හැකිය ( isinstance('', Iterable)). නමුත් hasattr('', '__iter__') == Falseඑය ව්‍යාකූල විය හැකිය.
jfs

83
නම් my_objectඉතා විශාල වේ (කියන්නේ, වැනි අනන්ත itertools.count()) ඔබගේ ලැයිස්තුව අවබෝධය කාලීන / මතකය ගොඩක් දක්වා ගත වනු ඇත. උත්පාදක යන්ත්රයක් සෑදීමට වඩා හොඳය, එය කිසි විටෙකත් (අනන්ත විය හැකි) ලැයිස්තුවක් තැනීමට උත්සාහ නොකරනු ඇත.
ක්‍රිස් ලුට්ස්

15
Some_object වෙනත් හේතුවක් නිසා ඇති වූ දෝෂ (දෝෂ ආදිය) ද විසි කරන්නේ නම් කුමක් කළ යුතුද ? “එය නැවත කළ නොහැකි TypeError” වෙතින් අපට එය පැවසිය හැක්කේ කෙසේද?
ෂෝං

54
Python 3: hasattr(u"hello", '__iter__')returnTrue
Carlos

578

තාරා ටයිප් කිරීම

try:
    iterator = iter(theElement)
except TypeError:
    # not iterable
else:
    # iterable

# for obj in iterator:
#     pass

පරීක්ෂා කිරීම ටයිප් කරන්න

වියුක්ත මූලික පන්ති භාවිතා කරන්න . ඔවුන්ට අවම වශයෙන් පයිතන් 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)හඳුනාගත හැකි හෝ __iter__()ක්‍රමයක් ඇති පංති අනාවරණය වේ, නමුත් එය __getitem__() ක්‍රමවේදය සමඟ නැවත ක්‍රියාත්මක වන පන්ති හඳුනා නොගනී . වස්තුවක් නැවත ක්‍රියාත්මක කළ හැකිද යන්න තීරණය කිරීමට ඇති එකම විශ්වාසදායක ක්‍රමය වන්නේ ඇමතීමයි iter(obj).


22
ලුසියානෝ රමල්හෝ විසින් රචිත “ෆ්ලූන්ට් පයිතන්” සිට: පයිතන් 3.4 වන විට, x වස්තුවක් නැවත ක්‍රියාත්මක කළ හැකිද යන්න පරීක්ෂා කිරීම සඳහා වඩාත් නිවැරදි ක්‍රමය වන්නේ එය (x) අමතා ටයිප් එෙරර් ව්‍යතිරේකයක් හැසිරවීමයි. Isinstance (x, abc.Iterable) භාවිතා කිරීමට වඩා මෙය වඩාත් නිවැරදියි, මන්ද iter (x) ද උරුමය ලබා ගැනීමේ ක්‍රමය සලකා බලන අතර Iterable ABC භාවිතා නොකරයි.
RdB

ඔබ "අනේ මම isinstance(x, (collections.Iterable, collections.Sequence))ඒ වෙනුවට යමි" යැයි සිතන්නේ iter(x)නම්, මෙය තවමත් ක්‍රියාත්මක කළ හැකි __getitem__නමුත් නොකළ හැකි වස්තුවක් හඳුනා නොගනී __len__. iter(x)ව්යතිරේකය භාවිතා කරන්න සහ අල්ලා ගන්න.
ඩේල්

ඔබගේ දෙවන පිළිතුර ක්‍රියාත්මක නොවේ. PyUNO මම කරන්න නම් iter(slide1), සියල්ල හොඳින් යයි, කෙසේ වෙතත් isinstance(slide1, Iterable)අවුලට TypeError: issubclass() arg 1 must be a class.
හායි-ඒන්ජල්

Er හයි-ඒන්ජල් PyUNOඔබේ දෝෂ පණිවිඩය issubclass()වෙනුවට පවසන බව දැනුම් දීමේ දෝෂයකි isinstance().
ජෝර්ජ් ෂෝලි

2
වස්තුවක් හරහා iter () ඇමතීම මිල අධික මෙහෙයුමක් විය හැකිය (Pytorch හි DataLoader බලන්න, එය iter () මත බහු ක්‍රියාදාමයන් ඇති කරයි / බිහි කරයි.
szali

133

මම කැමතියි තව ටිකක් ආලෝකය විහිදුවන්න iter, __iter__සහ __getitem__තිර පිටුපස සිදුවන්නේ කුමක්ද යන්න. එම දැනුමෙන් සන්නද්ධව ඔබට කළ හැකි හොඳම දේ වන්නේ මන්දැයි ඔබට තේරුම් ගත හැකිය

try:
    iter(maybe_iterable)
    print('iteration will probably work')
except TypeError:
    print('not iterable')

මම පළමුව කරුණු ලැයිස්තුගත කර පසුව ඔබ forපයිතන් වල ලූපයක් භාවිතා කරන විට සිදුවන්නේ කුමක්ද යන්න පිළිබඳ ඉක්මන් මතක් කිරීමක් කර පසුව කරුණු නිදර්ශනය කිරීම සඳහා සාකච්ඡාවක් පවත්වමි.

කරුණු

  1. ඔබ යම් වස්තුවක් සිට iterator ලබා ගත හැක oඇමතීම මගින් iter(o)පහත කොන්දේසි අවම වශයෙන් එක් සත්ය නම්:

    අ) oසතුව, __iter__ක iterator වස්තුව නැවත වන ක්රමය. Iterator යනු __iter__and සහ a __next__(Python 2 :) ක්‍රමයක් ඇති ඕනෑම වස්තුවකි next.

    ආ) oසතුව __getitem__ක්රමය.

  2. නිදසුනක් සඳහා Iterableහෝ Sequence, හෝ ගුණාංගය පරීක්ෂා කිරීම __iter__ප්‍රමාණවත් නොවේ.

  3. වස්තුවක් නම් oඋපකරණ පමණක් __getitem__, නමුත් __iter__, iter(o)උත්සාහක දිනුම් සිට භාණ්ඩ ලබා ගැනීමට බව iterator ඉදි කරන oදර්ශකය 0 ට ඇරඹෙන iterator පූර්ණ සංඛ්යාමය දර්ශකය ඕනෑම අල්ලා ඇත IndexError(නමුත් වෙනත් කිසිදු දෝෂ) මතු පසුව මතු වන බව StopIterationම.

  4. වඩාත් සාමාන්‍ය අර්ථයෙන් ගත් කල, iterඑය නැවත උත්සාහ කළ තැනැත්තා විසින් නැවත ලබා දුන් අයෙක් පරීක්ෂා කර බැලීමට හැකියාවක් තිබේද යන්න පරීක්ෂා කිරීමට ක්‍රමයක් නොමැත .

  5. වස්තුවක් oක්‍රියාත්මක කරන්නේ නම් __iter__, iterශ්‍රිතය මඟින් ආපසු ලබා දුන් වස්තුව __iter__අනුකාරකයක් බව සහතික කරයි . වස්තුවක් පමණක් ක්‍රියාත්මක කරන්නේ දැයි සනීපාරක්ෂක පරීක්‍ෂණයක් නොමැත __getitem__.

  6. __iter__ජය. වස්තුවක් නම් oඋපකරණ දෙකම __iter__හා __getitem__, iter(o)කියනු ඇත __iter__.

  7. ඔබේම වස්තූන් නැවත ක්‍රියාත්මක කිරීමට අවශ්‍ය නම්, සෑම විටම __iter__ක්‍රමය ක්‍රියාත්මක කරන්න .

for ලූප

ඉදිරියට යාම සඳහා, ඔබ forපයිතන් හි ලූපයක් භාවිතා කරන විට කුමක් සිදුවේද යන්න පිළිබඳ අවබෝධයක් අවශ්‍ය වේ. ඔබ දැනටමත් දන්නවා නම් ඊළඟ කොටසට දකුණට යාමට නිදහස් වන්න.

ඔබ for item in oකිසියම් ක්‍රියාකාරී වස්තුවක් සඳහා භාවිතා කරන විට o, පයිතන් ඇමතුම් ලබා iter(o)දෙන අතර ප්‍රතිලාභ අගය ලෙස iterator වස්තුවක් අපේක්ෂා කරයි. ඉරේටරයක් ​​යනු __next__(හෝ nextපයිතන් 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

A ට වඩා අනුමාන කිරීම 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

ඒ නිසයි හොඳින් Python Luciano Ramalho විසින් ඉල්ලා නිර්දේශ iterහැකි සහ හැසිරවීමේ TypeErrorවස්තුවක් iterable දැයි පරීක්ෂා කිරීමට වඩාත්ම නිවැරදි ක්රමයක් ලෙස. පොතෙන් කෙලින්ම උපුටා දැක්වීම:

පයිතන් 3.4 අනුව, වස්තුවක් නැවත xක්‍රියාත්මක කළ හැකිද යන්න පරීක්ෂා කිරීම සඳහා වඩාත් නිවැරදි ක්‍රමය නම්, ව්‍යතිරේකයක් නොමැති නම් එය ඇමතීම iter(x)සහ හැසිරවීමයි TypeError. මෙය භාවිතයට වඩා නිරවද්‍ය ය isinstance(x, abc.Iterable), මන්ද යත් iter(x), උරුමය __getitem__ක්‍රමය ද සලකා බලන අතර Iterableඒබීසී එසේ නොකරයි.

කරුණු 3 මත: එකම සපයන වස්තූන් එල්ලාවල මහතා __getitem__, නමුත්__iter__

BasicIterableඅපේක්ෂිත පරිදි කෘති නිදසුනක් උපුටා දැක්වීම: පයිතන් දර්ශකයක් මඟින් අයිතම ලබා ගැනීමට උත්සාහ කරන අනුකාරකයක් සාදයි, එය බිංදුවෙන් පටන් ගෙන, 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සමඟ 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__, මෙම ක්රමය දැනට නම්, යම් iterator වේ. මෙයින් අදහස් කරන්නේ ආපසු ලබා දුන් වස්තුව ක්‍රියාත්මක කළ යුතු බවයි __next__(හෝ nextපයිතන් 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__

බොහෝ builtin අනුක්රමය කැමති ඇයි ඔබ ඇසිය හැක 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__පහත පරිදි වේ:

  1. ඔබ ක්‍රියාත්මක කරන්නේ නම් __iter__, නිදසුන් පුනරාවර්තන ලෙස සලකනු isinstance(o, collections.abc.Iterable)ලබන අතර නැවත පැමිණේ True.
  2. ආපසු ලබා දුන් වස්තුව __iter__අනුකාරකයක් නොවේ නම්, iterවහාම අසමත් වී a මතු කරයි TypeError.
  3. __getitem__පසුගාමී අනුකූලතා හේතූන් මත විශේෂ හැසිරවීම පවතී. චතුර ලෙස පයිතන් වෙතින් නැවත උපුටා දැක්වීම:

ඕනෑම පයිතන් අනුක්‍රමයක් නැවත ක්‍රියාත්මක කළ හැක්කේ එබැවිනි: ඒවා සියල්ලම ක්‍රියාත්මක __getitem__වේ. ඇත්ත වශයෙන්ම, සම්මත අනුක්‍රමයන් ද ක්‍රියාත්මක වන අතර __iter__, ඔබත් එසේ කළ යුතුය, මන්දයත් විශේෂ හැසිරවීම __getitem__පසුගාමී අනුකූලතා හේතූන් මත පවතින අතර අනාගතයේ දී එය නැති වී යා හැකිය (මා මෙය ලියන විට එය ප්‍රතික්ෂේප නොකළද).


ඒ නිසා එය සංජානන නිර්වචනය කිරීම ආරක්ෂාකාරී වන අතර is_iterableනැවත විසින් Trueතුළ tryවාරණ හා Falseතුළ except TypeErrorවාරණ?
ඇලන්කල්විටි

මෙය විශිෂ්ට පිළිතුරකි. මම හිතන්නේ එය ගෙටිටම් ප්‍රොටෝකෝලයෙහි නොදැනුවත්ව හා අවාසනාවන්ත ස්වභාවය ඉස්මතු කරයි. එය කිසි විටෙකත් එකතු නොකළ යුතුය.
නීල් ජී

31

මෙය ප්‍රමාණවත් නොවේ: ආපසු ලබා දුන් වස්තුව __iter__පුනරාවර්තන ප්‍රොටෝකෝලය ක්‍රියාත්මක කළ යුතුය (එනම් nextක්‍රමය). ප්‍රලේඛනයේ අදාළ කොටස බලන්න .

පයිතන්හි, හොඳ පුරුද්දක් වන්නේ "පරීක්ෂා කිරීම" වෙනුවට "උත්සාහ කර බලන්න" යන්නයි.


9
"තාරා ටයිප් කිරීම" මම විශ්වාස කරනවාද? :)
විලෙම්

9
ill විලෙම්: හෝ "අවසර ඉල්ලන්න නොව සමාව ඉල්ලන්න" ;-)
jldupont

14
ill විලෙම් "අවසර" සහ "සමාව" යන මෝස්තර දෙකම තාරාවන්ගේ ටයිප් කිරීම සඳහා සුදුසුකම් ලබයි. ඔබ ඉල්ලා සිටින්නේ නම්, වස්තුවක් දේ කළ හැකි දේ ඒ වෙනුවට එය වඩා වේ තාරා ටයිප් බව,. ඔබ ස්වයං විචාරය භාවිතා කරන්නේ නම්, එය “අවසරය”; ඔබ එය කිරීමට උත්සාහ කර එය ක්‍රියාත්මක වේද නැද්ද යන්න බැලුවහොත් එය “සමාව දීම” වේ.
මාර්ක් රීඩ්

25

සිට Python 3.5 ඔබ භාවිතා කළ හැකිය ටයිප් වර්ගය සම්බන්ධ දේවල් සඳහා සම්මත පුස්තකාලය මොඩියුලය:

from typing import Iterable

...

if isinstance(my_item, Iterable):
    print(True)

22

පයිතන් <= 2.5 හි, ඔබට කළ නොහැකි හා නොකළ යුතු දේ - එය “අවිධිමත්” අතුරු මුහුණතක් විය.

නමුත් පයිතන් 2.6 සහ 3.0 සිට ඔබට නව ඒබීසී (වියුක්ත පාදක පන්තියේ) යටිතල පහසුකම් සහ එකතු කිරීමේ මොඩියුලයේ ඇති සමහර බිල්ඩින් ඒබීසී සමඟ ප්‍රයෝජන ගත හැකිය:

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)

දැන්, මෙය යෝග්‍යද නැතහොත් ඇත්ත වශයෙන්ම ක්‍රියාත්මක වේද යන්න සම්මුති පිළිබඳ කාරණයක් පමණි. ඔබට පෙනෙන පරිදි, ඔබට නැවත ලබා ගත නොහැකි වස්තුවක් අනුභව කළ හැකි ලෙස ලියාපදිංචි කළ හැකිය - තවද එය ධාවන වේලාවේදී ව්‍යතිරේකයක් මතු කරයි. එබැවින්, 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

වස්තුව ඔබ අපේක්ෂා කරන දේ තෘප්තිමත් නොකරන්නේ නම්, ඔබ ටයිප් එර්රර් එකක් විසි කරන්න, නමුත් නිසි ඒබීසී ලියාපදිංචි කර ඇත්නම්, ඔබේ චෙක්පත භාවිතයට ගත නොහැක. ඊට පටහැනිව, නම්__iter__ ක්‍රමවේදය තිබේ නම් පයිතන් එම පන්තියේ වස්තුව ස්වයංක්‍රීයව හඳුනාගත හැකිය.

එමනිසා, ඔබ නැවත කියවිය හැකි දෙයක් බලාපොරොත්තු වන්නේ නම්, එය නැවත නැවත අමතක කරන්න. අනෙක් අතට, ආදාන වර්ගය අනුව ඔබට විවිධ දේ කිරීමට අවශ්‍ය නම්, ඔබට ABC යටිතල ව්‍යුහය බෙහෙවින් ප්‍රයෝජනවත් විය හැකිය.


13
except:ආරම්භකයින් සඳහා උදාහරණ කේතයේ හිස් භාවිතා නොකරන්න . එය නරක පුරුදු ප්‍රවර්ධනය කරයි.
jfs


21
try:
  #treat object as iterable
except TypeError, e:
  #object is not actually iterable

ඔබේ තාරාව ඇත්තටම තාරාවෙක් දැයි බැලීමට චෙක්පත් ධාවනය නොකරන්න , එය නැවත කළ හැකි ද නැද්ද යන්න බැලීමට, එය එසේ යැයි සලකන්න සහ එය නොමැති නම් පැමිණිලි කරන්න.


3
තාක්ෂණික වශයෙන්, පුනරාවර්තනය අතරතුර ඔබේ ගණනය කිරීම මඟින් TypeErrorඔබව මෙහි විසි කර දැමිය හැකිය, නමුත් මූලික වශයෙන් ඔව්.
ක්‍රිස් ලුට්ස්

6
ill විලෙම්: කරුණාකර මිණුම් ලකුණක් කිරීමට ටයිමිට් භාවිතා කරන්න. පයිතන් ව්‍යතිරේක බොහෝ විට if-statement වලට වඩා වේගවත් වේ. ඔවුන්ට පරිවර්තකය හරහා තරමක් කෙටි මාර්ගයක් ගත හැකිය.
එස්.ලොට්

2
ill විලෙම්: අයන්පයිතන් මන්දගාමී (සීපයිතන්ට සාපේක්ෂව) ව්‍යතිරේක ඇත.
jfs

2
වැඩ කිරීමේ උත්සාහයක්: ප්‍රකාශය සැබවින්ම වේගවත්ය. එබැවින් ඔබට ව්‍යතිරේක කිහිපයක් තිබේ නම්, උත්සාහ කිරීම හැර වේගවත් වේ. ඔබ බොහෝ ව්‍යතිරේකයන් අපේක්ෂා කරන්නේ නම්, “නම්” වේගවත් විය හැකිය.
ආර්න් බාබෙන්හවුසර්හයිඩ්

2
හැර වස්තුව එකතු "විසින් අල්ලාගෙන නොකළ යුතුය as e" පසු TypeErrorඑකතු වෙනුවට විසින් " , e"?
HelloGoodbye

18

මම මෙතෙක් සොයාගෙන ඇති හොඳම විසඳුම:

hasattr(obj, '__contains__')

වස්තුව inක්‍රියාකරු ක්‍රියාත්මක කරන්නේ දැයි මූලික වශයෙන් පරීක්ෂා කරයි .

වාසි (වෙනත් විසඳුම් තුනම මේ තුනම නැත):

  • එය ප්‍රකාශනයකි ( උත්සාහයට වඩා ලැම්බඩා ලෙස ක්‍රියා කරයි ... හැර ප්‍රභේදය )
  • එය ( ප්‍රතිවිරුද්ධ ලෙස ) නූල් ද ඇතුළුව සියලු පුනරාවර්තන මඟින් ක්‍රියාත්මක කළ යුතුය__iter__
  • ඕනෑම පයිතන්> = 2.5 මත ක්‍රියා කරයි

සටහන්:

  • "සමාව ඉල්ලන්න, අවසරය නැත" යන පයිතන් දර්ශනය හොඳින් ක්‍රියාත්මක නොවේ. උදා: ලැයිස්තුවක් තුළ ඔබට පුනරාවර්තන හා අනුක්‍රමික නොවන දෙකම ඇති අතර, එක් එක් මූලද්‍රව්‍යය එහි වර්ගය අනුව වෙනස් ලෙස සැලකිය යුතුය. හැර සෙසු ක්‍රියාකාරකම් ක්‍රියාත්මක වනු ඇත , නමුත් එය බට්-කැත සහ නොමඟ යවන සුළු පෙනුමක් ඇත)
  • මෙම ගැටළුවට විසඳුම් ලබා දෙන වස්තුව (උදා: x සඳහා x සඳහා) එය නැවත ක්‍රියාත්මක කළ හැකිදැයි පරීක්ෂා කර බැලීමට විශාල පුනරාවර්තන සඳහා සැලකිය යුතු කාර්ය සාධන ද ties ුවම් ලබා දිය හැකිය (විශේෂයෙන් ඔබට නැවත සැකසිය හැකි පළමු අංග කිහිපයක් අවශ්‍ය නම්, උදාහරණ) සහ ඒවා වළක්වා ගත යුතුය

3
හොඳයි, නමුත් stackoverflow.com/questions/1952464/… හි යෝජනා කර ඇති පරිදි එකතු කිරීමේ මොඩියුලය භාවිතා නොකරන්නේ ඇයි? මට වඩා ප්‍රකාශිත බවක් පෙනේ.
ඩේව් ඒබ්‍රහම්ස්

1
කිසිදු පැහැදිලි කිරීමක් නැතිව එය කෙටි (සහ අතිරේක ආනයන අවශ්‍ය නොවේ): “අඩංගු” ක්‍රමයක් තිබීම යම් දෙයක් වස්තු එකතුවක් දැයි පරීක්ෂා කිරීමට ස්වාභාවික ක්‍රමයක් ලෙස හැඟේ.
ව්ලැඩ්

46
යම් දෙයකට යමක් අඩංගු විය හැකි නිසා එය නැවත කළ හැකි යැයි අදහස් නොකෙරේ. උදාහරණයක් ලෙස, ත්‍රිමාණ ube නකයක් තුළ ලක්ෂ්‍යයක් තිබේදැයි පරිශීලකයෙකුට පරීක්ෂා කළ හැකිය, නමුත් ඔබ මෙම වස්තුව හරහා නැවත ක්‍රියා කරන්නේ කෙසේද?
කේසි කුබල්

13
මෙය වැරදිය. ක iterable ම සහයෝගය නැත අඩංගු Python 3.4 සමග අවම වශයෙන්,.
පීටර් ෂිනර්ස්

15

ඔබට මෙය උත්සාහ කළ හැකිය:

def iterable(a):
    try:
        (x for x in a)
        return True
    except TypeError:
        return False

අපට උත්පාදක යන්ත්රයක් සෑදිය හැකි නම් (නමුත් කිසි විටෙකත් උත්පාදක යන්ත්රය භාවිතා නොකරන්න, එය ඉඩ ලබා නොගනී), එය නැවත කළ හැකිය. "ඩු" වර්ගයේ දෙයක් මෙන් පෙනේ. විචල්‍යයක් ප්‍රථමයෙන්ම ක්‍රියාත්මක කළ හැකිද යන්න ඔබ තීරණය කළ යුත්තේ ඇයි?


කුමක් ගැනද iterable(itertools.repeat(0))? :)
badp

5
adbadp, (x for x in a)යන්තම් උත්පාදක යන්ත්රයක් නිර්මාණය කරයි, එය a මත කිසිදු අනුක්රමයක් නොකරයි.
catchmeifyoutry

5
උත්සාහ කිරීම (x for x in a)හරියටම උත්සාහ කිරීමට සමානද iterator = iter(a)? එසේත් නැතිනම් දෙක එකිනෙකට වෙනස් වූ අවස්ථා තිබේද?
උපරිම

නැත for _ in a: breakවඩා පහසු? එය මන්දගාමීද?
Mr_and_Mrs_D

2
ObjectMr_and_Mrs_D පරීක්‍ෂා කරන ලද වස්තුව පසුව නැවත ක්‍රියාත්මක වන අනුකාරකයක් නම් එය නරක ය (එහි පිහිටීම නැවත සැකසිය නොහැකි බැවින් එය අයිතම 1 ක් කෙටි වනු ඇත), කසළ උත්පාදක යන්ත්ර නිර්මාණය කිරීමෙන් එම වස්තුව නැවත නැවත නොකෙරේ. එය 100% ටයිප් දෝෂයක් මතු කරයි නම් එය නැවත කළ නොහැකි බව මට විශ්වාස නැත.
Tcll

13

මම මෙහි හොඳ විසඳුමක් සොයා ගත්තා :

isiterable = lambda obj: isinstance(obj, basestring) \
    or getattr(obj, '__iter__', False)

11

අනුව Python 2 පාරිභාෂික ශබ්ද මාලාව , iterables වේ

සියලු අනුක්රමය වර්ග (වැනි list, strසහ tuple) සහ වැනි සමහර අනුක්රමය නොවන වර්ග dictහා fileහා ඔබ සමග නිර්වචනය යම් පන්තියකට වස්තු __iter__()හෝ __getitem__()ක්රමය. අනුපිළිවෙලක් අවශ්‍ය වන (සිප් (), සිතියම (), ...) සඳහා ලූප සඳහා සහ වෙනත් බොහෝ ස්ථානවල අයිටරබල්ස් භාවිතා කළ හැකිය. ප්‍රතිනිර්මාණය කළ හැකි වස්තුවක් සාදන ලද ශ්‍රිත iter () වෙත තර්කයක් ලෙස සම්මත කළ විට, එය වස්තුව සඳහා අනුකාරකයක් ලබා දෙයි.

ඇත්ත වශයෙන්ම, පයිතන් සඳහා වන සාමාන්‍ය කේතීකරණ විලාසය “අවසරයට වඩා සමාව ඉල්ලීම පහසුය” යන කාරණය මත පදනම්ව, සාමාන්‍ය අපේක්ෂාව වන්නේ භාවිතා කිරීමයි

try:
    for i in object_in_question:
        do_something
except TypeError:
    do_something_for_non_iterable

නමුත් ඔබට එය පැහැදිලිව පරීක්ෂා කිරීමට අවශ්‍ය නම්, ඔබට එය නැවත පරීක්ෂා කළ හැකිය hasattr(object_in_question, "__iter__") or hasattr(object_in_question, "__getitem__"). ඔබ ඒ දෙකම පරීක්ෂා කර බැලිය යුතුය, මන්ද strs ට __iter__ක්‍රමයක් නොමැති නිසා (අවම වශයෙන් පයිතන් 2 හි නැත, පයිතන් 3 හි ඔවුන් එසේ කරයි) සහ generatorවස්තූන් සඳහා __getitem__ක්‍රමයක් නොමැති නිසා .


8

මගේ ස්ක්‍රිප්ට් තුළ, iterableශ්‍රිතයක් අර්ථ දැක්වීමට මට බොහෝ විට පහසු වේ. (දැන් ඇල්ෆ් විසින් යෝජනා කරන ලද සරල කිරීම ඇතුළත් වේ):

import collections

def iterable(obj):
    return isinstance(obj, collections.Iterable):

එබැවින් ඕනෑම වස්තුවක් ඉතා පහසුවෙන් කියවිය හැකි ආකාරයෙන් නැවත ක්‍රියාත්මක කළ හැකිදැයි ඔබට පරීක්ෂා කළ හැකිය

if iterable(obj):
    # act on iterable
else:
    # not iterable

ඔබ callableශ්‍රිතය සමඟ කරන පරිදි

සංස්කරණය කරන්න: ඔබ අංකී ස්ථාපනය කර ඇත්නම්, ඔබට සරලවම කළ හැකිය: සිට numpy import iterable, එය හුදෙක් වැනි දෙයකි

def iterable(obj):
    try: iter(obj)
    except: return False
    return True

ඔබට අංකයක් නොමැති නම්, ඔබට මෙම කේතය හෝ ඉහත කේතය ක්‍රියාත්මක කළ හැකිය.


3
ඔබ sth වැනි සෑම විටම if x: return True else: return False( xබූලියන් වීමත් සමඟ ) ඔබට මෙය ලිවිය හැකිය return x. return isinstance(…)කිසිවක් නොමැතිව ඔබේ නඩුවේ if.
ඇල්ෆ්

ඇල්ෆේගේ විසඳුම වඩා හොඳ බව ඔබ පිළිගන්නා හෙයින්, එසේ පැවසීමට ඔබේ පිළිතුර සංස්කරණය නොකළේ මන්ද? ඒ වෙනුවට, ඔබට දැන් ඔබගේ පිළිතුරෙහි BOTH අනුවාද ඇත. අනවශ්‍ය වාචිකතාව. මෙය නිවැරදි කිරීම සඳහා සංස්කරණයක් ඉදිරිපත් කිරීම.
මෙවලම් සාදන්නා

2
ඔබ හැර “TypeError” අල්ලා ගත යුතුය. සෑම දෙයක්ම අල්ලා ගැනීම නරක රටාවකි.
මාරියස් ජම්රෝ

ඒක දන්නවා. මම එම කේත කොටස NumPy පුස්තකාලයෙන් පරිවර්තනය කළෙමි.
fmonegaglia

NumPy වෙතින් කේතයක් ගත් පමණින් එය හොඳ යැයි අදහස් නොකෙරේ ... රටාව හෝ නැත, සෑම දෙයක්ම අල්ලා ගත හැකි එකම කාලය වන්නේ ඔබ ඔබේ වැඩසටහන තුළ පැහැදිලිවම දෝෂ හැසිරවීමක් නම් පමණි.
Tcll

5

ඒ වගේ සාදන ලද ශ්‍රිතයක් ඇත:

from pandas.util.testing import isiterable

කෙසේ වෙතත් මෙය පෙනෙන්නේ __iter__අනුපිළිවෙලවල් හා ඒ හා සමාන දේ ගැන සැබවින්ම සැලකිල්ලක් නොදක්වනවාද යන්නයි.
ead

4

එය සෑම විටම පිඹුරා ඇත මන්ද යන්න මට හිමි නොවනු වෙනවා callable(obj) -> boolනමුත් iterable(obj) -> bool...
නියත වශයෙන්ම එය කිරීමට පහසු වේ hasattr(obj,'__call__')එය හෙමින් පවා නම්.

වෙනත් සෑම පිළිතුරක්ම නිර්දේශ කරන්නේ try/ භාවිතා කිරීම except TypeError, ඕනෑම භාෂාවක් අතර ව්‍යතිරේක සඳහා පරීක්‍ෂා කිරීම සාමාන්‍යයෙන් නරක පුරුද්දක් ලෙස සලකන හෙයින්, මෙන්න iterable(obj) -> boolමම ක්‍රියාත්මක කිරීමට වැඩි කැමැත්තක් දැක්වූ අතර බොහෝ විට භාවිතා කරමි:

පයිතන් 2 වෙනුවෙන්, මම එම අමතර කාර්ය සාධනය වැඩි කිරීම සඳහා ලැම්බඩා භාවිතා කරමි ...
(පයිතන් 3 හි ඔබ ශ්‍රිතය අර්ථ දැක්වීම සඳහා භාවිතා කරන දේට කමක් නැත, defදළ වශයෙන් සමාන වේගයක් ඇත lambda)

iterable = lambda obj: hasattr(obj,'__iter__') or hasattr(obj,'__getitem__')

මෙම ශ්‍රිතය __iter__පරික්‍ෂා නොකරන බැවින් වස්තූන් සඳහා වේගයෙන් ක්‍රියාත්මක වන බව සලකන්න __getitem__.

බොහෝ පුනරාවර්තනය කළ හැකි වස්තූන් රඳා පැවතිය යුත්තේ __iter__විශේෂ අවස්ථා වස්තූන් නැවත වැටෙන්නේ කොතැනට ද යන්න මත __getitem__ය.
(මෙය සම්මත බැවින් එය සී වස්තු වලටද බලපායි)


ඔහු ක්‍රියාකාරී කේතයක් සපයන්නේ නැත, පයිතන් ක්‍රියාකාරිත්වය ගැන කතා කිරීමට ඉඩ දෙන්න ... මෙම පිළිතුර සැබවින්ම පහසුව සඳහා පමණක් වුවද මම මෙහි කිහිප වතාවක්ම දැක ඇත්තෙමි.
Tcll

3
def is_iterable(x):
    try:
        0 in x
    except TypeError:
        return False
    else:
        return True

මෙය සියලු ආකාරයේ නැවත සැකසිය හැකි වස්තූන් සඳහා ඔව් යැයි කියනු ඇත, නමුත් එය පයිතන් 2 හි නූල් එපා යැයි කියනු ඇත . (අ ආවර්තනික කාර්යය වැලක් හෝ නූල් කන්ටේනර් ගත විය හැකි විට මම උදාහරණයක් අවශ්ය දේ ඒ. දී තිබෙන බව, සමාව ඉල්ලා obfuscode විය හැක, එය පළමු අවසර වඩා හොඳය.)

import numpy

class Yes:
    def __iter__(self):
        yield 1;
        yield 2;
        yield 3;

class No:
    pass

class Nope:
    def __iter__(self):
        return 'nonsense'

assert is_iterable(Yes())
assert is_iterable(range(3))
assert is_iterable((1,2,3))   # tuple
assert is_iterable([1,2,3])   # list
assert is_iterable({1,2,3})   # set
assert is_iterable({1:'one', 2:'two', 3:'three'})   # dictionary
assert is_iterable(numpy.array([1,2,3]))
assert is_iterable(bytearray("not really a string", 'utf-8'))

assert not is_iterable(No())
assert not is_iterable(Nope())
assert not is_iterable("string")
assert not is_iterable(42)
assert not is_iterable(True)
assert not is_iterable(None)

මෙහි ඇති තවත් බොහෝ උපාය මාර්ග නූල් වලට ඔව් යැයි කියනු ඇත. ඔබට අවශ්‍ය නම් ඒවා භාවිතා කරන්න.

import collections
import numpy

assert isinstance("string", collections.Iterable)
assert isinstance("string", collections.Sequence)
assert numpy.iterable("string")
assert iter("string")
assert hasattr("string", '__getitem__')

සටහන: is_iterable () වර්ගයේ නූල් ඔව් කියන්න bytesහා bytearray.

  • bytesපයිතන් 3 හි ඇති වස්තූන් නැවත ක්‍රියාත්මක වේ True == is_iterable(b"string") == is_iterable("string".encode('utf-8')). පයිතන් 2 හි එවැනි වර්ගයක් නොමැත.
  • bytearray පයිතන් 2 සහ 3 හි ඇති වස්තූන් නැවත ලබා ගත හැකිය True == is_iterable(bytearray(b"abc"))

මෙම විශ්රාම වැටුප් hasattr(x, '__iter__')ක්රමය Python 2 Python 3 නූල් ඔව් කියන්න කිසිම ඇත (උනත් යන්න ''හෝ b''හෝ u''). එය දැකීම ගැන @ ලුයිස්මාසුලිට ස්තූතියි ඔබට දෝෂයක් ඇති වනු ඇත __iter__.


2

පහසුම ක්‍රමය නම්, පයිතන්ගේ තාරා ටයිප් කිරීමට ගරු කිරීම , දෝෂය හසු කර ගැනීමයි (පයිතන් වස්තුවක් අනුකාරකයක් බවට පත්වීමට අපේක්ෂා කරන්නේ කුමක්ද යන්න හොඳින් දනී):

class A(object):
    def __getitem__(self, item):
        return something

class B(object):
    def __iter__(self):
        # Return a compliant iterator. Just an example
        return iter([])

class C(object):
    def __iter__(self):
        # Return crap
        return 1

class D(object): pass

def iterable(obj):
    try:
        iter(obj)
        return True
    except:
        return False

assert iterable(A())
assert iterable(B())
assert iterable(C())
assert not iterable(D())

සටහන් :

  1. __iter__ව්‍යතිරේක වර්ගය එක හා සමාන නම්, වස්තුව නැවත ක්‍රියාත්මක කළ නොහැකි ද, නැතහොත් දෝෂ සහිත ද යන්න ක්‍රියාත්මක කිරීම ද යන්න අදාල නොවේ. කෙසේ වෙතත් ඔබට වස්තුව නැවත සැකසීමට නොහැකි වනු ඇත.
  2. ඔබේ සැලකිල්ල මට වැටහී ඇතැයි මම සිතමි: මගේ වස්තුව සඳහා අර්ථ දක්වා නොමැති නම් , එසවීම සඳහා callableතාරාවන්ගේ යතුරු ලියනය මත විශ්වාසය තැබිය හැකිදැයි පරීක්ෂා කිරීමක් ලෙස පවතින්නේ කෙසේද , නමුත් නැවත පරීක්ෂා කිරීම සඳහා එය එසේ නොවේද?AttributeError__call__

    මම පිළිතුර නොදනිමි, නමුත් ඔබට මා (සහ වෙනත් පරිශීලකයින්) ලබා දුන් ශ්‍රිතය ක්‍රියාත්මක කළ හැකිය, නැතහොත් ඔබේ කේතයේ ඇති ව්‍යතිරේකය අල්ලා ගන්න (එම කොටසෙහි ඔබේ ක්‍රියාත්මක කිරීම මා ලියූ ශ්‍රිතයට සමාන වනු ඇත - ඔබ හුදකලා බව සහතික කරන්න ඉතිරි කේතයෙන් iterator නිර්මාණය කිරීම මඟින් ඔබට ව්‍යතිරේකය ග්‍රහණය කර වෙනත් ආකාරයකින් වෙන්කර හඳුනාගත හැකිය TypeError.


1

මෙම isiterableපහත දැක්වෙන කේතය ප්රතිලාභ දී func Trueවස්තුව iterable නම්. එය නැවත ලබා ගත නොහැකි ප්‍රතිලාභ නම්False

def isiterable(object_):
    return hasattr(type(object_), "__iter__")

උදාහරණයක්

fruits = ("apple", "banana", "peach")
isiterable(fruits) # returns True

num = 345
isiterable(num) # returns False

isiterable(str) # returns False because str type is type class and it's not iterable.

hello = "hello dude !"
isiterable(hello) # returns True because as you know string objects are iterable

2
ඉහත දක්වා ඇති සවිස්තරාත්මක පිළිතුරු බොහෝ උඩු යටිකුරු කර ඇති අතර ඔබ පැහැදිලි කළ නොහැකි පිළිතුරක් විසි කරයි ...
meh

කරුණාකර හිස් කේතයක් පළ නොකරන්න. මෙය කරන්නේ කුමක්ද යන්න පිළිබඳ පැහැදිලි කිරීමක් ද ඇතුළත් කරන්න.
ජොනතන් මී

1

__iter__ගුණාංගය පරික්ෂා කිරීම වෙනුවට , ඔබට ගුණාංගය පරීක්ෂා කළ හැකිය __len__, එය නූල් ද ඇතුළුව සෑම පයිතන් බිල්ටින් විසින්ම ක්‍රියාත්මක කළ හැකිය.

>>> hasattr(1, "__len__")
False
>>> hasattr(1.3, "__len__")
False
>>> hasattr("a", "__len__")
True
>>> hasattr([1,2,3], "__len__")
True
>>> hasattr({1,2}, "__len__")
True
>>> hasattr({"a":1}, "__len__")
True
>>> hasattr(("a", 1), "__len__")
True

කිසිවක් කළ නොහැකි වස්තූන් පැහැදිලි හේතුන් මත මෙය ක්‍රියාත්මක නොකරනු ඇත. කෙසේ වෙතත්, එය ක්‍රියාත්මක නොකරන පරිශීලක-නිර්වචනය කළ හැකි ක්‍රියාකාරකම් අල්ලා නොගනී, එසේම iterගනුදෙනු කළ හැකි උත්පාදක ප්‍රකාශන ද නොකරයි . කෙසේ වෙතත්, මෙය පේළියකින් කළ හැකි අතර, orජනක යන්ත්‍ර සඳහා සරල ප්‍රකාශන පරීක්‍ෂණයක් එකතු කිරීමෙන් මෙම ගැටළුව විසඳනු ඇත. (ලිවීම type(my_generator_expression) == generatorමඟින් විසි වන බව සලකන්න . ඒ වෙනුවට මෙම පිළිතුර NameErrorවෙත යොමු වන්න .)

ඔබට වර්ග වලින් GeneratorType භාවිතා කළ හැකිය:

>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True

--- උත්තරීර් විසින් පිළිගත් පිළිතුර

(මෙය ඔබට lenවස්තුව ඇමතිය හැකිදැයි පරීක්ෂා කිරීමට ප්‍රයෝජනවත් වේ .)


අවාසනාවකට මෙන් සියලු නැවත ලබා ගත හැකි වස්තූන් භාවිතා නොවේ __len__... මෙම අවස්ථාව සඳහා, එය සාමාන්‍යයෙන් වස්තු 2 ක් අතර දුර ගණනය කිරීමේ නුසුදුසු භාවිතයයි. obj.dist()පහසුවෙන් ආදේශ කළ හැකි තැන .
Tcll

ඔව්. බොහෝ පරිශීලකයින් විසින් නිර්වචනය කරන ලද iterables iter සහ getitem ක්‍රියාත්මක කරන නමුත් len නොවේ. කෙසේ වෙතත්, වර්ග වලින් සාදා ඇති අතර, ඔබට එය මත ලෙන් ක්‍රියාකාරිත්වය ඇමතිය හැකිදැයි පරීක්ෂා කිරීමට අවශ්‍ය නම්, කාචය පරීක්ෂා කිරීම වඩාත් ආරක්ෂිත වේ. නමුත් ඔබ හරි.
ඩාර්ත්කැඩියස්

0

සැබවින්ම "නිවැරදි" නොවන නමුත් නූල්, ටුපල්, ෆ්ලෝට් වැනි බොහෝ පොදු වර්ගවල ඉක්මන් පරීක්ෂාවක් ලෙස සේවය කළ හැකිය ...

>>> '__iter__' in dir('sds')
True
>>> '__iter__' in dir(56)
False
>>> '__iter__' in dir([5,6,9,8])
True
>>> '__iter__' in dir({'jh':'ff'})
True
>>> '__iter__' in dir({'jh'})
True
>>> '__iter__' in dir(56.9865)
False

0

සාදයට ප්‍රමාද වූ නමුත් මම මේ ප්‍රශ්නය මගෙන්ම ඇසූ අතර මෙය දුටු විට පිළිතුරක් ගැන සිතුවෙමි. කවුරුහරි දැනටමත් මෙය පළ කර ඇත්දැයි මම නොදනිමි. නමුත් අත්‍යාවශ්‍යයෙන්ම, සියලු ක්‍රියාකාරී වර්ග වල __getitem __ () ඒවායේ විධානයෙහි ඇති බව මම දුටුවෙමි . වස්තුවක් උත්සාහ නොකර පවා නැවත සැකසිය හැකි දැයි ඔබ පරීක්ෂා කරන්නේ මේ ආකාරයට ය. (පුන් අදහස් කර ඇත)

def is_attr(arg):
    return '__getitem__' in dir(arg)

අවාසනාවට, මෙය විශ්වාස කළ නොහැකි ය. උදාහරණය
timgeb

1
කුලක වස්තු තවත් ප්‍රති-ආදර්ශයකි.
රේමන්ඩ් හෙටින්ගර්

එය ද pun ුවමක් වන්නේ කෙසේද?
විල්ව්ෂාර්ප්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.