উত্তর:
অভ্যন্তরীণ ফাংশনগুলি 2.x এ ননলোকাল ভেরিয়েবলগুলি পড়তে পারে , কেবল সেগুলি পুনরায় ফিরিয়ে আনবে না। এটি বিরক্তিকর, তবে আপনি এটি চারপাশে কাজ করতে পারেন। কেবল একটি অভিধান তৈরি করুন এবং এতে আপনার উপাদানটিকে উপাদান হিসাবে সংরক্ষণ করুন। ইনার ফাংশন থেকে নিষিদ্ধ করা হয় না mutating যে বস্তু nonlocal ভেরিয়েবল পড়ুন।
উইকিপিডিয়া থেকে উদাহরণ ব্যবহার করতে:
def outer():
d = {'y' : 0}
def inner():
d['y'] += 1
return d['y']
return inner
f = outer()
print(f(), f(), f()) #prints 1 2 3
def inner(): print d; d = {'y': 1}
। এখানে, print d
বাইরের সার্চ d
এইভাবে nonlocal পরিবর্তনশীল তৈরি d
ভেতরের সুযোগ।
X = 1
কেবল X
কোনও নির্দিষ্ট বস্তুর ( int
মান সহ একটি 1
) সাথে নামটিকে আবদ্ধ করে । X = 1; Y = X
একই সঠিক অবজেক্টে দুটি নাম বেঁধে রাখে। যাইহোক, কিছু বস্তু পরিবর্তনযোগ্য এবং আপনি তাদের মান পরিবর্তন করতে পারেন।
এলিয়াস জামারিয়ার উত্তর দ্বারা নিম্নলিখিত সমাধানটি অনুপ্রাণিত হয়েছে , তবে এই উত্তরের বিপরীতে বাইরের ফাংশনের একাধিক কল সঠিকভাবে পরিচালনা করা সম্ভব নয়। "ভেরিয়েবল" inner.y
বর্তমান কলটির স্থানীয় outer
। কেবল এটি পরিবর্তনশীল নয়, যেহেতু এটি নিষিদ্ধ, তবে একটি অবজেক্ট অ্যাট্রিবিউট (অবজেক্টটি inner
নিজেই ফাংশন হিসাবে কাজ করছে)। এটি খুব কুরুচিপূর্ণ (নোট করুন যে inner
ফাংশনটি সংজ্ঞায়িত করার পরে অ্যাট্রিবিউটটি তৈরি করা যেতে পারে ) তবে কার্যকর বলে মনে হয়।
def outer():
def inner():
inner.y += 1
return inner.y
inner.y = 0
return inner
f = outer()
g = outer()
print(f(), f(), g(), f(), g()) #prints (1, 2, 1, 3, 2)
inc()
এবং dec()
ফিরে আসা বলুন যে বৃদ্ধি এবং হ্রাস একটি ভাগ করা কাউন্টার। তারপরে আপনার বর্তমান কাউন্টার মানটি সংযুক্ত করার জন্য কোন ফাংশনটি স্থির করতে হবে এবং অন্য (গুলি) থেকে সেই ফাংশনটি উল্লেখ করতে হবে। যা দেখতে কিছুটা অদ্ভুত এবং অসম্পূর্ণ দেখায়। যেমন dec()
একটি লাইনে inc.value -= 1
।
অভিধানের বদলে ননলোকাল ক্লাসে কম বিশৃঙ্খলা নেই । @ ক্রিসিবের উদাহরণ পরিবর্তন করা :
def outer():
class context:
y = 0
def inner():
context.y += 1
return context.y
return inner
তারপর
f = outer()
assert f() == 1
assert f() == 2
assert f() == 3
assert f() == 4
প্রতিটি বাইরের () কল একটি নতুন এবং স্বতন্ত্র শ্রেণি তৈরি করে যা প্রসঙ্গে বলা হয় (কেবল একটি নতুন উদাহরণ নয়)। সুতরাং এটি ভাগ করে নেওয়া প্রসঙ্গে @ নাথানিয়েলের সচেতনতা এড়িয়ে চলে ।
g = outer()
assert g() == 1
assert g() == 2
assert f() == 5
__slots__ = ()
ক্লাস ব্যবহার না করে কোনও বস্তু যুক্ত করে তৈরি করে যেমন context.z = 3
একটি বাড়িয়ে তোলে AttributeError
। সমস্ত শ্রেণীর পক্ষে এটি সম্ভব, যদি না তারা কোনও শ্রেণীর উত্তরাধিকার সূত্রে সংজ্ঞায়িত না করে inherit
আমি মনে করি যে এখানে "কী" অ্যাক্সেস বলতে কী বোঝায় key ক্লোজার স্কোপের বাইরে কোনও ভেরিয়েবল পড়া নিয়ে কোনও সমস্যা হওয়া উচিত নয়, যেমন,
x = 3
def outer():
def inner():
print x
inner()
outer()
প্রত্যাশিত হিসাবে কাজ করা উচিত (মুদ্রণ 3)। তবে এক্স এর মানকে ওভাররাইড করা কাজ করে না, যেমন,
x = 3
def outer():
def inner():
x = 5
inner()
outer()
print x
এখনও 3 মুদ্রণ করবে 3. আমার পিইপি -3104 বোঝার থেকে ননলোকাল কীওয়ার্ডটি coverেকে দেওয়া বোঝানো হচ্ছে। পিইপিতে উল্লিখিত হিসাবে, আপনি একই জিনিস (ধরণের ধরণের গোলযোগ) সম্পাদন করতে একটি শ্রেণি ব্যবহার করতে পারেন:
class Namespace(object): pass
ns = Namespace()
ns.x = 3
def outer():
def inner():
ns.x = 5
inner()
outer()
print ns.x
def ns(): pass
তারপরে ns.x = 3
। এটি সুন্দর নয়, তবে এটি আমার চোখে কিছুটা কুৎসিত।
class Namespace: x = 3
?
ns
একটি বিশ্বব্যাপী অবজেক্ট, যার কারণেই আপনি বিবৃতিতে ns.x
মডিউল স্তরে print
একেবারে শেষের দিকে উল্লেখ করতে পারেন ।
পাইথন 2 এ ননলোকাল ভেরিয়েবলগুলি প্রয়োগ করার আরও একটি উপায় রয়েছে, যদি এখানে যে কোনও উত্তরই যে কোনও কারণেই অনাকাঙ্ক্ষিত হয়:
def outer():
outer.y = 0
def inner():
outer.y += 1
return outer.y
return inner
f = outer()
print(f(), f(), f()) #prints 1 2 3
ভেরিয়েবলের অ্যাসাইনমেন্ট স্টেটমেন্টে ফাংশনের নামটি ব্যবহার করা অপ্রয়োজনীয়, তবে এটি একটি অভিধানে ভেরিয়েবলটি রাখার চেয়ে আমার কাছে সহজ এবং পরিস্কার মনে হয়। ক্রিস বি এর উত্তরের মতোই একটি কল থেকে অন্য কলটিতে মানটি মনে হয় remembered
f = outer()
এবং পরে করেন g = outer()
তবে f
তার পাল্টা পুনরায় সেট করা হবে। এর কারণ হল তারা উভয় ভাগ একটি হল একক outer.y
পরিবর্তনশীল, বরং প্রতিটি তাদের নিজস্ব স্বাধীন এক থাকার চেয়ে। যদিও এই কোডটি ক্রিস বিয়ের উত্তরের চেয়ে আরও নান্দনিকভাবে আনন্দদায়ক দেখায়, তবে আপনি যদি outer
একবারের বেশি বার কল করতে চান তবে তার উপায়টি লেজিক স্কোপিং অনুকরণ করার একমাত্র উপায় বলে মনে হচ্ছে ।
outer.y
ফাংশন কল (উদাহরণস্বরূপ) তে স্থানীয় কিছু জড়িত না outer()
, তবে outer
তার ঘেরের সুযোগে নামের সাথে আবদ্ধ ফাংশন অবজেক্টের একটি বিশেষত্বকে বরাদ্দ করে । এবং সেই জন্য লিখিতভাবে outer.y
, এর পরিবর্তে অন্য কোনও নাম সমভাবে ভালভাবে ব্যবহার করা যেতে পারে outer
তবে শর্ত থাকে যে এটি সেই সুযোগে আবদ্ধ। এটা কি সঠিক?
outer.y
নামটি ব্যবহার না করে inner.y
(যেহেতু inner
আমরা কলটির অভ্যন্তরে আবদ্ধ outer()
, যা আমরা চাই ঠিক তেমন সুযোগ), কিন্তু রাখছি অন্তর্নিহিত সংজ্ঞার inner.y = 0
পরে সূচনা (যেমন তার বৈশিষ্ট্যটি তৈরি হওয়ার সময় বস্তুটি অবশ্যই উপস্থিত থাকতে হবে) তবে অবশ্যই আগে ? return inner
অ্যালোস মাহদল আরেকটি উত্তর সম্পর্কে একটি মন্তব্যে করা পরামর্শের দ্বারা অনুপ্রাণিত এমন কিছু এখানে রয়েছে :
class Nonlocal(object):
""" Helper to implement nonlocal names in Python 2.x """
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def outer():
nl = Nonlocal(y=0)
def inner():
nl.y += 1
return nl.y
return inner
f = outer()
print(f(), f(), f()) # -> (1 2 3)
হালনাগাদ
সম্প্রতি এটি পিছনে তাকানোর পরে, আমি কীভাবে ডেকোরেটর-এর মতো হয়েছিল তা দেখে আমি আশ্চর্য হয়ে গিয়েছিলাম — যখন এটি আমার উপর প্রকাশিত হয়েছিল যে একে হিসাবে প্রয়োগ করা এটি আরও জেনারিক এবং দরকারী করে তুলবে (যদিও তর্কসাপেক্ষভাবে এটির পাঠ্যতাকে কিছুটা ডিগ্রী করে দেয়)।
# Implemented as a decorator.
class Nonlocal(object):
""" Decorator class to help implement nonlocal names in Python 2.x """
def __init__(self, **kwargs):
self._vars = kwargs
def __call__(self, func):
for k, v in self._vars.items():
setattr(func, k, v)
return func
@Nonlocal(y=0)
def outer():
def inner():
outer.y += 1
return outer.y
return inner
f = outer()
print(f(), f(), f()) # -> (1 2 3)
নোট করুন যে উভয় সংস্করণ পাইথন 2 এবং 3 উভয়তেই কাজ করে।
পাইথনের স্কোপিং বিধিগুলিতে একটি ওয়ার্ট রয়েছে - অ্যাসাইনমেন্টটি তার তত্ক্ষণাত বন্ধ করে ফাংশন স্কোপে একটি পরিবর্তনীয় স্থানীয় করে তোলে। গ্লোবাল ভেরিয়েবলের জন্য, আপনি global
কীওয়ার্ড দিয়ে এটি সমাধান করবেন ।
সমাধানটি হ'ল দুটি বস্তুর মধ্যে ভাগ করে নেওয়া এমন কোনও বস্তুর পরিচয় করিয়ে দেওয়া, যার মধ্যে পারস্পরিক পরিবর্তনশীল থাকে তবে এটি নিজেকে ভেরিয়েবলের মাধ্যমে উল্লেখ করা হয় যা বরাদ্দ করা হয়নি।
def outer(v):
def inner(container = [v]):
container[0] += 1
return container[0]
return inner
একটি বিকল্প হ'ল কিছু স্কোপ হ্যাকারি:
def outer(v):
def inner(varname = 'v', scope = locals()):
scope[varname] += 1
return scope[varname]
return inner
প্যারামিটারটির নামটি পেতে আপনি কিছু কৌশল বুঝতে পারেন outer
এবং তারপরে এটি নাম হিসাবে পাস করতে পারেন, তবে নামের উপর নির্ভর না করে আপনার outer
ওয়াই সংযুক্তকারীটি ব্যবহার করা প্রয়োজন।
nonlocal
। locals()
সৃষ্টি একটি অভিধান outer()
সময়ে গুলি স্থানীয়দের inner()
সংজ্ঞায়িত কিন্তু পরিবর্তন যে অভিধান করে হয় না পরিবর্তন v
মধ্যে outer()
। আপনার আরও অভ্যন্তরীণ ফাংশন রয়েছে যা বন্ধ ওভার ভেরিয়েবলটি ভাগ করতে চায় যখন এটি আর কাজ করবে না। একটি বলুন inc()
এবং dec()
সেই বৃদ্ধি এবং হ্রাস একটি ভাগ করা কাউন্টার।
nonlocal
একটি অজগর 3 বৈশিষ্ট্য।
nonlocal
পাইথন 2 এর সাধারণভাবে পাইথন 3 এর প্রভাব কীভাবে অর্জন করা যায় । আপনার ধারণাগুলি সাধারণ ক্ষেত্রে কভার করে না তবে কেবল একটি অভ্যন্তরীণ ফাংশন সহ। একটি উদাহরণের জন্য এই টুকরো তাকান । উভয় অভ্যন্তর ফাংশন নিজস্ব ধারক আছে। বাইরের ফাংশনটির সুযোগে আপনার একটি পরিবর্তনীয় বস্তুর প্রয়োজন, অন্য উত্তরগুলি ইতিমধ্যে প্রস্তাবিত হিসাবে।
nonlocal
শব্দ পাইথন 3. চালু
এটি করার আরেকটি উপায় (যদিও এটি খুব ভার্বোস):
import ctypes
def outer():
y = 0
def inner():
ctypes.pythonapi.PyCell_Set(id(inner.func_closure[0]), id(y + 1))
return y
return inner
x = outer()
x()
>> 1
x()
>> 2
y = outer()
y()
>> 1
x()
>> 3
ব্যবহারিক এবং কিছুটা কম মার্জিত ব্যবহারের ক্ষেত্রে উপরের দিকে মার্টিনো মার্জিত সমাধান বাড়ানো:
class nonlocals(object):
""" Helper to implement nonlocal names in Python 2.x.
Usage example:
def outer():
nl = nonlocals( n=0, m=1 )
def inner():
nl.n += 1
inner() # will increment nl.n
or...
sums = nonlocals( { k:v for k,v in locals().iteritems() if k.startswith('tot_') } )
"""
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __init__(self, a_dict):
self.__dict__.update(a_dict)
গ্লোবাল ভেরিয়েবল ব্যবহার করুন
def outer():
global y # import1
y = 0
def inner():
global y # import2 - requires import1
y += 1
return y
return inner
f = outer()
print(f(), f(), f()) #prints 1 2 3
ব্যক্তিগতভাবে, আমি গ্লোবাল ভেরিয়েবলগুলি পছন্দ করি না। তবে, আমার প্রস্তাবটি https://stackoverflow.com/a/19877437/1083704 উত্তরের উপর ভিত্তি করে
def report():
class Rank:
def __init__(self):
report.ranks += 1
rank = Rank()
report.ranks = 0
report()
যেখানে ব্যবহারকারীকে বিশ্বব্যাপী ভেরিয়েবল ঘোষণা ranks
করতে হবে, প্রতিবার আপনাকে কল করতে হবে report
। আমার উন্নতি ব্যবহারকারী থেকে ফাংশন ভেরিয়েবল আরম্ভ করার প্রয়োজনীয়তা দূর করে elim
inner
, তবে এটি বরাদ্দ করতে পারবেন না তবে আপনি এর কীগুলি এবং মানগুলি সংশোধন করতে পারেন। এটি গ্লোবাল ভেরিয়েবলের ব্যবহার এড়িয়ে চলে।