python - কিভাবে রেফারেন্স দ্বারা একটি পরিবর্তনশীল পাস করব?




reference parameter-passing (16)

পাইথন ডকুমেন্টেশনগুলি রেফারেন্স বা মান দ্বারা প্রেরিত হয় কিনা তা সম্পর্কে অস্পষ্ট বলে মনে হয় এবং নিম্নলিখিত কোডটি অপরিবর্তিত মান 'মূল'

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

প্রকৃত রেফারেন্স দ্বারা পরিবর্তনশীল পাস করতে কিছু আছে কি?


পাইথন কোন পরিবর্তনশীল আছে

পরামিতি ক্ষণস্থায়ী বুঝতে চাবি "পরিবর্তনশীল" সম্পর্কে চিন্তা বন্ধ করা হয়। Python এ নাম এবং বস্তু রয়েছে এবং তারা একসাথে ভেরিয়েবলের মত উপস্থিত রয়েছে, তবে এটি সর্বদা তিনটি পৃথক করার জন্য উপকারী।

  1. পাইথন নাম এবং বস্তু আছে।
  2. অ্যাসাইনমেন্ট একটি বস্তুর একটি নাম binds।
  3. একটি ফাংশনে একটি আর্গুমেন্ট পাস করলেও একটি বস্তুর নাম (ফাংশনের প্যারামিটার নাম) আবদ্ধ হয়।

যে সব আছে। পরিবর্তন এই প্রশ্নের জন্য অপ্রাসঙ্গিক।

উদাহরণ:

a = 1

এটি নামটি টাইপ করে এমন একটি বস্তুর টাইপ পূর্ণসংখ্যা যা মান 1 ধরে থাকে।

b = x

এই নামটি b কে একই বস্তুর সাথে আবদ্ধ করে যা x নামটি বর্তমানে আবদ্ধ। তারপরে, নামের b নাম x সাথে আর কিছুই করার নেই।

পাইথন 3 ভাষা রেফারেন্সে বিভাগ 3.1 এবং 4.2 দেখুন।

সুতরাং প্রশ্নটিতে প্রদর্শিত self.Change(self.variable) , self.Change(self.variable) নামটি ' var (কার্যকারিতা Change করার self.Change(self.variable) নামটি 'Original' এবং অ্যাসাইনমেন্ট var = 'Changed' ফাংশন Change শরীরের মধ্যে) একই নাম আবার বরাদ্দ: কিছু অন্যান্য বস্তুর (যে একটি স্ট্রিং রাখা পাশাপাশি অন্য কিছু সম্পূর্ণ হতে পারে)।


(সম্পাদনা - ব্লেয়ার তার ব্যাপক জনপ্রিয় উত্তর আপডেট করেছে যাতে এটি সঠিক হয়)

আমার মনে হয় গুরুত্বপূর্ণ যে সর্বাধিক ভোট (ব্লেয়ার কনরাড দ্বারা) বর্তমান পোস্টটি, তার ফলাফলের সাথে সঠিক হওয়া সত্ত্বেও, ভুল পথে চলছে এবং এর সংজ্ঞাগুলির ভিত্তিতে সীমারেখা ভুল। যদিও অনেকগুলি ভাষা রয়েছে (যেমন সি) যা ব্যবহারকারীকে রেফারেন্স দ্বারা পাস করে বা মান দ্বারা পাস করতে দেয় তবে পাইথন তাদের মধ্যে একটি নয়।

ডেভিড কোরনাপাউর উত্তরটি প্রকৃত উত্তরকে নির্দেশ করে এবং ব্যাখ্যা করে যে ব্লেয়ার কনরাডের পোস্টের আচরণ সঠিক বলে মনে হয় না কেন।

পাইথন মান দ্বারা পাসের পরিমাণে, সমস্ত ভাষাগুলি মূল্যের দ্বারা কিছু পাস করে (যেহেতু এটি একটি "মান" বা "রেফারেন্স") পাঠানো আবশ্যক। যাইহোক, এর মানে এই নয় যে পাইথনটি মান অনুসারে পাস করে যে সি প্রোগ্রামার এটি সম্পর্কে চিন্তা করবে।

আপনি যদি আচরণ চান, ব্লেয়ার কনরাড এর উত্তর জরিমানা। কিন্তু যদি আপনি পাইথনকে মূল্যের দ্বারা পাস না করে বা রেফারেন্স দ্বারা পাস করতে না পারার কারণে বাদাম এবং বোল্ট জানতে চান তবে ডেভিড কোরনাপেউর উত্তরটি পড়ুন।


আপনি এখানে কিছু সত্যিই ভাল উত্তর পেয়েছেন।

x = [ 2, 4, 4, 5, 5 ]
print x  # 2, 4, 4, 5, 5

def go( li ) :
  li = [ 5, 6, 7, 8 ]  # re-assigning what li POINTS TO, does not
  # change the value of the ORIGINAL variable x

go( x ) 
print x  # 2, 4, 4, 5, 5  [ STILL! ]


raw_input( 'press any key to continue' )

আমি অন্যান্য উত্তরগুলি বরং দীর্ঘ এবং জটিল খুঁজে পেয়েছিলাম, তাই পাইথন ভেরিয়েবল এবং প্যারামিটারগুলিকে চেনার উপায় ব্যাখ্যা করার জন্য আমি এই সহজ চিত্রটি তৈরি করেছি।


এই ক্ষেত্রে পরিবর্তনশীল শিরোনামের পরিবর্তে var self.variable হয় self.variable একটি রেফারেন্স বরাদ্দ করা self.variable , এবং আপনি অবিলম্বে var থেকে একটি স্ট্রিং বরাদ্দ করেন। এটা আর self.variable ইঙ্গিত করা self.variable । নিম্নোক্ত কোড স্নিপেট দেখায় কি হবে যদি আপনি var এবং self.variable দ্বারা নির্দেশিত তথ্য গঠন সংশোধন করেন, এই ক্ষেত্রে একটি তালিকা:

>>> class PassByReference:
...     def __init__(self):
...         self.variable = ['Original']
...         self.change(self.variable)
...         print self.variable
...         
...     def change(self, var):
...         var.append('Changed')
... 
>>> q = PassByReference()
['Original', 'Changed']
>>> 

আমি নিশ্চিত অন্য কেউ এই আরও স্পষ্ট করতে পারে।


এটি পাস-বাই-মান বা পাস-বাই-রেফারেন্স নয় - এটি কল-বাই-অবজেক্ট। ফ্রেড্রিক লুন্ধু এইটি দেখুন:

http://effbot.org/zone/call-by-object.htm

এখানে একটি উল্লেখযোগ্য উদ্ধৃতি:

"... ভেরিয়েবল [নাম] বস্তু নয় ; অন্য কোন ভেরিয়েবল দ্বারা বা বস্তুর দ্বারা উল্লেখ করা যায় না।"

আপনার উদাহরণে, যখন Change পদ্ধতি বলা হয় - এটির জন্য একটি namespace তৈরি করা হয়; এবং var একটি নাম হয়ে ওঠে, সেই নামের জায়গার মধ্যে, স্ট্রিং বস্তুর জন্য 'Original' । যে বস্তুর তারপর দুটি নামস্থান একটি নাম আছে। পরবর্তী, var = 'Changed' var একটি নতুন স্ট্রিং বস্তুর সাথে binds, এবং এইভাবে পদ্ধতির নামস্থানটি 'Original' সম্পর্কে ভুলে যায়। অবশেষে, যে নামস্থানটি ভুলে গিয়েছে, এবং এর সাথে স্ট্রিং 'Changed'


পাইথনের পাস-বাই-অ্যাসাইনমেন্ট স্কীমটি সি ++ এর রেফারেন্স প্যারামিটার বিকল্পের মতোই যথেষ্ট নয়, তবে এটি সি-তে (এবং অন্যান্যদের) যুক্তিযুক্ত পাসিং মডেলের মতো একই রকম বলে মনে হয়:

  • অননুমোদিত আর্গুমেন্ট কার্যকরভাবে " মান অনুসারে " পাস করা হয় । পূর্ণসংখ্যা এবং স্ট্রিংগুলির মতো বস্তুগুলি অনুলিপি দ্বারা পরিবর্তিত বস্তুর রেফারেন্স দ্বারা গৃহীত হয়, তবে যেহেতু আপনি যেকোনো জায়গায় অপরিবর্তনীয় বস্তুগুলি পরিবর্তন করতে পারবেন না, প্রভাবটি একটি অনুলিপি তৈরি করার মতোই বেশি।
  • পরিবর্তনযোগ্য আর্গুমেন্টগুলি কার্যকরভাবে " পয়েন্টার দ্বারা " পাস করা হয় । তালিকা এবং অভিধানগুলির মতো বস্তুগুলি বস্তু রেফারেন্স দ্বারাও পাস করা হয়, যা সি-পাসের অ্যারেগুলির মতো একই পয়েন্টার হিসাবে-পরিবর্তনযোগ্য বস্তুগুলি ফাংশনে পরিবর্তিত হতে পারে, যেমন সি অ্যারে ।

রেফারেন্স দ্বারা / মান দ্বারা পরিবর্তে নিয়োগ দ্বারা প্রেরিত উপাদান চিন্তা করুন। এভাবে, এটি সর্বদাই পরিষ্কার, স্বাভাবিক নিয়োগের সময় কী ঘটেছে তা বোঝার সময় পর্যন্ত কি ঘটছে।

সুতরাং, একটি ফাংশন / পদ্ধতিতে একটি তালিকা পাস যখন, তালিকা পরামিতি নাম নির্ধারিত হয়। তালিকায় যোগ তালিকা তালিকা পরিবর্তন করা হবে। ফাংশনের ভেতর তালিকা পুনঃনির্মাণের মূল তালিকাটি পরিবর্তন করবে না, যেহেতু:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

যেহেতু অপ্রয়োজনীয় প্রকারগুলি সংশোধন করা যাবে না, তাই তারা মান দ্বারা প্রেরিত হচ্ছে বলে মনে হচ্ছে - একটি ফাংশনে একটি int পাস করার অর্থ ফাংশন প্যারামিটারের int নির্ধারণ করা। আপনি শুধুমাত্র যেটি পুনর্নির্মাণ করতে পারেন, কিন্তু এটি মূল ভেরিয়েবল মান পরিবর্তন করবে না।


সাধারণত আমি ব্যবহার করা একটি সহজ কৌশল একটি তালিকায় এটি মোড়ানো হয়:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(হ্যাঁ আমি জানি এটি অস্বস্তিকর হতে পারে তবে কখনও কখনও এটি করার পক্ষে যথেষ্ট সহজ।)


আপনি বলতে পারেন যে আপনাকে একটি পরিবর্তনযোগ্য বস্তু থাকতে হবে, তবে বিশ্বব্যাপী ভেরিয়েবলগুলির উপর নজর রাখতে আপনাকে পরামর্শ দিতে বলুন যেহেতু তারা আপনাকে সাহায্য করতে পারে বা এই ধরনের সমস্যা সমাধান করতে পারে!

http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

উদাহরণ:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2

যেহেতু আপনার উদাহরণ বস্তু ভিত্তিক হতে পারে, তাই আপনি অনুরূপ ফলাফল অর্জন করতে নিম্নলিখিত পরিবর্তন করতে পারে:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print(self.variable)

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

রেফারেন্স দ্বারা পাস করার সময় পিয়থনটিতে ভালভাবে ফিট করা যায় না এবং খুব কমই ব্যবহার করা উচিত এমন কিছু কার্যকারিতা রয়েছে যা প্রকৃতপক্ষে স্থানীয় ভেরিয়েবলে অবতীর্ণ বস্তুটি পেতে কাজ করতে পারে বা তথাকথিত ফাংশনের অভ্যন্তরে একটি স্থানীয় পরিবর্তনশীলকে পুনরায় সাইন ইন করতে পারে।

মৌলিক ধারণা হল এমন একটি ফাংশন যা অ্যাক্সেস করতে পারে এবং অন্য ফাংশনে বস্তুর রূপে বা কোনও শ্রেণিতে সংরক্ষণ করা যেতে পারে।

একটি উপায় একটি মোড়ক ফাংশন ( globalগ্লোবাল ভেরিয়েবলের জন্য) বা nonlocal(একটি ফাংশনে স্থানীয় ভেরিয়েবলের জন্য) ব্যবহার করা হয়।

def change(wrapper):
    wrapper(7)

x = 5
def setter(val):
    global x
    x = val
print(x)

একই ধারণা পড়া এবং delএকটি পরিবর্তনশীল eting জন্য কাজ করে ।

শুধু পড়ার জন্য এমন একটি ছোট lambda: xউপায়ও ব্যবহার করা যায় যা কল করার যোগ্য ফেরত দেয় যখন বলা হয় x এর বর্তমান মান প্রদান করে। এটি কিছুটা দূরবর্তী অতীতে ভাষাগুলিতে ব্যবহৃত "নাম অনুসারে কল করুন" এর মত।

একটি ভেরিয়েবল অ্যাক্সেস করতে 3 টি র্যাপার পাস করা একটু অপ্রত্যাশিত তাই তাদের এমন একটি শ্রেণিতে আবদ্ধ করা যেতে পারে যা প্রক্সি বৈশিষ্ট্য রয়েছে:

class ByRef:
    def __init__(self, r, w, d):
        self._read = r
        self._write = w
        self._delete = d
    def set(self, val):
        self._write(val)
    def get(self):
        return self._read()
    def remove(self):
        self._delete()
    wrapped = property(get, set, remove)

# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15

পাইথনগুলি "প্রতিফলন" সমর্থনটি এমন একটি বস্তু পেতে পারে যা একটি নির্দিষ্ট ক্ষেত্রের মধ্যে নাম / পরিবর্তনশীলকে পুনরায় সাইন ইন করতে সক্ষম হয় যা স্পষ্টভাবে ফাংশন সংজ্ঞায়িত না করে:

class ByRef:
    def __init__(self, locs, name):
        self._locs = locs
        self._name = name
    def set(self, val):
        self._locs[self._name] = val
    def get(self):
        return self._locs[self._name]
    def remove(self):
        del self._locs[self._name]
    wrapped = property(get, set, remove)

def change(x):
    x.wrapped = 7

def test_me():
    x = 6
    print(x)
    change(ByRef(locals(), "x"))
    print(x)

এখানে ByRefক্লাস একটি অভিধান এক্সেস wraps। তাই অ্যাক্সেস বৈশিষ্ট্য প্রবেশ wrappedঅভিধানে একটি আইটেম অ্যাক্সেস অনুবাদ করা হয়। বিটলিনের ফলাফল localsএবং স্থানীয় পরিবর্তনশীল নামটি পাস করে এটি একটি স্থানীয় পরিবর্তনশীল অ্যাক্সেস শেষ করে। 3.5 হিসাবে পাইথন ডকুমেন্টেশন পরামর্শ দেয় যে অভিধান পরিবর্তন করলেও কাজ না হলেও এটি আমার জন্য কাজ করে।


আমি দ্রুত ফোর্ট্রান কোড কয়েকটি পাইথন রূপান্তর করতে নিম্নলিখিত পদ্ধতিটি ব্যবহার করেছি। সত্য, আসল প্রশ্নটি প্রকাশ করা হিসাবে এটি রেফারেন্স দ্বারা পাস করা হয় না, কিন্তু কিছু ক্ষেত্রে প্রায় একটি সহজ কাজ।

a=0
b=0
c=0
def myfunc(a,b,c):
    a=1
    b=2
    c=3
    return a,b,c

a,b,c = myfunc(a,b,c)
print a,b,c

এখানে উত্তরগুলির অনেক অন্তর্দৃষ্টি, কিন্তু আমি মনে করি এখানে অতিরিক্ত পয়েন্ট স্পষ্টভাবে উল্লেখ করা হয় না। পাইথন ডকুমেন্টেশন থেকে উদ্ধৃত করে https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python -for -local- এবং- গ্লোবাল- variables-in-pythonhttps://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

"পাইথন ইন, কোনও ফাংশনের ভিতরে উল্লেখিত ভেরিয়েবলগুলি নিখুঁতভাবে বিশ্বব্যাপী। যদি একটি পরিবর্তনশীলকে ফাংশনের শরীরের মধ্যে যে কোনও নতুন মান বরাদ্দ করা হয় তবে এটি একটি স্থানীয় বলে মনে করা হয়। যদি একটি পরিবর্তনশীল কখনও ফাংশনের ভিতরে একটি নতুন মান ধার্য করে, ভেরিয়েবলটি নিখরচায় স্থানীয়, এবং আপনাকে স্পষ্টভাবে এটি 'বিশ্বব্যাপী' হিসাবে ঘোষণা করতে হবে। প্রথম দিকে কিছুটা বিস্ময়কর হলেও, একটি মুহূর্তের বিবেচনার বিষয়টি এটিকে ব্যাখ্যা করে। এক দিকে, নির্ধারিত ভেরিয়েবলগুলির জন্য বিশ্বব্যাপী প্রয়োজনগুলি অপ্রত্যাশিত পার্শ্ব প্রতিক্রিয়াগুলির বিরুদ্ধে একটি বার সরবরাহ করে। অন্যদিকে, যদি বিশ্বব্যাপী সমস্ত বিশ্বব্যাপী রেফারেন্সের জন্য বিশ্বব্যাপী প্রয়োজন হয়, তবে আপনি সর্বদা বিশ্বব্যাপী ব্যবহার করতে চান। আপনি বিল্ট-ইন ফাংশন বা আমদানি করা মডিউলটির একটি উপাদানতে বিশ্বব্যাপী প্রতিটি উল্লেখ হিসাবে ঘোষণা করতে হবে।এই বিভ্রান্তি পার্শ্বপ্রতিক্রিয়া সনাক্ত করার জন্য বিশ্বব্যাপী ঘোষণার উপযোগিতাটি হারাবে। "

এমনকি একটি ফাংশন থেকে একটি পরিবর্তনযোগ্য বস্তুর পাশাপাশি যখন এটি এখনও প্রযোজ্য। এবং আমার কাছে ফাংশনের বস্তুর উপর অবজেক্ট এবং অপারেটিংয়ের মধ্যে আচরণের পার্থক্যের কারণটি স্পষ্টভাবে ব্যাখ্যা করে।

def test(l):
    print "Received", l , id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

দেয়:

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

বৈশ্বিক ঘোষিত নয় এমন একটি বিশ্বব্যাপী পরিবর্তনশীলের জন্য বরাদ্দ একটি নতুন স্থানীয় বস্তু তৈরি করে এবং মূল বস্তুর লিঙ্কটি ভেঙ্গে দেয়।


পাইথন এই জিনিসটি কীভাবে কাজ করে সে বিষয়ে সমস্ত দুর্দান্ত ব্যাখ্যা ছাড়াও, আমি সমস্যাটির জন্য একটি সহজ পরামর্শ দেখিনি। আপনি বস্তু এবং দৃষ্টান্ত তৈরি করতে বলে মনে হচ্ছে, ইনস্ট্যান্স ভেরিয়েবলগুলি পরিচালনা এবং তাদের পরিবর্তন করার পাইথনিক পদ্ধতিটি নিম্নরূপ:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.Change()
        print self.variable

    def Change(self):
        self.variable = 'Changed'

উদাহরণস্বরূপ পদ্ধতি, আপনি সাধারণত selfঅ্যাক্সেস ইনস্ট্যান্স গুণাবলী উল্লেখ। ইনস্ট্যান্স বৈশিষ্ট্য সেট করা __init__এবং উদাহরণ পদ্ধতিতে তাদের পরিবর্তন বা পরিবর্তন করা স্বাভাবিক । যে আপনি selfপ্রথম যুক্তি als পাস কেন def Change

আরেকটি সমাধান এটির মতো স্ট্যাটিক পদ্ধতি তৈরি করতে হবে:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.variable = PassByReference.Change(self.variable)
        print self.variable

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var

রেফারেন্স দ্বারা একটি বস্তু পাস করার জন্য একটি ছোট কৌশল আছে, যদিও ভাষাটি এটি সম্ভব করে না। এটি জাভাতেও কাজ করে, এটি একটি আইটেমের তালিকা। ;-)

class PassByReference:
    def __init__(self, name):
        self.name = name

def changeRef(ref):
    ref[0] = PassByReference('Michael')

obj = PassByReference('Peter')
print obj.name

p = [obj] # A pointer to obj! ;-)
changeRef(p)

print p[0].name # p->name

এটি একটি কুশ্রী হ্যাক, কিন্তু এটি কাজ করে। ;-P







pass-by-reference