আমি একটু পারস্পরিক উপর আরো হালকা বিট চালা চাই 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__পাইথন 2 next:) পদ্ধতিযুক্ত যেকোন বস্তু ।
খ) oএকটি __getitem__পদ্ধতি আছে।
এর Iterableউদাহরণ Sequenceবা জন্য অনুসন্ধান করা বা বৈশিষ্ট্যের __iter__জন্য অনুসন্ধান করা যথেষ্ট নয়।
যদি কোনও অবজেক্ট oকেবল প্রয়োগ করে __getitem__, তবে তা নয় __iter__, iter(o)একটি পুনরুক্তি তৈরি করবে oযা সূচক 0 থেকে শুরু করে পূর্ণসংখ্য সূচক থেকে আইটেম আনার চেষ্টা করে The পুনরুক্তি IndexErrorকরা উত্থাপিত কোনও (তবে অন্য কোনও ত্রুটি) ধরা পড়বে এবং তারপরে StopIterationনিজেই উত্থাপিত হবে ।
খুব সাধারণ অর্থে, iterএটির চেষ্টা করা ছাড়াও পুনরুক্তি করা ইটারেটরটি বুদ্ধিমান কিনা তা যাচাই করার উপায় নেই ।
যদি কোনও অবজেক্ট oপ্রয়োগ করে __iter__তবে iterফাংশনটি নিশ্চিত করবে যে প্রত্যাবর্তিত বস্তুটি __iter__একটি পুনরাবৃত্তকারী। কোনও বস্তু কেবল প্রয়োগ করে কিনা সেখানে কোনও বিড়াল চেক নেই __getitem__।
__iter__ধিক্কার জানাই। একটি বস্তু যদি oকার্যকরী উভয় __iter__এবং __getitem__, iter(o)ডাকব __iter__।
আপনি যদি নিজের আইটেমগুলিকে পুনরাবৃত্ত করতে চান তবে সর্বদা __iter__পদ্ধতিটি প্রয়োগ করুন ।
for লুপ
পাশাপাশি অনুসরণ করতে, আপনি forপাইথনে কোনও লুপ নিযুক্ত করলে কী ঘটে তা বোঝার প্রয়োজন you আপনি যদি ইতিমধ্যে জেনে থাকেন তবে নিখরচায় পরবর্তী বিভাগে যেতে পারেন।
আপনি যখন for item in oকিছু পুনরাবৃত্তিযোগ্য অবজেক্টের জন্য ব্যবহার করেন o, পাইথন কল দেয় iter(o)এবং প্রত্যাবর্তনের মান হিসাবে কোনও পুনরাবৃত্ত বস্তুর প্রত্যাশা করে। একটি পুনরুক্তি হ'ল কোনও বস্তু যা একটি __next__(বা nextপাইথন 2 এ) পদ্ধতি এবং একটি __iter__পদ্ধতি প্রয়োগ করে ।
কনভেনশন দ্বারা, __iter__একটি পুনরাবৃত্তির পদ্ধতিটি নিজেই (return 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
এ কারণেই লুসিও রামালহোর ফ্লুয়েন্ট পাইথন কোনও বস্তুর পুনরাবৃত্তিযোগ্য কিনা তা যাচাই করার সবচেয়ে সঠিক উপায় হিসাবে iterসম্ভাব্যতার কল এবং পরিচালনা করার পরামর্শ দেয় TypeError। বই থেকে সরাসরি উদ্ধৃতি:
পাইথন ৩.৪ অনুসারে, কোনও বস্তুর xপুনরাবৃত্তিযোগ্য কিনা তা যাচাই করার সর্বাধিক সঠিক উপায়টি যদি iter(x)কোনও TypeErrorব্যতিক্রম না হয় তবে কল করা এবং পরিচালনা করতে হবে। এটি ব্যবহারের চেয়ে আরও সঠিক isinstance(x, abc.Iterable), কারণ iter(x)এটি উত্তরাধিকার __getitem__পদ্ধতিটিও বিবেচনা করে , যদিও Iterableএবিসি তা করে না।
3 পয়েন্টে: কেবলমাত্র সরবরাহ করে এমন অবজেক্টগুলিতে আইট্রেট করা __getitem__but__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তা অভ্যন্তরীণভাবে পরিচালিত হয় ises এ কারণেই 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__পদ্ধতিটি যদি উপস্থিত থাকে তবে তার ফেরতের মান একটি পুনরাবৃত্তিকারী। এর অর্থ হল যে প্রত্যাবর্তিত অবজেক্ট অবশ্যই প্রয়োগ করতে হবে __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
Point দফায়: __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
Point দফায়: আপনার পুনরাবৃত্তিযোগ্য ক্লাসগুলি প্রয়োগ করা উচিত __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__পিছনের সামঞ্জস্যতার কারণে বিশেষ হ্যান্ডলিং বিদ্যমান। ফ্লুয়েন্ট পাইথন থেকে আবার উদ্ধৃত:
এজন্য যে কোনও পাইথন সিকোয়েন্সটি পুনরাবৃত্তিযোগ্য: সেগুলি সমস্ত প্রয়োগ করে __getitem__। প্রকৃতপক্ষে, স্ট্যান্ডার্ড সিকোয়েন্সগুলিও বাস্তবায়ন করে __iter__এবং আপনারও হওয়া উচিত, কারণ __getitem__পশ্চাদপদ সামঞ্জস্যতার কারণে বিশেষ হ্যান্ডলিং উপস্থিত রয়েছে এবং ভবিষ্যতেও চলে যেতে পারে (যদিও এটি লেখার সাথে সাথে এটি অবহেলা করা হয়নি)।
__getitem__কোনও বস্তুকে পুনরাবৃত্ত করার জন্যও যথেষ্ট