আমি একটু পারস্পরিক উপর আরো হালকা বিট চালা চাই 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__
কোনও বস্তুকে পুনরাবৃত্ত করার জন্যও যথেষ্ট