উত্তর:
পাইথনে আইট্রেটার অবজেক্টগুলি পুনরায় প্রোটোকলের সাথে সামঞ্জস্য করে, যার মূলত তারা দুটি পদ্ধতি সরবরাহ করে: __iter__()
এবং __next__()
।
__iter__
পুনরুক্তিকারীর বস্তুর ফেরৎ এবং পরোক্ষভাবে লুপ শুরুতে বলা হয়।
__next__()
পদ্ধতি পরবর্তী মান এবং পরোক্ষভাবে প্রতিটি লুপ বৃদ্ধি এ বলা হয়। প্রত্যাবর্তনের আর কোনও মান না থাকাকালীন এই পদ্ধতিটি স্টিপটিরেটনের ব্যতিক্রম উত্থাপন করে, যা পুনরাবৃত্তি বন্ধ করতে লুপিং কনস্ট্রাক্টস দ্বারা স্পষ্টত ক্যাপচার করা হয়।
এখানে একটি কাউন্টার একটি সাধারণ উদাহরণ:
class Counter:
def __init__(self, low, high):
self.current = low - 1
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 2: def next(self)
self.current += 1
if self.current < self.high:
return self.current
raise StopIteration
for c in Counter(3, 9):
print(c)
এটি মুদ্রণ করবে:
3
4
5
6
7
8
পূর্ববর্তী উত্তরে যেমন জেনারেটর ব্যবহার করে এটি লেখা সহজ:
def counter(low, high):
current = low
while current < high:
yield current
current += 1
for c in counter(3, 9):
print(c)
মুদ্রিত আউটপুট একই হবে। ফণা অধীনে, জেনারেটর অবজেক্ট পুনরায় প্রোটোকল সমর্থন করে এবং ক্লাস কাউন্টার হিসাবে প্রায় অনুরূপ কিছু করে।
ডেভিড Mertz এর নিবন্ধ, Iteilers এবং সাধারণ জেনারেটর , একটি বেশ ভাল ভূমিকা।
__next__
। counter
এটি একটি পুনরাবৃত্তিকারী, তবে এটি কোনও ক্রম নয়। এটি এর মান সংরক্ষণ করে না। উদাহরণস্বরূপ, লুপের জন্য দ্বিগুণ নেস্টের জন্য কাউন্টারটি ব্যবহার করা উচিত নয়।
__iter__
(পাশাপাশি __init__
)। অন্যথায়, অবজেক্টটি কেবল একবারে পুনরাবৃত্তি হতে পারে। উদাহরণস্বরূপ, যদি আপনি বলেন ctr = Counters(3, 8)
, তবে আপনি for c in ctr
একাধিকবার ব্যবহার করতে পারবেন না ।
Counter
একটি পুনরাবৃত্তকারী এবং পুনরাবৃত্তিকে কেবল একবার পুনরাবৃত্তি করার কথা। আপনি যদি পুনরায় সেট self.current
করেন __iter__
, তবে এর উপরে নেস্ট করা লুপটি Counter
সম্পূর্ণরূপে ভেঙে যাবে এবং পুনরাবৃত্তকারীগুলির সমস্ত ধরণের আচরণ (যা iter
তাদের প্রতি আহ্বান করা আদর্শবাদী) লঙ্ঘন করা হয়েছে। আপনি যদি ctr
একাধিকবার পুনরাবৃত্তি করতে সক্ষম হতে চান তবে এটি একটি পুনরাবৃত্ত-পুনরুক্তিযোগ্য হওয়া দরকার, যেখানে এটি প্রতিবারই অনুরোধ __iter__
করা হয় এবং একেবারে একটি নতুন পুনরাবৃত্তি ফিরিয়ে দেয় । মেশানো এবং মিলানোর চেষ্টা করা (একটি পুনরাবৃত্তকারী যা প্রেরণ করা হওয়ার পরে স্পষ্টত পুনরায় সেট __iter__
করা হয়) প্রোটোকল লঙ্ঘন করে।
Counter
কোনও অ-পুনরাবৃত্তির পুনরাবৃত্তিযোগ্য হতে হয়, আপনি __next__
/ next
সম্পূর্ণরূপে সংজ্ঞাটি মুছে ফেলতে এবং সম্ভবত __iter__
এই উত্তরটির শেষে বর্ণিত জেনারেটরের মতো একই ফর্মের জেনারেটর ফাংশন হিসাবে পুনরায় সংজ্ঞায়িত করতে পারেন (সীমার পরিবর্তে ব্যতীত আর্গুমেন্ট থেকে আগত __iter__
, তারা আর্গুমেন্ট করে দেখতে আগ্রহী হবেন __init__
সংরক্ষিত self
এবং থেকে অ্যাক্সেস self
মধ্যে __iter__
)।
একটি পুনরাবৃত্তি ফাংশন তৈরির চারটি উপায় রয়েছে:
__iter__
এবং__next__
(অথবা next
পাইথন 2.x এ))__getitem__
)উদাহরণ:
# generator
def uc_gen(text):
for char in text.upper():
yield char
# generator expression
def uc_genexp(text):
return (char for char in text.upper())
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text.upper()
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text.upper()
def __getitem__(self, index):
return self.text[index]
চারটি পদ্ধতি কার্যকর করার জন্য:
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print(ch, end=' ')
print()
যার ফলাফল:
A B C D E
A B C D E
A B C D E
A B C D E
দ্রষ্টব্য :
দুটি জেনারেটর ধরণের ( uc_gen
এবং uc_genexp
) হতে পারে না reversed()
; প্লেইন ইটারেটর ( uc_iter
) এর জন্য __reversed__
ম্যাজিক পদ্ধতিটি প্রয়োজন (যা ডক্স অনুসারে একটি নতুন পুনরাবৃত্তকারীকে ফিরিয়ে দিতে হবে, তবে self
কাজগুলি (অন্তত সিপিথনে)) ফেরত যেতে হবে ; এবং গেটাইটেম পুনরাবৃত্তিযোগ্য ( uc_getitem
) এর অবশ্যই __len__
ম্যাজিক পদ্ধতি থাকতে হবে:
# for uc_iter we add __reversed__ and update __next__
def __reversed__(self):
self.index = -1
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += -1 if self.index < 0 else +1
return result
# for uc_getitem
def __len__(self)
return len(self.text)
অসীম অলসভাবে মূল্যায়নকৃত পুনরুত্থক সম্পর্কে কর্নেল প্যানিকের গৌণ প্রশ্নের উত্তর দেওয়ার জন্য, উপরোক্ত চারটি পদ্ধতির প্রত্যেকটি ব্যবহার করে এখানে উদাহরণগুলি দেওয়া হল:
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
যার ফলাফল (কমপক্ষে আমার নমুনা চালানোর জন্য):
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
কোনটি ব্যবহার করবেন তা কীভাবে চয়ন করবেন? এটি বেশিরভাগ স্বাদের বিষয়। আমি যে দুটি পদ্ধতিটি প্রায়শই দেখতে পাই তা হ'ল জেনারেটর এবং পুনরায় প্রোটোকল, সেইসাথে একটি সংকর ( __iter__
একটি জেনারেটর ফিরিয়ে দেওয়া)।
জেনারেটর এক্সপ্রেশন তালিকা অনুধাবন প্রতিস্থাপনের জন্য দরকারী (তারা অলস এবং তাই সংস্থানগুলিতে সঞ্চয় করতে পারে)।
যদি কারও পূর্ববর্তী পাইথন ২.x সংস্করণ ব্যবহারের সাথে সামঞ্জস্যতার প্রয়োজন হয় __getitem__
।
uc_iter
এর কাজটি শেষ হওয়ার আগে একটি উদাহরণ শেষ হতে হবে (অন্যথায় এটি অসীম দ্বারা হবে); আপনি যদি আবার এটি করতে চান তবে আপনাকে আবার কল করে একটি নতুন uc_iter()
পুনরাবৃত্তি পেতে হবে।
self.index = 0
মধ্যে __iter__
যাতে তোমাদের উপর অনেক বার পুনরুক্তি করতে পারেন। অন্যথায় আপনি পারবেন না।
প্রথমে ইটারটুলস মডিউলটি সমস্ত ধরণের ক্ষেত্রে অবিশ্বাস্যরূপে কার্যকর যার ক্ষেত্রে একটি পুনরুক্তিকারী কার্যকর হবে তবে অজগরটিতে একটি পুনরুক্তি তৈরি করার জন্য আপনার এখানে প্রয়োজনীয় সমস্ত বিষয়:
উত্পাদ
এটা কি দুর্দান্ত না? ফলন কোনও ফাংশনে স্বাভাবিক রিটার্ন প্রতিস্থাপন করতে ব্যবহার করা যেতে পারে । এটি অবজেক্টটিকে ঠিক একইরূপে ফেরত দেয়, তবে রাষ্ট্রটিকে ধ্বংস করে এবং প্রস্থান করার পরিবর্তে, আপনি যখন পরবর্তী পুনরাবৃত্তি সম্পাদন করতে চান তখন এটি রাষ্ট্র সংরক্ষণ করে। ক্রিয়াকলাপের এটির উদাহরণ উদাহরণ থেকে এটির তাত্ত্বিক ক্রিয়া তালিকা থেকে সরাসরি টানা :
def count(n=0):
while True:
yield n
n += 1
যেমন ফাংশন বর্ণনায় বর্ণিত হয়েছে (এটি গণনা () এটির টোলস মডিউল থেকে ফাংশন ...), এটি একটি পুনরুক্তি তৈরি করে যা এন থেকে শুরু করে পরপর পূর্ণসংখ্যার ফেরত দেয়।
জেনারেটর এক্সপ্রেশনগুলি হ'ল পোকার সম্পূর্ণ ক্যান (দুর্দান্ত কীট!)) এগুলি মেমরি সংরক্ষণের জন্য তালিকার সংকলনের জায়গায় ব্যবহার করা যেতে পারে (তালিকার বোধগম্যতা স্মৃতিতে একটি তালিকা তৈরি করে যা ভেরিয়েবলের জন্য বরাদ্দ না থাকলে ব্যবহারের পরে নষ্ট হয়ে যায়, তবে জেনারেটর এক্সপ্রেশন জেনারেটর অবজেক্ট তৈরি করতে পারে ... যা অভিনব উপায় বলছি Iterator)। এখানে একটি জেনারেটর এক্সপ্রেশন সংজ্ঞা একটি উদাহরণ:
gen = (n for n in xrange(0,11))
এটি সম্পূর্ণ পরিসীমা 0 এবং 10 এর মধ্যে হওয়ার পূর্বনির্ধারিত ব্যতীত উপরের আমাদের পুনরাবৃত্ত সংজ্ঞাটির সাথে খুব অনুরূপ।
আমি সবেমাত্র xrange () (অবাক হয়েছি যা আমি এর আগে দেখিনি ...) এবং এটি উপরের উদাহরণে যুক্ত করেছি। এক্সরেঞ্জ () হ'ল পরিসীমা () এর পুনরাবৃত্তিযোগ্য সংস্করণ যা তালিকার পূর্বনির্মাণ না করার সুবিধা রয়েছে। এটি যদি আপনার পুনরাবৃত্তি করার জন্য ডেটাগুলির একটি দৈত্য কর্পস থাকে এবং কেবল এটির করতে এত মেমরি থাকে তবে এটি খুব কার্যকর হবে।
আমি আপনার return self
মধ্যে কিছু করতে দেখছি __iter__
। আমি কেবল খেয়াল করতে চেয়েছিলাম যে __iter__
নিজে নিজেই একটি জেনারেটর হতে পারে (এইভাবে প্রয়োজনীয়তা অপসারণ __next__
এবং StopIteration
ব্যতিক্রম উত্থাপন )
class range:
def __init__(self,a,b):
self.a = a
self.b = b
def __iter__(self):
i = self.a
while i < self.b:
yield i
i+=1
অবশ্যই এখানে কেউ সরাসরি জেনারেটর তৈরি করতে পারে তবে আরও জটিল ক্লাসগুলির জন্য এটি কার্যকর হতে পারে।
return self
মধ্যে __iter__
। আমি যখন yield
এটি ব্যবহার করার চেষ্টা করতে যাচ্ছিলাম তখন আমি খুঁজে পেলাম যে আপনার কোডটি আমি যা চেষ্টা করতে চাই ঠিক তাই করছি।
next()
? return iter(self).next()
?
self.current
বা অন্য কোনও কাউন্টারকে রাখার সাথে জড়িত নয় । এটি শীর্ষ ভোটের উত্তর হওয়া উচিত!
iter
তবে সেগুলি নিজেরাই শ্রেণীর উদাহরণ নয়।
এই প্রশ্নটি পুনরাবৃত্তিযোগ্য অবজেক্ট সম্পর্কে, পুনরাবৃত্তকারীদের সম্পর্কে নয়। পাইথনে, সিকোয়েন্সগুলি পুনরাবৃত্ত হয় তাই পুনরাবৃত্ত শ্রেণীর তৈরি করার একটি উপায় হ'ল এটি একটি সিক্যুয়েন্সের মতো আচরণ করা, অর্থাৎ এটি __getitem__
এবং __len__
পদ্ধতিগুলি দেওয়া। আমি পাইথন 2 এবং 3 এ পরীক্ষা করেছি।
class CustomRange:
def __init__(self, low, high):
self.low = low
self.high = high
def __getitem__(self, item):
if item >= len(self):
raise IndexError("CustomRange index out of range")
return self.low + item
def __len__(self):
return self.high - self.low
cr = CustomRange(0, 10)
for i in cr:
print(i)
__len__()
পদ্ধতি থাকতে হবে না । __getitem__
একা প্রত্যাশিত আচরণই যথেষ্ট।
একটি জটিল অবজেক্টের জন্য এই পৃষ্ঠার সমস্ত উত্তর সত্যিই দুর্দান্ত। তবে বিল্টিন পুনরাবৃত্ত প্রকারযুক্ত বৈশিষ্ট্যগুলির মতো str
, যেমন list
, set
বা dict
, বা কোনও বাস্তবায়ন হিসাবে collections.Iterable
আপনি নিজের শ্রেণীর কিছু জিনিস বাদ দিতে পারেন।
class Test(object):
def __init__(self, string):
self.string = string
def __iter__(self):
# since your string is already iterable
return (ch for ch in self.string)
# or simply
return self.string.__iter__()
# also
return iter(self.string)
এটি এর মতো ব্যবহার করা যেতে পারে:
for x in Test("abcde"):
print(x)
# prints
# a
# b
# c
# d
# e
return iter(self.string)
।
এটি ছাড়া একটি পুনরাবৃত্তিযোগ্য ফাংশন yield
। এটি iter
ফাংশনটি এবং একটি বন্ধ ব্যবহার করে যা list
অজগর 2 এর সংলগ্ন ক্ষেত্রটিতে একটি পরিবর্তনীয় ( ) এ অবস্থায় রাখে ।
def count(low, high):
counter = [0]
def tmp():
val = low + counter[0]
if val < high:
counter[0] += 1
return val
return None
return iter(tmp, None)
পাইথন 3 এর জন্য, ক্লোজার স্টেটটি বদ্ধ পরিসরে একটি অপরিবর্তনীয় স্থানে রাখা হয় এবং nonlocal
রাষ্ট্রের পরিবর্তনশীল আপডেট করতে স্থানীয় স্কোপে ব্যবহৃত হয়।
def count(low, high):
counter = 0
def tmp():
nonlocal counter
val = low + counter
if val < high:
counter += 1
return val
return None
return iter(tmp, None)
পরীক্ষা;
for i in count(1,10):
print(i)
1
2
3
4
5
6
7
8
9
iter
, তবে কেবল স্পষ্ট করে বলার জন্য: এটি কেবলমাত্র yield
ভিত্তিক জেনারেটর ফাংশনটি ব্যবহার করার চেয়ে জটিল এবং কম দক্ষ ; পাইথনের yield
ভিত্তিক জেনারেটর ফাংশনগুলির জন্য একটি টন দোভাষী সহায়তা রয়েছে যা আপনি এখানে কোড নিতে পারেন না, এই কোডটি উল্লেখযোগ্যভাবে ধীর করে তোলে। তবুও আপ-ভোট দিয়েছেন।
আপনি যদি সংক্ষিপ্ত এবং সাধারণ কিছু সন্ধান করেন তবে এটি আপনার পক্ষে যথেষ্ট হবে:
class A(object):
def __init__(self, l):
self.data = l
def __iter__(self):
return iter(self.data)
ব্যবহারের উদাহরণ:
In [3]: a = A([2,3,4])
In [4]: [i for i in a]
Out[4]: [2, 3, 4]
এখানে ম্যাট গ্রেগরির উত্তর দ্বারা অনুপ্রাণিত হলেন আরও জটিল জটিল পুনরাবৃত্তি যা একটি, বি, ..., জেড, আ, আব, ..., জেডজেড, আ, আব, ..., জাজি, জেডজ
class AlphaCounter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 3: def __next__(self)
alpha = ' abcdefghijklmnopqrstuvwxyz'
n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
if n_current > n_high:
raise StopIteration
else:
increment = True
ret = ''
for x in self.current[::-1]:
if 'z' == x:
if increment:
ret += 'a'
else:
ret += 'z'
else:
if increment:
ret += alpha[alpha.find(x)+1]
increment = False
else:
ret += x
if increment:
ret += 'a'
tmp = self.current
self.current = ret[::-1]
return tmp
for c in AlphaCounter('a', 'zzz'):
print(c)