একটি জেনারেটর ভাষার সুবিধা যেমন yield
একটি ভাল ধারণা আছে?
আমি জোর দিয়ে হ্যাঁ, পাইথনের দৃষ্টিকোণ থেকে এর উত্তর দিতে চাই , এটি দুর্দান্ত ধারণা ।
আমি প্রথমে আপনার প্রশ্নে কিছু প্রশ্ন এবং অনুমানকে সম্বোধন করে শুরু করব, তারপরে পাইথনে জেনারেটরগুলির ব্যাপকতা এবং তাদের অযৌক্তিক উপযোগিতা প্রদর্শন করব।
নিয়মিত নন-জেনারেটর ফাংশন সহ আপনি এটিকে কল করতে পারেন এবং যদি এটি একই ইনপুট দেওয়া হয় তবে এটি একই আউটপুট ফেরত দেবে। ফলন সহ, এটি তার অভ্যন্তরীণ অবস্থার উপর নির্ভর করে বিভিন্ন আউটপুট দেয় returns
এটা মিথ্যা। বস্তুগুলির পদ্ধতিগুলি তাদের নিজস্ব অভ্যন্তরীণ অবস্থার সাথে ফাংশন হিসাবে বিবেচনা করা যেতে পারে। পাইথনে, যেহেতু সবকিছুই একটি বস্তু, তাই আপনি আসলে কোনও বস্তুর কাছ থেকে কোনও পদ্ধতি পেতে পারেন এবং সেই পদ্ধতিটি ঘিরে ফেলতে পারেন (এটি যে বস্তুটি এসেছে সেটির সাথে আবদ্ধ, সুতরাং এটি তার অবস্থার কথা মনে রাখে)।
অন্যান্য উদাহরণগুলির মধ্যে ইচ্ছাকৃতভাবে এলোমেলো ফাংশনগুলির পাশাপাশি নেটওয়ার্ক, ফাইল সিস্টেম এবং টার্মিনালের মতো ইনপুট পদ্ধতি অন্তর্ভুক্ত রয়েছে।
এই জাতীয় ফাংশন কীভাবে ভাষার দৃষ্টান্তের সাথে খাপ খায়?
ভাষার দৃষ্টান্ত যদি প্রথম শ্রেণির ফাংশনগুলির মতো জিনিসগুলিকে সমর্থন করে এবং জেনারেটরগুলি ইটারেবল প্রোটোকলের মতো অন্যান্য ভাষার বৈশিষ্ট্যগুলিকে সমর্থন করে তবে তারা নির্বিঘ্নে ফিট করে।
এটি আসলে কোনও সম্মেলন ভেঙে দেয়?
না, যেহেতু এটি ভাষায় বেকড রয়েছে, কনভেনশনগুলি চারপাশে নির্মিত এবং এতে জেনারেটরগুলির ব্যবহার (বা প্রয়োজন!) অন্তর্ভুক্ত।
প্রোগ্রামিং ল্যাঙ্গুয়েজ সংকলক / দোভাষীকে এই জাতীয় বৈশিষ্ট্যটি বাস্তবায়নের জন্য কোনও কনভেনশন থেকে বেরিয়ে আসতে হবে
অন্য কোনও বৈশিষ্ট্যের মতো, সংকলকটি কেবল বৈশিষ্ট্যটি সমর্থন করার জন্য ডিজাইন করা দরকার। পাইথনের ক্ষেত্রে, ফাংশনগুলি ইতিমধ্যে রাষ্ট্রযুক্ত অবজেক্ট (যেমন ডিফল্ট আর্গুমেন্ট এবং ফাংশন টীকা)।
এই বৈশিষ্ট্যটির কাজ করার জন্য কোনও ভাষার কী মাল্টি-থ্রেডিং বাস্তবায়ন করতে হবে, বা থ্রেডিং প্রযুক্তি ছাড়াই এটি করা যেতে পারে?
মজাদার ঘটনা: ডিফল্ট পাইথন বাস্তবায়ন থ্রেডিং মোটেও সমর্থন করে না। এটিতে একটি গ্লোবাল ইন্টারপ্রেটার লক (জিআইএল) বৈশিষ্ট্যযুক্ত, তাই পাইথনের অন্য কোনও উদাহরণ চালানোর জন্য আপনি দ্বিতীয় প্রক্রিয়াটি ব্যয় না করে আসলে কিছুই একই সাথে চলমান হয় না।
দ্রষ্টব্য: উদাহরণ পাইথন 3 এ রয়েছে
ফলনের বাইরে
যদিও yield
শব্দ কোন ফাংশন ব্যবহার করা যেতে পারে এটি একটি জেনারেটর পরিণত, এটা এক করতে একমাত্র উপায় নয়। পাইথন জেনারেটর এক্সপ্রেশন বৈশিষ্ট্যযুক্ত, অন্য পুনরাবৃত্ত (অন্যান্য জেনারেটর সহ) এর ক্ষেত্রে জেনারেটর স্পষ্টভাবে প্রকাশ করার একটি শক্তিশালী উপায়
>>> pairs = ((x,y) for x in range(10) for y in range(10) if y >= x)
>>> pairs
<generator object <genexpr> at 0x0311DC90>
>>> sum(x*y for x,y in pairs)
1155
আপনি দেখতে পাচ্ছেন, সিনট্যাক্সটি কেবল পরিষ্কার এবং পঠনযোগ্য নয়, sum
জেনারেটর গ্রহণের মতো বিল্ট-ইন ফাংশন ।
সঙ্গে
উইথ স্টেটমেন্টের জন্য পাইথন এনহান্সমেন্ট প্রস্তাবটি দেখুন । আপনি অন্যান্য ভাষায় উইথ স্টেটমেন্ট থেকে আশা করতে পারেন তার চেয়ে এটি অনেক আলাদা different স্ট্যান্ডার্ড লাইব্রেরি থেকে সামান্য সহায়তায় পাইথনের জেনারেটর তাদের জন্য প্রসঙ্গ পরিচালক হিসাবে সুন্দরভাবে কাজ করে।
>>> from contextlib import contextmanager
>>> @contextmanager
def debugWith(arg):
print("preprocessing", arg)
yield arg
print("postprocessing", arg)
>>> with debugWith("foobar") as s:
print(s[::-1])
preprocessing foobar
raboof
postprocessing foobar
অবশ্যই, মুদ্রণ জিনিসগুলি আপনি এখানে করতে পারেন এমন সবচেয়ে বিরক্তিকর জিনিস সম্পর্কে তবে এটি দৃশ্যমান ফলাফল দেখায়। আরও আকর্ষণীয় বিকল্পগুলির মধ্যে সম্পদের স্বয়ংক্রিয় ব্যবস্থাপনার (ফাইলগুলি / স্ট্রিমগুলি / নেটওয়ার্ক সংযোগগুলি খোলার এবং বন্ধ করা), সমাবর্তনের জন্য লক করা, অস্থায়ীভাবে মোড়ক বা কোনও ফাংশন প্রতিস্থাপন এবং সংশোধন করে ডেটা পুনরায় সংক্ষেপণ অন্তর্ভুক্ত রয়েছে। যদি কলিং ফাংশনগুলি আপনার কোডে ইনজেকশন কোডের মতো হয়, তবে বিবৃতি সহ অন্য কোডে আপনার কোডের অংশগুলি মোড়ানো করার মতো। তবে আপনি এটি ব্যবহার করুন, এটি কোনও ভাষা কাঠামোর মধ্যে সহজ হুকের শক্ত উদাহরণ। ফলন-ভিত্তিক জেনারেটর প্রসঙ্গ পরিচালকগণ তৈরি করার একমাত্র উপায় নয়, তবে তারা অবশ্যই একটি সুবিধাজনক।
জন্য এবং আংশিক ক্লান্তি
পাইথনের লুপগুলির জন্য একটি আকর্ষণীয় উপায়ে কাজ করুন। তাদের নিম্নলিখিত ফর্ম্যাট আছে:
for <name> in <iterable>:
...
প্রথমত, আমি যে অভিব্যক্তিটি বলেছিলাম <iterable>
তা পুনরাবৃত্তিযোগ্য অবজেক্ট পাওয়ার জন্য মূল্যায়ন করা হয়। দ্বিতীয়ত, পুনরাবৃত্তকারী __iter__
এটিতে ডেকেছিল এবং ফলস্বরূপ পুনরাবৃত্তকারীগুলি পর্দার আড়ালে সঞ্চিত থাকে। এরপরে, __next__
আপনাকে যে নামটি দেওয়া হয়েছিল তার সাথে আবদ্ধ হওয়ার জন্য একটি মান পেতে পুনরুত্থককে ডাকা হয় <name>
। এই পদক্ষেপটি পুনরুদ্ধার না করা অবধি কলটি __next__
a নিক্ষেপ করবে StopIteration
। ব্যতিক্রমটি লুপটির জন্য গিলে ফেলেছে এবং সেখান থেকে কার্যকর করা চলে।
জেনারেটরগুলিতে ফিরে আসছেন: আপনি যখন __iter__
কোনও জেনারেটরে কল করেন, এটি কেবল নিজের কাছে ফিরে আসে।
>>> x = (a for a in "boring generator")
>>> id(x)
51502272
>>> id(x.__iter__())
51502272
এর অর্থ হ'ল আপনি যে জিনিসটির সাথে এটি করতে চান তা থেকে কোনও কিছুর উপরে পুনরাবৃত্তি আলাদা করতে পারেন এবং সেই আচরণের মধ্য দিয়ে পরিবর্তন করতে পারেন। নীচে, লক্ষ্য করুন যে কীভাবে একই জেনারেটরটি দুটি লুপে ব্যবহৃত হয় এবং দ্বিতীয়টিতে এটি প্রথম থেকে যেখানে ছেড়ে যায় সেখান থেকে এটি কার্যকর করা শুরু করে।
>>> generator = (x for x in 'more boring stuff')
>>> for letter in generator:
print(ord(letter))
if letter > 'p':
break
109
111
114
>>> for letter in generator:
print(letter)
e
b
o
r
i
n
g
s
t
u
f
f
অলস মূল্যায়ন
তালিকার সাথে তুলনায় জেনারেটরগুলির নীচের দিকগুলির একটি হ'ল আপনি কোনও জেনারেটরে অ্যাক্সেস করতে পারবেন কেবল তার পরের জিনিসটি of আপনি আর আগের ফলাফল হিসাবে ফিরে যেতে পারবেন না, বা মধ্যবর্তী ফলাফলগুলি না পেরিয়ে কোনও একটিতে এগিয়ে যান। এর উপরের অংশটি একটি জেনারেটর এর সমতুল্য তালিকার তুলনায় প্রায় কোনও স্মৃতি নিতে পারে না।
>>> import sys
>>> sys.getsizeof([x for x in range(10000)])
43816
>>> sys.getsizeof(range(10000000000))
24
>>> sys.getsizeof([x for x in range(10000000000)])
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
sys.getsizeof([x for x in range(10000000000)])
File "<pyshell#10>", line 1, in <listcomp>
sys.getsizeof([x for x in range(10000000000)])
MemoryError
জেনারেটরগুলিও অলসভাবে বেঁধে রাখা যেতে পারে।
logfile = open("logs.txt")
lastcolumn = (line.split()[-1] for line in logfile)
numericcolumn = (float(x) for x in lastcolumn)
print(sum(numericcolumn))
প্রথম, দ্বিতীয় এবং তৃতীয় রেখাগুলি কেবল প্রতিটি জেনারেটর সংজ্ঞায়িত করে তবে কোনও আসল কাজ করে না। যখন শেষ লাইনটি ডাকা হয়, যোগফলের জন্য একটি সংখ্যাটির জন্য সংখ্যার কলম জিজ্ঞাসা করে, সংখ্যার কলামটি লাস্টক্লম থেকে একটি মান প্রয়োজন, লাস্টক্লম লগফাইলে একটি মান জিজ্ঞাসা করে, যা আসলে ফাইলটি থেকে একটি লাইন পড়ে। যোগফলটি প্রথম পূর্ণসংখ্যা না পাওয়া পর্যন্ত এই স্ট্যাকটি উন্মুক্ত করা হয়। তারপরে, প্রক্রিয়াটি আবার দ্বিতীয় লাইনের জন্য ঘটে। এই মুহুর্তে, যোগফলের দুটি পূর্ণসংখ্যা থাকে এবং এটি তাদের একসাথে যুক্ত করে। নোট করুন যে তৃতীয় লাইনটি এখনও ফাইল থেকে পড়েনি। এরপরে অঙ্কগুলি অঙ্কের কলামটি (অবধি চেনের সম্পূর্ণ অংশ থেকে পুরোপুরি অবজ্ঞাত) থেকে অনুরোধ করে এবং সংখ্যার ক্রম অবসন্ন না হওয়া পর্যন্ত এগুলি যুক্ত করে চলেছে Sum
এখানে সত্যই আকর্ষণীয় অংশটি হ'ল লাইনগুলি পৃথকভাবে পড়া, গ্রাস করা এবং ফেলে দেওয়া হয়। কোনও মুহুর্তে পুরো ফাইলটি একবারে মেমরির মধ্যে নেই। এই লগ ফাইলটি বলুন, একটি টেরাবাইট হলে কী হবে? এটি কেবল কাজ করে, কারণ এটি একবারে কেবল একটি লাইন পড়ে।
উপসংহার
এটি পাইথনের সমস্ত জেনারেটরের ব্যবহারের সম্পূর্ণ পর্যালোচনা নয়। উল্লেখযোগ্যভাবে, আমি অসীম জেনারেটর, রাষ্ট্র মেশিনগুলি, মানগুলিতে ফিরে যাওয়া এবং কর্টিনগুলির সাথে তাদের সম্পর্ক এড়িয়ে চলেছি।
আমি বিশ্বাস করি যে এটি নির্ধারণ করার পক্ষে যথেষ্ট যে আপনার জেনারেটরগুলি একটি পরিষ্কারভাবে সংহত, দরকারী ভাষা বৈশিষ্ট্য হিসাবে থাকতে পারে।
yield
মূলত একটি স্টেট ইঞ্জিন। এটি প্রতিবার একই ফলাফল ফেরত দেওয়ার উদ্দেশ্যে নয়। এটি নিখুঁত সুনির্দিষ্টতার সাথে যা করবে তা হ'ল প্রতিবারের অনুরোধের সময় পরবর্তী আইটেমটি একটি গণনার মধ্যে ফিরিয়ে আনতে হবে। থ্রেড প্রয়োজন হয় না; আপনার বর্তমান অবস্থা বজায় রাখার জন্য আপনার একটি ক্লোজার (কম বেশি) প্রয়োজন।