python संदर्भ के द्वारा मैं एक चर कैसे पास करूं?




reference parameter-passing (19)

आपको यहां कुछ वाकई अच्छे जवाब मिल गए हैं।

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' )

पायथन दस्तावेज अस्पष्ट लगता है कि पैरामीटर संदर्भ या मूल्य से पारित होते हैं, और निम्न कोड अपरिवर्तित मान 'मूल'

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

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

क्या वास्तविक संदर्भ द्वारा चर को पारित करने के लिए मैं कुछ कर सकता हूं?


तकनीकी रूप से, पायथन हमेशा संदर्भ मानों से पास का उपयोग करता है । मैं अपने बयान का समर्थन करने के लिए अपना दूसरा जवाब दोहराने जा रहा हूं।

पायथन हमेशा पास-दर-संदर्भ मानों का उपयोग करता है। कोई अपवाद नहीं है। किसी भी परिवर्तनीय असाइनमेंट का मतलब संदर्भ मान की प्रतिलिपि बनाना है। कोई अपवाद नहीं। कोई वैरिएबल नाम संदर्भ मान के लिए बाध्य है। हमेशा।

आप लक्ष्य वस्तु के पते के रूप में संदर्भ मान के बारे में सोच सकते हैं। उपयोग किए जाने पर पता स्वचालित रूप से संदर्भित किया जाता है। इस तरह, संदर्भ मान के साथ काम करते हुए, ऐसा लगता है कि आप सीधे लक्षित वस्तु के साथ काम करते हैं। लेकिन लक्ष्य पर कूदने के लिए एक कदम आगे के बीच एक संदर्भ है।

यहां उदाहरण दिया गया है जो साबित करता है कि पायथन संदर्भ द्वारा गुज़रने का उपयोग करता है:

अगर तर्क मूल्य से पारित किया गया था, बाहरी lst संशोधित नहीं किया जा सका। हरा लक्ष्य वस्तुएं हैं (काला काला के अंदर संग्रहीत मूल्य है, लाल ऑब्जेक्ट प्रकार है), पीले रंग के अंदर संदर्भ मूल्य के साथ स्मृति है - तीर के रूप में खींचा गया है। नीला ठोस तीर संदर्भ मान है जो फ़ंक्शन को पास किया गया था (धराशायी नीले तीर पथ के माध्यम से)। बदसूरत गहरा पीला आंतरिक शब्दकोश है। (यह वास्तव में एक हरे रंग की अंडाकार के रूप में भी खींचा जा सकता है। रंग और आकार केवल यह कहता है कि यह आंतरिक है।)

संदर्भ id() यानी, लक्ष्य वस्तु का पता) क्या है, यह जानने के लिए आप id() अंतर्निर्मित फ़ंक्शन का उपयोग कर सकते हैं।

संकलित भाषाओं में, एक चर एक मेमोरी स्पेस है जो प्रकार के मान को कैप्चर करने में सक्षम है। पायथन में, एक चर एक संदर्भ चर (एक स्ट्रिंग के रूप में आंतरिक रूप से कब्जा कर लिया जाता है) संदर्भ चर से बंधे होते हैं जो लक्ष्य वस्तु के संदर्भ मान रखता है। वेरिएबल का नाम आंतरिक शब्दकोश में कुंजी है, उस डिक्शनरी आइटम का मान भाग लक्ष्य के संदर्भ मान को संग्रहीत करता है।

पाइथन में संदर्भ मान छिपे हुए हैं। संदर्भ मान संग्रहीत करने के लिए कोई स्पष्ट उपयोगकर्ता प्रकार नहीं है। हालांकि, आप संदर्भ चर के रूप में एक सूची तत्व (या किसी अन्य उपयुक्त कंटेनर प्रकार में तत्व) का उपयोग कर सकते हैं, क्योंकि सभी कंटेनर तत्वों को लक्ष्य ऑब्जेक्ट्स के संदर्भ के रूप में भी संग्रहीत करते हैं। दूसरे शब्दों में, तत्व वास्तव में कंटेनर के अंदर निहित नहीं हैं - केवल तत्वों के संदर्भ हैं।


पाइथन में यह सामग्री कैसे काम करती है, इस बारे में सभी महान स्पष्टीकरणों के अलावा, मुझे समस्या के लिए एक सरल सुझाव नहीं दिख रहा है। जैसा कि आप ऑब्जेक्ट्स और इंस्टेंस बनाते हैं, उदाहरण चर को संभालने और उन्हें बदलने का पाइथोनिक तरीका निम्न है:

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

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

उदाहरण के तरीकों में, आप आमतौर selfपर पहुंच उदाहरण विशेषताओं का उपयोग करते हैं। __init__उदाहरण के तरीकों में उदाहरण विशेषताओं को सेट करना और पढ़ना या बदलना सामान्य बात है । यही कारण है कि आप selfपहले तर्क के लिए अलस पास करते हैं 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 PassByReferenceIsh:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print self.variable

    def change(self, var):
        self.__dict__[var] = 'Changed'

वास्तविक कोड में, निश्चित रूप से, आप लुकअप लुकअप पर त्रुटि जांच जोड़ देंगे।


pass by objectपाइथन में उपयोग की जाने वाली अवधारणा की सरल (मुझे आशा है) स्पष्टीकरण यहां दिया गया है।
जब भी आप किसी ऑब्जेक्ट को फ़ंक्शन पर पास करते हैं, ऑब्जेक्ट स्वयं ही पास हो जाता है (पाइथन में ऑब्जेक्ट वास्तव में आप अन्य प्रोग्रामिंग भाषाओं में मूल्य कहेंगे) इस ऑब्जेक्ट का संदर्भ नहीं है। दूसरे शब्दों में, जब आप कॉल करते हैं:

def change_me(list):
   list = [1, 2, 3]

my_list = [0, 1]
change_me(my_list)

वास्तविक वस्तु - [0, 1] (जिसे अन्य प्रोग्रामिंग भाषाओं में मूल्य कहा जाएगा) पारित किया जा रहा है। तो वास्तव में समारोह change_meकुछ ऐसा करने की कोशिश करेगा:

[0, 1] = [1, 2, 3]

जो स्पष्ट रूप से कार्य को पारित वस्तु को नहीं बदलेगा। अगर समारोह इस तरह दिखता है:

def change_me(list):
   list.append(2)

फिर कॉल का नतीजा होगा:

[0, 1].append(2)

जो स्पष्ट रूप से वस्तु को बदल देगा। यह जवाब इसे अच्छी तरह से बताता है।


संदर्भ के अनुसार पास कुछ भी नहीं है जो कि अजगर में अच्छी तरह से फिट बैठता है और शायद ही कभी इसका उपयोग किया जाना चाहिए कुछ ऐसे कामकाज हैं जो वास्तव में स्थानीय चर के लिए असाइन की गई वस्तु को प्राप्त करने के लिए काम कर सकते हैं या एक स्थानीय चर को एक बुलाए गए फ़ंक्शन के अंदर से फिर से सौंप सकते हैं।

मूल विचार यह है कि एक ऐसा कार्य हो जो उस पहुंच को कर सके और किसी अन्य वर्ग में ऑब्जेक्ट के रूप में या कक्षा में संग्रहीत किया जा सके।

एक तरीका है एक रैपर फ़ंक्शन में ( globalवैश्विक चर के लिए) या nonlocal(फ़ंक्शन में स्थानीय चर के लिए ) का उपयोग करना है।

def change(wrapper):
    wrapper(7)

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

एक ही विचार delएक चर पढ़ने और etting के लिए काम करता है ।

केवल पढ़ने के लिए केवल इसका उपयोग करने का एक छोटा lambda: 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कक्षा एक शब्दकोश पहुंच लपेटती है। तो wrappedउत्तीर्ण पहुंच का अनुवाद पास शब्दकोश में किसी आइटम पहुंच में किया जाता है। बिल्टिन के परिणाम localsऔर स्थानीय चर के नाम को पारित करके यह एक स्थानीय चर का उपयोग कर समाप्त होता है। 3.5 के रूप में पायथन दस्तावेज सलाह देता है कि शब्दकोश बदलने से काम नहीं हो सकता है लेकिन ऐसा लगता है कि यह मेरे लिए काम करता है।


चूंकि आपका उदाहरण ऑब्जेक्ट उन्मुख होता है, इसलिए आप एक समान परिणाम प्राप्त करने के लिए निम्न परिवर्तन कर सकते हैं:

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'

असाइनमेंट द्वारा तर्क पारित किए जाते हैं । इसके पीछे तर्क दो गुना है:

  1. पारित पैरामीटर वास्तव में किसी ऑब्जेक्ट का संदर्भ है (लेकिन संदर्भ मान द्वारा पारित किया जाता है)
  2. कुछ डेटा प्रकार म्यूटेबल हैं, लेकिन अन्य नहीं हैं

इसलिए:

  • यदि आप एक म्यूटेबल ऑब्जेक्ट को किसी विधि में पास करते हैं, तो विधि को उसी ऑब्जेक्ट का संदर्भ मिलता है और आप इसे अपने दिल की खुशी में बदल सकते हैं, लेकिन यदि आप विधि में संदर्भ को दोबारा जोड़ते हैं, तो बाहरी क्षेत्र को इसके बारे में कुछ भी नहीं पता होगा, और उसके बाद आप कर चुके हैं, बाहरी संदर्भ अभी भी मूल वस्तु पर इंगित करेगा।

  • यदि आप किसी विधि के लिए अपरिवर्तनीय ऑब्जेक्ट पास करते हैं, तो भी आप बाहरी संदर्भ को पुनर्निर्मित नहीं कर सकते हैं, और आप ऑब्जेक्ट को भी म्यूटेट नहीं कर सकते हैं।

इसे और भी स्पष्ट करने के लिए, चलो कुछ उदाहरण हैं।

सूची - एक परिवर्तनीय प्रकार

आइए किसी विधि को पारित सूची को संशोधित करने का प्रयास करें:

def try_to_change_list_contents(the_list):
    print('got', the_list)
    the_list.append('four')
    print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

आउटपुट:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

चूंकि पारित पैरामीटर outer_list संदर्भ है, इसकी एक प्रति नहीं, हम इसे बदलने के लिए उत्परिवर्तनीय सूची विधियों का उपयोग कर सकते हैं और बाहरी दायरे में परिवर्तनों को प्रतिबिंबित कर सकते हैं।

अब देखते हैं कि जब हम पैरामीटर के रूप में पारित संदर्भ को बदलने का प्रयास करते हैं तो क्या होता है:

def try_to_change_list_reference(the_list):
    print('got', the_list)
    the_list = ['and', 'we', 'can', 'not', 'lie']
    print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

आउटपुट:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

चूंकि the_list पैरामीटर मान द्वारा पारित किया गया था, इसलिए इसकी एक नई सूची असाइन करने से कोई प्रभाव नहीं पड़ा कि विधि के बाहर कोड देख सकता था। the_list outer_list संदर्भ की एक प्रति थी, और हमारे पास एक नई सूची the_list बिंदु था, लेकिन outer_list कहां बदलने का कोई तरीका नहीं था।

स्ट्रिंग - एक अपरिवर्तनीय प्रकार

यह अपरिवर्तनीय है, इसलिए स्ट्रिंग की सामग्री को बदलने के लिए हम कुछ भी नहीं कर सकते हैं

अब, संदर्भ को बदलने का प्रयास करें

def try_to_change_string_reference(the_string):
    print('got', the_string)
    the_string = 'In a kingdom by the sea'
    print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

आउटपुट:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

दोबारा, चूंकि the_string पैरामीटर मान द्वारा पारित किया गया था, इसके लिए एक नई स्ट्रिंग को असाइन करने का कोई प्रभाव नहीं पड़ा कि विधि के बाहर कोड देख सकता था। the_string outer_string संदर्भ की एक प्रति थी, और हमारे पास एक नई स्ट्रिंग के लिए the_string बिंदु था, लेकिन outer_string कहां बदलने का कोई तरीका नहीं था।

मुझे उम्मीद है कि यह चीजों को थोड़ा सा साफ़ कर देगा।

संपादित करें: यह ध्यान दिया गया है कि यह इस सवाल का जवाब नहीं देता है कि @ डेविड ने मूल रूप से पूछा था, "क्या वास्तविक संदर्भ द्वारा चर को पारित करने के लिए मैं कुछ कर सकता हूं?"। चलो उस पर काम करते हैं।

हम इसके आसपास कैसे हो जाते हैं?

@ एंड्रिया के जवाब से पता चलता है, आप नया मान वापस कर सकते हैं। यह चीजों को पारित करने के तरीके को नहीं बदलता है, लेकिन आपको वह जानकारी प्राप्त करने देता है जिसे आप वापस चाहते हैं:

def return_a_whole_new_string(the_string):
    new_string = something_to_do_with_the_old_string(the_string)
    return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

यदि आप वास्तव में रिटर्न वैल्यू का उपयोग करना टालना चाहते हैं, तो आप अपना मूल्य रखने के लिए कक्षा बना सकते हैं और इसे फ़ंक्शन में पास कर सकते हैं या किसी मौजूदा वर्ग का उपयोग कर सकते हैं, जैसे सूची:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
    new_string = something_to_do_with_the_old_string(stuff_to_change[0])
    stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

हालांकि यह थोड़ा बोझिल लगता है।


संदर्भ संदर्भ वस्तुओं को संग्रहीत करने के लिए आप केवल रिक्त वर्ग का उपयोग कर सकते हैं क्योंकि आंतरिक रूप से ऑब्जेक्ट विशेषताएँ आवृत्ति शब्दकोश में संग्रहीत होती हैं। उदाहरण देखें।

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

एक सामान्य चाल जो मैं आम तौर पर उपयोग करता हूं वह सिर्फ एक सूची में लपेटना है:

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

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

(हाँ मुझे पता है कि यह असुविधाजनक हो सकता है, लेकिन कभी-कभी यह करने के लिए काफी आसान है।)


पायथन में कोई चर नहीं हैं

पैरामीटर को समझने की कुंजी "चर" के बारे में सोचना बंद करना है। पाइथन में नाम और वस्तुएं हैं और साथ में वे चर की तरह दिखाई देते हैं, लेकिन यह हमेशा तीनों को अलग करना उपयोगी होता है।

  1. पायथन के नाम और वस्तुएं हैं।
  2. असाइनमेंट किसी ऑब्जेक्ट पर एक नाम बांधता है।
  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 के बॉडी में) उसी नाम को फिर से असाइन करता है: किसी अन्य ऑब्जेक्ट (जो एक स्ट्रिंग को भी पकड़ने के लिए होता है लेकिन पूरी तरह से कुछ और हो सकता था)।


समस्या पाइथन में क्या चर हैं की गलतफहमी से आता है। यदि आप सबसे पारंपरिक भाषाओं में उपयोग किया जाता है, तो आपके पास निम्न अनुक्रम में क्या होता है इसका एक मानसिक मॉडल है:

a = 1
a = 2

आप मानते हैं कि a स्मृति स्थान है जो मान 1 को संग्रहीत करता है, फिर मान 2 को संग्रहीत करने के लिए अद्यतन किया जाता है। ऐसा नहीं है कि चीजें पाइथन में कैसे काम करती हैं। इसके बजाय, मान 1 साथ किसी ऑब्जेक्ट के संदर्भ के रूप में प्रारंभ होता है, फिर मान 2 साथ किसी ऑब्जेक्ट के संदर्भ के रूप में पुन: असाइन किया जाता है। उन दो वस्तुओं को सह-अस्तित्व जारी रखना जारी रख सकता है, भले ही पहले व्यक्ति का संदर्भ न हो; वास्तव में वे कार्यक्रम के भीतर किसी अन्य संदर्भ से साझा किया जा सकता है।

जब आप पैरामीटर के साथ फ़ंक्शन को कॉल करते हैं, तो एक नया संदर्भ बनाया जाता है जो पारित ऑब्जेक्ट को संदर्भित करता है। यह फ़ंक्शन कॉल में उपयोग किए गए संदर्भ से अलग है, इसलिए उस संदर्भ को अपडेट करने का कोई तरीका नहीं है और इसे संदर्भित करें नई वस्तु आपके उदाहरण में:

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

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

self.variable स्ट्रिंग ऑब्जेक्ट 'Original' संदर्भ है। जब आप Change कहते हैं तो आप ऑब्जेक्ट में दूसरा संदर्भ var बनाते हैं। फ़ंक्शन के अंदर आप संदर्भ var को एक अलग स्ट्रिंग ऑब्जेक्ट 'Changed' पुन: असाइन करते हैं, लेकिन संदर्भ self.variable अलग है और बदलता नहीं है।

इसके आसपास एकमात्र तरीका एक परिवर्तनीय वस्तु को पारित करना है। चूंकि दोनों संदर्भ एक ही वस्तु का संदर्भ देते हैं, इसलिए ऑब्जेक्ट में कोई भी परिवर्तन दोनों स्थानों पर दिखाई देता है।

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

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

मैंने कुछ फोरट्रान कोड को पाइथन में त्वरित रूप से परिवर्तित करने के लिए निम्न विधि का उपयोग किया। सच है, यह मूल प्रश्न के रूप में संदर्भ द्वारा पारित नहीं किया गया है, लेकिन कुछ मामलों में यह एक साधारण काम है।

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

संदर्भ / मूल्य के बजाय असाइनमेंट द्वारा सामानों को पारित करने के बारे में सोचें। इस तरह, यह सब कुछ स्पष्ट है, जब तक आप समझते हैं कि सामान्य असाइनमेंट के दौरान क्या होता है।

इसलिए, किसी फ़ंक्शन / विधि में कोई सूची उत्तीर्ण करते समय, सूची पैरामीटर नाम को असाइन की जाती है। सूची में शामिल होने के परिणामस्वरूप सूची संशोधित की जाएगी। फ़ंक्शन के अंदर सूची को पुन: असाइन करने से मूल सूची नहीं बदलेगी, क्योंकि:

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

चूंकि अपरिवर्तनीय प्रकारों को संशोधित नहीं किया जा सकता है, इसलिए वे मान द्वारा पारित होने की तरह प्रतीत होते हैं - एक फ़ंक्शन में int को गुजरने का अर्थ है फ़ंक्शन पैरामीटर को int निर्दिष्ट करना। आप इसे कभी भी पुनः असाइन कर सकते हैं, लेकिन यह मूल चर वैल्यू को नहीं बदलेगा।


(संपादित करें - ब्लेयर ने अपने बेहद लोकप्रिय उत्तर को अपडेट किया है ताकि यह अब सटीक हो)

मुझे लगता है कि यह ध्यान रखना महत्वपूर्ण है कि सबसे अधिक वोट (ब्लेयर कॉनराड द्वारा) के साथ वर्तमान पोस्ट, इसके परिणाम के संबंध में सही होने के दौरान, भ्रामक है और इसकी परिभाषाओं के आधार पर सीमा रेखा गलत है। हालांकि कई भाषाएं हैं (जैसे सी) जो उपयोगकर्ता को या तो संदर्भ द्वारा पास करने या मूल्य से गुजरने की अनुमति देती है, पाइथन उनमें से एक नहीं है।

डेविड Cournapeau का जवाब असली जवाब के लिए इंगित करता है और बताता है कि ब्लेयर कॉनराड की पोस्ट में व्यवहार सही क्यों लगता है जबकि परिभाषाएं नहीं हैं।

इस हद तक कि पाइथन मूल्य से गुजरता है, सभी भाषाओं को डेटा के कुछ टुकड़े के बाद मूल्य से गुजरना पड़ता है (चाहे वह "मान" या "संदर्भ" हो) को भेजा जाना चाहिए। हालांकि, इसका मतलब यह नहीं है कि पायथन इस अर्थ में मूल्य से गुजरता है कि एक सी प्रोग्रामर इसके बारे में सोचता है।

यदि आप व्यवहार चाहते हैं, ब्लेयर कॉनराड का जवाब ठीक है। लेकिन अगर आप नट्स और बोल्ट जानना चाहते हैं कि क्यों पाइथन न तो मूल्य से गुज़रता है या संदर्भ द्वारा पास होता है, तो डेविड कोर्नपेउ के जवाब को पढ़ें।


एफ़बॉट (उर्फ फ्रेड्रिक लन्ध) ने पाइथन की परिवर्तनीय गुजरने वाली शैली को कॉल-बाय-ऑब्जेक्ट के रूप में वर्णित किया है: http://effbot.org/zone/call-by-object.htm

ऑब्जेक्ट्स को ढेर और पॉइंटर्स पर आवंटित किया जाता है ताकि उन्हें कहीं भी पास किया जा सके।

  • जब आप x = 1000 जैसे असाइनमेंट करते हैं, तो एक शब्दकोश प्रविष्टि बनाई जाती है जो मौजूदा नामस्थान में स्ट्रिंग "x" को एक सूचक में पूर्णांक ऑब्जेक्ट में एक हजार तक नक्शा बनाती है।

  • जब आप x = 2000 साथ "x" को अपडेट करते हैं, तो एक नया पूर्णांक ऑब्जेक्ट बनाया जाता है और शब्दकोश को नई ऑब्जेक्ट पर इंगित करने के लिए अपडेट किया जाता है। पुराना एक हज़ार ऑब्जेक्ट अपरिवर्तित है (और इस बात पर निर्भर करता है कि ऑब्जेक्ट को कुछ और संदर्भित करता है या नहीं)।

  • जब आप y = x जैसे नए असाइनमेंट करते हैं, तो एक नई शब्दकोश प्रविष्टि "y" बनाई जाती है जो "x" के लिए प्रविष्टि के समान ऑब्जेक्ट को इंगित करती है।

  • तार और पूर्णांक जैसे ऑब्जेक्ट्स अपरिवर्तनीय हैं । इसका मतलब यह है कि ऐसी कोई विधियां नहीं हैं जो ऑब्जेक्ट को बनाए जाने के बाद बदल सकती हैं। उदाहरण के लिए, एक बार पूर्णांक ऑब्जेक्ट एक हजार बनने के बाद, यह कभी नहीं बदलेगा। गणित नई पूर्णांक वस्तुओं को बनाकर किया जाता है।

  • सूचियों जैसे ऑब्जेक्ट्स परिवर्तनीय हैं । इसका मतलब है कि ऑब्जेक्ट की ओर इशारा करते हुए ऑब्जेक्ट की सामग्री को कुछ भी बदला जा सकता है। उदाहरण के लिए, x = []; y = x; x.append(10); print y x = []; y = x; x.append(10); print y x = []; y = x; x.append(10); print y करेगा [10] । खाली सूची बनाई गई थी। दोनों "एक्स" और "वाई" एक ही सूची में इंगित करते हैं। ऐपेंड विधि सूची ऑब्जेक्ट को बदलता है (अपडेट करता है) (डेटाबेस में रिकॉर्ड जोड़ना) और परिणाम "x" और "y" दोनों के लिए दृश्यमान है (जैसे डेटाबेस अद्यतन प्रत्येक डेटाबेस के लिए दृश्यमान होगा)।

उम्मीद है कि आपके लिए इस मुद्दे को स्पष्ट करता है।


इस मामले में वैरिएबल शीर्षक वैरिएबल में var को Change जाता है, और आप तुरंत var को स्ट्रिंग असाइन करते हैं। यह अब 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://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






pass-by-reference