প্রসঙ্গ
ধরুন আমার কাছে নিম্নলিখিত পাইথন কোড রয়েছে:
def example_function(numbers, n_iters):
sum_all = 0
for number in numbers:
for _ in range(n_iters):
number = halve(number)
sum_all += number
return sum_all
ns = [1, 3, 12]
print(example_function(ns, 3))
example_functionএখানে nsফলাফলের সঞ্চারের সময় তালিকার প্রতিটি উপাদানকে কেবল 3 বার অর্ধেক করে দেওয়া হয়। এই স্ক্রিপ্টটি চালানোর আউটপুট কেবল:
2.0
যেহেতু 1 / (2 ^ 3) * (1 + 3 + 12) = 2।
এখন, আসুন আমরা বলি যে (কোনও কারণে, সম্ভবত ডিবাগিং, বা লগিং), আমি গ্রহণ করছি মধ্যবর্তী পদক্ষেপগুলি সম্পর্কে কিছু ধরণের তথ্য প্রদর্শন করতে চাই example_function। হয়তো আমি তখন এই ফাংশনটি আবার কিছু লিখতে চাই:
def example_function(numbers, n_iters):
sum_all = 0
for number in numbers:
print('Processing number', number)
for i_iter in range(n_iters):
number = number/2
print(number)
sum_all += number
print('sum_all:', sum_all)
return sum_all
যা এখন, আগের মত একই যুক্তি দিয়ে ডাকলে, নিম্নলিখিতগুলি আউটপুট দেয়:
Processing number 1
0.5
0.25
0.125
sum_all: 0.125
Processing number 3
1.5
0.75
0.375
sum_all: 0.5
Processing number 12
6.0
3.0
1.5
sum_all: 2.0
এটি ঠিক আমার উদ্দেশ্যটি অর্জন করেছিল। তবে, এই example_functionনীতিটির বিপরীতে কিছুটা যায় যে কোনও ফাংশনটিতে কেবল একটি কাজ করা উচিত এবং এখন এর কোডটি স্লাগভাবে দীর্ঘতর এবং আরও জটিল। এই জাতীয় কোনও সাধারণ ক্রিয়াকলাপের জন্য এটি কোনও সমস্যা নয় তবে আমার প্রসঙ্গে আমার একে অপরকে কল করা বেশ জটিল ফাংশন রয়েছে এবং মুদ্রণ বিবৃতিগুলি প্রায়শই এখানে দেখানো থেকে আরও জটিল পদক্ষেপগুলিতে জড়িত, যার ফলে আমার কোডের জটিলতায় যথেষ্ট পরিমাণে বৃদ্ধি ঘটে (একের জন্য আমার ফাংশনগুলির লগিং সম্পর্কিত কোডের আরও লাইন ছিল এর প্রকৃত উদ্দেশ্য সম্পর্কিত লাইনগুলি তুলনায়!)।
তদুপরি, যদি আমি পরে সিদ্ধান্ত নিই যে আমি আর আমার ফাংশনটিতে কোনও মুদ্রণ বিবৃতি চাই না, আমাকে এই কার্যকারিতা সম্পর্কিত কোনও ভেরিয়েবলের পাশাপাশি example_functionসমস্ত printবিবৃতি নিজেই মুছে ফেলতে হবে , যা প্রক্রিয়া ক্লান্তিকর এবং ত্রুটি উভয়ই is -prone।
পরিস্থিতি আরও খারাপ হয় যদি আমি সবসময় ফাংশন সম্পাদনের সময় মুদ্রণ বা মুদ্রণ না করার সম্ভাবনা থাকতে চাই, তবে আমাকে দুটি অত্যন্ত অনুরূপ ফাংশন ( printবিবৃতিতে একটি ছাড়া একটি) ঘোষণা করতে পরিচালিত করি, যা বজায় রাখার জন্য ভয়ানক, বা এর মতো কিছু সংজ্ঞায়িত করতে:
def example_function(numbers, n_iters, debug_mode=False):
sum_all = 0
for number in numbers:
if debug_mode:
print('Processing number', number)
for i_iter in range(n_iters):
number = number/2
if debug_mode:
print(number)
sum_all += number
if debug_mode:
print('sum_all:', sum_all)
return sum_all
যার ফলস্বরূপ আমাদের একটি সাধারণ ক্ষেত্রেও একটি ফুলে যাওয়া এবং (আশাবাদী) অযথা জটিল ফাংশনের ফলাফল example_function।
প্রশ্ন
এর মূল কার্যকারিতা থেকে মুদ্রণ কার্যকারিতা "ডিকুবল" করার কোনও অজগর উপায় আছে example_function?
আরও সাধারণভাবে, কোনও ফাংশনের মূল উদ্দেশ্য থেকে alচ্ছিক কার্যকারিতা ডিকুয়াল করার অজগর উপায় আছে কি?
আমি এ পর্যন্ত যা চেষ্টা করেছি:
এই মুহুর্তে আমি যে সমাধানটি পেয়েছি তা হ'ল ডেকপলিংয়ের জন্য কলব্যাকগুলি ব্যবহার করছে। উদাহরণস্বরূপ, কেউ এর example_functionমতো আবারও লিখতে পারেন :
def example_function(numbers, n_iters, callback=None):
sum_all = 0
for number in numbers:
for i_iter in range(n_iters):
number = number/2
if callback is not None:
callback(locals())
sum_all += number
return sum_all
এবং তারপরে একটি কলব্যাক ফাংশন সংজ্ঞায়িত করে যা আমি চাই মুদ্রণ কার্যকারিতা সম্পাদন করে:
def print_callback(locals):
print(locals['number'])
এবং example_functionএই মত কল :
ns = [1, 3, 12]
example_function(ns, 3, callback=print_callback)
যা তখন ফলাফল:
0.5
0.25
0.125
1.5
0.75
0.375
6.0
3.0
1.5
2.0
এটি বেসের কার্যকারিতা থেকে মুদ্রণের কার্যকারিতা সাফল্যের সাথে ডিউপল করে example_function। তবে এই পদ্ধতির মূল সমস্যাটি হ'ল কলব্যাক ফাংশনটি কেবলমাত্র একটি নির্দিষ্ট অংশে চালানো যেতে পারে example_function(এই ক্ষেত্রে ডানদিকে বর্তমান নম্বর অর্ধেকের পরে), এবং সমস্ত মুদ্রণ ঠিক সেখানে ঘটতে হবে। এটি কখনও কখনও কলব্যাক ফাংশনের নকশাকে বেশ জটিল করে তোলে (এবং কিছু আচরণ অর্জন করা অসম্ভব করে তোলে)।
উদাহরণস্বরূপ, যদি কেউ প্রশ্নের পূর্ববর্তী অংশে ঠিক একই ধরণের মুদ্রণ অর্জন করতে চান (কোন নম্বরটি প্রক্রিয়াজাত করা হচ্ছে তা দেখানো হচ্ছে, এর সাথে সম্পর্কিত অংশগুলি সহ) ফলাফলটি কলব্যাক হবে:
def complicated_callback(locals):
i_iter = locals['i_iter']
number = locals['number']
if i_iter == 0:
print('Processing number', number*2)
print(number)
if i_iter == locals['n_iters']-1:
print('sum_all:', locals['sum_all']+number)
যার ফলশ্রুতি হ'ল আগের মতো একই আউটপুট:
Processing number 1.0
0.5
0.25
0.125
sum_all: 0.125
Processing number 3.0
1.5
0.75
0.375
sum_all: 0.5
Processing number 12.0
6.0
3.0
1.5
sum_all: 2.0
তবে এটি লিখতে, পড়তে এবং ডিবাগ করার জন্য ব্যথা।
loggingমডিউলটি এখানে কীভাবে সহায়তা করবে তা আমি দেখছি না । যদিও printপ্রসঙ্গটি সেট আপ করার সময় আমার প্রশ্ন বিবৃতিগুলি ব্যবহার করে, আমি আসলে কোনও ফাংশনের মূল উদ্দেশ্য থেকে কোনও ধরণের alচ্ছিক কার্যকারিতা কীভাবে ডিকুয়েল করব তার একটি সমাধান খুঁজছি। উদাহরণস্বরূপ, সম্ভবত আমি জিনিসগুলি রান করার সাথে সাথে প্লট করার জন্য একটি ফাংশন চাই। সেক্ষেত্রে আমি বিশ্বাস করি যে loggingমডিউলটি প্রযোজ্য হবে না।
logging), তবে কীভাবে স্বেচ্ছাসেবক কোড আলাদা করবেন না।
loggingমডিউলটি দেখুন