ব্যাখ্যা
এখানে সমস্যাটি হ'ল i
ফাংশনটি f
তৈরি হয়ে গেলে এর মান সংরক্ষণ করা হয় না । বরং কখন ডাকাf
হবে তার মান সন্ধান করুন ।i
আপনি যদি এটির বিষয়ে চিন্তা করেন তবে এই আচরণটি সঠিক ধারণা দেয়। প্রকৃতপক্ষে, এটি একমাত্র যুক্তিযুক্ত উপায় যা কাজ করতে পারে work কল্পনা করুন যে আপনার এমন একটি ফাংশন রয়েছে যা বৈশ্বিক চলকটি অ্যাক্সেস করে, এর মতো:
global_var = 'foo'
def my_function():
print(global_var)
global_var = 'bar'
my_function()
আপনি যখন এই কোডটি পড়বেন, আপনি অবশ্যই - এটি "বার" মুদ্রণ করবেন বলে আশা করবেন, "ফু" নয়, কারণ global_var
ফাংশন ঘোষণার পরে এর মান পরিবর্তিত হয়েছে। একই জিনিসটি আপনার নিজের কোডে ঘটছে: আপনি কল f
করার সময়টির মান i
পরিবর্তন হয়ে গেছে এবং সেট হয়ে গেছে 2
।
সমাধান
এই সমস্যাটি সমাধান করার অনেক উপায় রয়েছে। এখানে কয়েকটি বিকল্প রয়েছে:
i
এটিকে ডিফল্ট আর্গুমেন্ট হিসাবে ব্যবহার করে তাড়াতাড়ি বাইন্ডিং বাধ্য করুন
ক্লোজার ভেরিয়েবলগুলি (যেমন i
) এর বিপরীতে , ফাংশনটি সংজ্ঞায়িত হওয়ার সাথে সাথে ডিফল্ট আর্গুমেন্টগুলি তত্ক্ষণাত মূল্যায়ন করা হয়:
for i in range(3):
def f(i=i):
return i
functions.append(f)
এটি কীভাবে / কেন কাজ করে তা সম্পর্কে একটু অন্তর্দৃষ্টি দেওয়ার জন্য: একটি ফাংশনের ডিফল্ট আর্গুমেন্টগুলি ফাংশনের একটি বৈশিষ্ট হিসাবে সংরক্ষণ করা হয়; সুতরাং এর বর্তমান মান i
স্ন্যাপশট এবং সংরক্ষণ করা হয়।
>>> i = 0
>>> def f(i=i):
... pass
>>> f.__defaults__
(0,)
>>>
>>> i = 5
>>> f.__defaults__
(0,)
i
বন্ধের বর্তমান মান ক্যাপচার জন্য একটি ফাংশন কারখানা ব্যবহার করুন
আপনার সমস্যার মূল এটি i
হ'ল একটি পরিবর্তনশীল যা পরিবর্তন করতে পারে। আমরা আর কোনও পরিবর্তনশীল তৈরি না করে যা কখনই পরিবর্তিত হবে না তার গ্যারান্টিযুক্ত এই সমস্যাটি ঘিরে কাজ করতে পারি - এবং এটি করার সবচেয়ে সহজ উপায় হ'ল একটি বন্ধ :
def f_factory(i):
def f():
return i
return f
for i in range(3):
f = f_factory(i)
functions.append(f)
ব্যবহার করুন functools.partial
বর্তমান মূল্য জুড়তে অনুমতি i
থেকেf
functools.partial
আপনাকে একটি বিদ্যমান ফাংশনে যুক্তি যুক্ত করতে দেয়। একরকম, এটিও এক ধরণের ফাংশন কারখানা।
import functools
def f(i):
return i
for i in range(3):
f_with_i = functools.partial(f, i)
functions.append(f_with_i)
ক্যাভ্যাট: আপনি যদি ভেরিয়েবলকে একটি নতুন মান নির্ধারণ করেন তবে এই সমাধানগুলি কেবলমাত্র কার্যকর হয়। আপনি যদি ভেরিয়েবলে সঞ্চিত বস্তুটি পরিবর্তন করেন তবে আপনি আবার একই সমস্যাটি অনুভব করবেন:
>>> i = []
>>> def f(i=i):
... print('i =', i)
...
>>> i.append(5)
>>> f()
i = [5]
i
আমরা এটি একটি ডিফল্ট যুক্তিতে রূপান্তরিত করেও কীভাবে পরিবর্তন হয়েছে তা লক্ষ্য করুন ! আপনার কোড যদি mutates i
, তাহলে আপনি একটি কেনে কপি এর i
আপনার ফাংশন, তাই পছন্দ:
def f(i=i.copy()):
f = f_factory(i.copy())
f_with_i = functools.partial(f, i.copy())