Bir değişkeni referans olarak nasıl iletirim?


2628

Python belgeleri, parametrelerin referans veya değere göre geçirilip geçirilmediği konusunda net görünmüyor ve aşağıdaki kod, değiştirilmemiş 'Orijinal' değerini üretiyor

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

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

Değişkeni gerçek referansla geçmek için yapabileceğim bir şey var mı?


23
Kısa bir açıklama / açıklama için bu yığın akışı sorusunun ilk cevabına bakınız . Dizeler değişmez olduğundan değiştirilmeyecek ve yeni bir değişken oluşturulacak, dolayısıyla "dış" değişken hala aynı değere sahip olacaktır.
PhilS

10
BlairConrad'ın cevabındaki kod iyidir, ancak DavidCournapeau ve DarenThomas tarafından sağlanan açıklama doğrudur.
Ethan Furman

70
Seçilen cevabı okumadan önce, lütfen bu kısa metni okumayı düşünün. Diğer dillerde "değişkenler", Python'da "isimler" vardır . "Değişkenler" ve "referanslar" yerine "adlar" ve "nesneler" hakkında düşünün ve birçok benzer problemden kaçınmalısınız.
lqc

24
Neden bu gereksiz bir sınıf kullanıyor? Bu Java değil: P
Peter R

2
başka bir geçici çözüm şöyle bir sarmalayıcı 'referans' oluşturmaktır: ref = type ('', (), {'n': 1}) stackoverflow.com/a/1123054/409638
robert

Yanıtlar:


2831

Bağımsız değişkenler ödevle iletilir . Bunun arkasındaki mantık iki yönlüdür:

  1. geçirilen parametresinin a, referans bir nesneye (ancak bir referans değeri ile geçirilir)
  2. bazı veri türleri değiştirilebilir, ancak diğerleri

Yani:

  • Değiştirilebilir bir nesneyi bir yönteme geçirirseniz , yöntem aynı nesneye başvuru alır ve kalbinizin zevkine dönüştürebilirsiniz, ancak yöntemdeki başvuruyu yeniden bağlarsanız, dış kapsam bu konuda hiçbir şey bilmez ve sonra işiniz bittiğinde, dış referans yine de orijinal nesneyi gösterecektir.

  • Bir başarılı olursa iletmenin bir yöntemi nesne, yine dış başvuru rebind değildir, ve hatta nesne mutasyona olamaz.

Daha da netleştirmek için, bazı örnekler verelim.

Liste - değiştirilebilir bir tür

Bir yönteme geçirilen listeyi değiştirmeye çalışalım:

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)

Çıktı:

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

Aktarılan parametre outer_listbir kopyası değil referans olduğu için , değişiklik listesi yöntemlerini kullanarak değiştirebiliriz ve değişikliklerin dış kapsama yansıtılmasını sağlayabiliriz.

Şimdi parametre olarak iletilen referansı değiştirmeye çalıştığımızda ne olacağını görelim:

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)

Çıktı:

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

Yana the_listparametre kendisine yeni bir liste atayarak, değeri tarafından kabul edildi yöntemle dışında kod görebildiğini hiçbir etkisi olmadı. the_listBir kopyası olan outer_listreferans ve biz vardı the_listyeni listeye noktası, ama değiştirmek için hiçbir yolu yoktuouter_list sivri.

String - değişmez tip

Değişmez, bu yüzden dizenin içeriğini değiştirmek için yapabileceğimiz hiçbir şey yok

Şimdi referansı değiştirmeye çalışalım

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)

Çıktı:

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

Yine, the_stringparametre değere göre iletildiğinden, ona yeni bir dize atamanın, yöntemin dışındaki kodun görebileceği bir etkisi yoktu. the_stringBir kopyası olan outer_stringreferans ve biz vardı the_stringyeni bir dizeye noktası, ama değiştirmek için hiçbir yolu yoktu outer_stringsivri.

Umarım bu biraz şeyleri temizler.

DÜZENLE: Bunun @David'in aslında "Değişkeni gerçek referansla geçmek için yapabileceğim bir şey var mı?" Bunun üzerinde çalışalım.

Bunu nasıl hallederiz?

@ Andrea'nın cevabının gösterdiği gibi, yeni değeri geri verebilirsiniz. Bu, işlerin aktarılma şeklini değiştirmez, ancak istediğiniz bilgileri geri almanıza izin verir:

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)

Bir dönüş değeri kullanmaktan gerçekten kaçınmak istiyorsanız, değerinizi korumak ve onu işleve aktarmak veya liste gibi mevcut bir sınıfı kullanmak için bir sınıf oluşturabilirsiniz:

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

Bu biraz hantal gibi görünse de.


165
Aynı şey, C ile aynıdır, "referansla" geçtiğinizde aslında referansla değere geçiyorsunuz ... "Referansla" tanımlayın: P
Andrea Ambu

104
Şartlarını anladığımdan emin değilim. Bir süredir C oyunundan çıktım, ama geri döndüğümde, "referansla geçme" yoktu - bir şeyleri geçebilirdiniz ve her zaman değere göre geçti, bu yüzden parametre listesinde ne varsa kopyalandı. Ancak bazen şey, bir bellek parçasına (ilkel, dizi, yapı, her neyse) uyan bir işaretçi idi, ancak dış kapsamdan kopyalanan işaretçiyi değiştiremezdiniz - işlevle işiniz bittiğinde , orijinal işaretçi hala aynı adrese işaret ediyordu. C ++ farklı davranan referanslar getirdi.
Blair Conrad

34
@Zac Bowling Söylediklerinizin pratik anlamda bu cevapla ne kadar alakalı olduğunu anlamıyorum. Python yeni gelen geçen hakkında bilmek istiyorsa ref / val, o zaman bu cevaptan paket olacaktır: 1- Sen edebilirsiniz sürece, bir değişkenin 'dışında' değerini değiştirmek için, bir işlev bağımsız değişkenler olarak aldığı referans kullanmak çünkü parametreyi yeni bir nesneye başvurmak üzere yeniden atamazsınız. 2- Değişmez bir tipe atamak her zaman dış değişkene yaptığınız referansı kıran yeni bir nesne yaratacaktır.
Cam Jackson

11
@CamJackson, daha iyi bir örneğe ihtiyacınız var - sayılar da Python'daki değişmez nesneler. Ayrıca, eşitlerin sol tarafında abone olmadan yapılan herhangi bir atamanın, değiştirilemez ya da değiştirilmesin adı yeni bir nesneye yeniden atayacağını söylemek doğru olmaz mı? def Foo(alist): alist = [1,2,3]olacak değil arayanlar açısından listenin içeriğini değiştirme.
Mark Ransom

59
-1. Gösterilen kod iyi, nasıl tamamen yanlış olduğuna dair açıklama. Nedenine ilişkin doğru açıklamalar için DavidCournapeau veya DarenThomas'ın cevaplarına bakın.
Ethan Furman

685

Sorun Python'da hangi değişkenlerin yanlış anlaşılmasından kaynaklanıyor. Geleneksel dillerin çoğuna alışkınsanız, aşağıdaki sırada neler olduğuna dair zihinsel bir modeliniz vardır:

a = 1
a = 2

Bunun adeğeri saklayan bir bellek konumu olduğuna inanıyorsunuz 1, daha sonra değeri saklamak için güncelleniyor 2. Python'da işler böyle çalışmaz. Aksine, adeğere sahip bir nesneye başvuru olarak başlar 1, sonra değere sahip bir nesneye başvuru olarak yeniden atanır 2. Bu iki nesne a, birincisine atıfta bulunmasa da birlikte var olmaya devam edebilir ; aslında, program içindeki herhangi bir sayıda başka referansla paylaşılabilirler.

Parametreli bir işlevi çağırdığınızda, iletilen nesneye başvuran yeni bir başvuru oluşturulur. Bu, işlev çağrısında kullanılan referanstan ayrıdır, bu nedenle bu başvuruyu güncellemenin ve yeni nesne. Örneğinizde:

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

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

self.variabledize nesnesine bir başvurudur 'Original'. Aradığınızda nesneye Changeikinci bir başvuru oluşturursunuz var. İşlev içinde başvuruyu varfarklı bir dize nesnesine yeniden atarsınız 'Changed', ancak başvuru self.variableayrıdır ve değişmez.

Bunun tek yolu değiştirilebilir bir nesneyi geçirmektir. Her iki başvuru da aynı nesneye başvurduğundan, nesnede yapılan değişiklikler her iki yere de yansıtılır.

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

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

106
İyi özlü açıklama. "Bir işlevi çağırdığınızda ..." paragrafınız, 'Python işlev parametrelerinin değere göre aktarılan referanslar olduğu' gibi şifreli ifadenin en iyi açıklamalarından biridir. Bence sadece paragrafı anlarsanız, her şey mantıklıdır ve oradan mantıklı bir sonuç olarak akar. O zaman yeni bir nesne oluştururken ve var olan bir nesneyi değiştirirken farkında olmanız gerekir.
Cam Jackson

3
Ancak referansı nasıl yeniden atayabilirsiniz? Ben 'var' adresini değiştiremezsiniz ama dize "Değişti" şimdi 'var' bellek adresinde saklanacak olduğunu düşündüm. Açıklamanız, "Değiştirildi" ve "Orijinal" ifadelerinin bunun yerine bellekteki farklı yerlere ait olduğunu ve "var" ı farklı bir adrese değiştirdiğinizi gösterir. Bu doğru mu?
Glassjawed

9
@Glassjawed, sanırım anlıyorsun. "Değiştirildi" ve "Orijinal", farklı bellek adreslerinde iki farklı dize nesnesidir ve birinden diğerine işaret etmek için 'var' değişiklikleri.
Mark Ransom

id () işlevini kullanmak, konuların netleştirilmesine yardımcı olur, çünkü Python yeni bir nesne oluşturduğunda bunu netleştirir (bu yüzden her neyse, bence).
Tim Richardson

1
@MinhTran en basit terimlerle, bir referans bir nesneye "atıfta bulunan" bir şeydir. Bunun fiziksel temsili büyük olasılıkla bir işaretçi, ama bu sadece bir uygulama detayı. Gerçekten yürekten soyut bir kavram.
Mark Ransom

329

Diğer cevapları oldukça uzun ve karmaşık buldum, bu yüzden Python'un değişkenleri ve parametreleri nasıl ele aldığını açıklamak için bu basit diyagramı oluşturdum. resim açıklamasını buraya girin


2
güzel, hafif bir fark, rahat bir seyirci için açık değil, bir ara görev olduğunu fark etmeyi kolaylaştırır. +1
user22866

9
A'nın değişebilir olup olmadığı önemli değil. B'ye farklı bir şey atarsanız, A değişmez . Bir nesne değiştirilebilirse, onu değiştirebilirsiniz. Ama bunun doğrudan bir isme atanmasıyla hiçbir ilgisi yok ..
Martijn Pieters

1
@Martijn Haklısın. Cevabın değişebilirlikten bahsettiği kısmını kaldırdım. Artık daha basit olabileceğini sanmıyorum.
Zenadix

4
Güncelleme için teşekkürler, çok daha iyi! Çoğu insanı şaşırtan şey bir aboneliğe atanmadır; örneğin B[0] = 2, doğrudan atamaya karşı B = 2,.
Martijn Pieters

11
"A, B'ye atanmıştır." Bu belirsiz değil mi? Bence sıradan İngilizcede ya A=Bda anlamına gelebilir B=A.
Hatshepsut

240

Ne değere göre geçme ne de referansla geçme - nesneye göre çağrıdır. Bkz, Fredrik Lundh tarafından:

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

İşte önemli bir teklif:

"... değişkenler [adlar) nesne değildir ; diğer değişkenler tarafından gösterilemez veya nesneler tarafından adlandırılamazlar."

Örneğinizde, Changeyöntem çağrıldığında - bunun için bir ad alanı oluşturulur; ve varbu ad alanı içinde dize nesnesi için bir ad olur 'Original'. Bu nesnenin iki ad alanında bir adı vardır. Ardından, yeni bir dize nesnesine var = 'Changed'bağlanır varve böylece yöntemin ad alanı unutulur 'Original'. Son olarak, bu ad alanı unutulur ve dize 'Changed'ile birlikte unutulur .


21
Satın almayı zor buluyorum. Bana göre Java gibi, parametreler bellekteki nesnelere işaret eder ve bu işaretçiler yığın veya kayıtlardan geçirilir.
Luciano

10
Bu java gibi değil. Aynı olmadığı durumlardan biri değişmez nesnelerdir. Önemsiz fonksiyonu lambda x: x hakkında düşünün. Bunu x = [1, 2, 3] ve x = (1, 2, 3) için uygulayın. İlk durumda, döndürülen değer girişin bir kopyası olacak ve ikinci durumda aynı olacaktır.
David Cournapeau

26
Hayır, aynen Java'nın nesneler için semantiği gibi. "İlk durumda, döndürülen değer girdinin bir kopyası olacak ve ikinci durumda aynı olacak" ile ne demek istediğinizden emin değilim. ancak bu ifade açıkça yanlış gibi görünüyor.
Mike Graham

23
Java ile tamamen aynıdır. Nesne başvuruları değere göre iletilir. Farklı düşünen herkes swap, iki referansı değiştirebilecek bir fonksiyon için Python kodunu a = [42] ; b = 'Hello'; swap(a, b) # Now a is 'Hello', b is [42]
eklemelidir

24
Java'da nesneleri ilettiğinizde Java ile tamamen aynıdır. Bununla birlikte, Java'nın ilkel değerleri de kopyalanarak geçirilen ilkelleri de vardır. Böylece bu durumda farklılık gösterirler.
Claudiu

174

Referans / değere göre ödevle aktarılan şeyleri düşünün . Bu şekilde, normal görev sırasında neler olduğunu anladığınız sürece neler olduğu her zaman açıktır.

Bu nedenle, bir listeyi bir işleve / yönteme iletirken liste parametre adına atanır. Listeye eklemek listenin değiştirilmesine neden olur. İşlev içindeki listeyi yeniden atamak orijinal listeyi değiştirmez, çünkü:

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

Değişmez tipler değiştirilemediğinden, değerin geçirildiği anlaşılırlar - int'in bir fonksiyona geçirilmesi int'nin fonksiyonun parametresine atanması anlamına gelir. Bunu yalnızca yeniden atayabilirsiniz, ancak orijinal değişkenlerin değerini değiştirmez.


3
İlk bakışta bu cevap asıl soruyu kaldırıyor gibi görünüyor. İkinci bir okumadan sonra bunun konuyu açıklığa kavuşturduğunu fark ettim. Bu "isim ataması" kavramına iyi bir takip burada bulunabilir: Pythonista gibi bir kod: Deyimsel Python
Christian Groleau

65

Effbot (diğer adıyla Fredrik Lundh) Python'un değişken geçiş stilini nesneye göre çağrı olarak tanımladı: http://effbot.org/zone/call-by-object.htm

Nesneler öbek üzerinde tahsis edilir ve onlara işaretçiler her yerden geçirilebilir.

  • Gibi bir atama yaptığınızda x = 1000, geçerli ad alanındaki "x" dizesini bir işaretçi ile bin içeren tam sayı nesnesine eşleyen bir sözlük girdisi oluşturulur.

  • "X" ile güncellediğinizde x = 2000, yeni bir tamsayı nesnesi oluşturulur ve sözlük yeni nesneyi gösterecek şekilde güncellenir. Eski bin nesne değişmez (ve başka bir şey nesneyi ifade edip etmediğine bağlı olarak hayatta olabilir veya olmayabilir).

  • Yeni bir atama yaptığınızda y = x, "x" girişiyle aynı nesneyi gösteren yeni bir sözlük girdisi "y" oluşturulur.

  • Dizeler ve tamsayılar gibi nesneler değişmezdir . Bu, nesneyi oluşturulduktan sonra değiştirebilecek hiçbir yöntem olmadığı anlamına gelir. Örneğin, bin tam sayı nesnesi oluşturulduktan sonra asla değişmez. Matematik, yeni tamsayı nesneleri oluşturularak yapılır.

  • Listeler gibi nesneler değiştirilebilir . Bu, nesnenin içeriğinin, nesneye işaret eden herhangi bir şeyle değiştirilebileceği anlamına gelir. Örneğin, x = []; y = x; x.append(10); print yyazdırılacaktır [10]. Boş liste oluşturuldu. Hem "x" hem de "y" aynı listeyi gösterir. Ekleme yöntemi (bir veritabanına bir kayıt ekleme) mutasyon (güncellemeler) liste nesnesi ve sonuç her iki "x" ve "y" tarafından görülebilir (sadece bir veritabanı güncelleme olarak bu veritabanına her bağlantı için görünür olacaktır).

Bu sizin için sorunu açıklar.


2
Bunu bir geliştiriciden öğrenmeyi gerçekten takdir ediyorum. id()Pepr'ın cevabının önerdiği gibi , fonksiyonun işaretçinin (nesne referansının) değerini döndürdüğü doğru mu?
Dürüst Abe

4
@HonestAbe Evet, CPython'da id () adresi döndürür. Ancak PyPy ve Jython gibi diğer pitonlarda id () sadece benzersiz bir nesne tanımlayıcıdır.
Raymond Hettinger

59

Teknik olarak, Python her zaman referans değerlerle pass kullanır . İfademi desteklemek için diğer cevabımı tekrarlayacağım .

Python her zaman referans by değerleri kullanır. Herhangi bir istisna yoktur. Herhangi bir değişken ataması referans değerin kopyalanması anlamına gelir. İstisna yok. Herhangi bir değişken, referans değere bağlı addır. Her zaman.

Bir referans değeri hedef nesnenin adresi olarak düşünebilirsiniz. Adres kullanıldığında otomatik olarak kaydı kaldırılır. Bu şekilde, referans değerle çalışırken, doğrudan hedef nesne ile çalıştığınız anlaşılıyor. Ama her zaman arasında bir referans var, hedefe atlamak için bir adım daha.

İşte Python'un referans olarak geçerken kullandığını kanıtlayan örnek:

Argümanı geçirmenin resimli örneği

Bağımsız değişken değere göre iletildiyse, dış lstdeğiştirilemez. Yeşil, hedef nesnelerdir (siyah, içinde saklanan değerdir, kırmızı, nesne tipidir), sarı, içinde referans değerinin bulunduğu oktur - hafızadır. Mavi düz ok, işleve iletilen referans değerdir (kesikli mavi ok yolu üzerinden). Çirkin koyu sarı iç sözlüktür. (Aslında yeşil bir elips olarak da çizilebilir. Renk ve şekil sadece dahili olduğunu söylüyor.)

Kullanabilirsiniz id()Referans değerin ne olduğunu (yani hedef nesnenin adresi) öğrenmek yerleşik işlevi kullanabilirsiniz.

Derlenmiş dillerde bir değişken, türün değerini yakalayabilen bir bellek alanıdır. Python'da bir değişken, hedef nesneye referans değerini tutan referans değişkenine bağlı bir addır (dahili olarak dize olarak yakalanır). Değişkenin adı dahili sözlükteki anahtardır, söz konusu sözlük öğesinin değer kısmı referans değerini hedefe depolar.

Referans değerleri Python'da gizlidir. Referans değerini saklamak için açık bir kullanıcı türü yoktur. Bununla birlikte, tüm değişkenler hedef nesnelere referans olarak da depolandığından, bir liste öğesini (veya başka bir uygun kap türündeki öğeyi) referans değişkeni olarak kullanabilirsiniz. Başka bir deyişle, elemanlar aslında kabın içinde yer almaz - sadece elemanlara referanslar bulunur.


1
Aslında bu referans değeri ile geçtiğini doğruladı. Bu cevap için +1, örnek iyi olmasa da.
BugShotGG

30
Yeni terminoloji icat etmek ("referans değere göre geçiş" veya "nesneye göre çağrı" gibi) yararlı değildir. "Call by (value | reference | name)" standart terimlerdir. "referans" standart bir terimdir. Referansları değere göre iletmek, standart terminolojiyi kullanarak Python, Java ve diğer birçok dilin davranışını doğru bir şekilde tanımlar.
cayhorstmann

4
@cayhorstmann: Sorun Python değişkeninin diğer dillerle aynı terminoloji anlamına gelmemesidir. Bu şekilde, referans ile çağrı burada iyi uymuyor. Ayrıca, referans terimini tam olarak nasıl tanımlarsınız ? Gayri resmi olarak, Python yolu kolayca nesnenin adresini iletmek olarak tanımlanabilir. Ancak potansiyel olarak dağıtılmış bir Python uygulamasıyla uyuşmuyor.
pepr

1
Bu yanıtı beğendim, ancak örneğin akışa gerçekten yardım edip etmediğini düşünebilirsiniz. Ayrıca, 'referans değerini' 'nesne referansı' ile değiştirdiyseniz, burada görüldüğü gibi 'resmi' olarak değerlendirebileceğimiz terminolojiyi kullanırsınız: Fonksiyonları Tanımlama
Dürüst Abe

2
Bu teklifin sonunda belirtilen ve şu ifadeyi içeren bir dipnot vardır: "Aslında, nesne referansı ile çağrı daha iyi bir açıklama olacaktır, çünkü değiştirilebilir bir nesne geçirilirse, arayan kişinin kendisi üzerinde yaptığı değişiklikleri görecektir ... " Ben karışıklık diğer diller ile kurulan uyum terminoloji çalışırken neden olduğunu size katılıyorum. Anlambilim bir yana, anlaşılması gereken şeyler şunlardır: sözlükler / ad alanları, ad bağlama işlemleri ve ad → işaretçi → nesne (zaten bildiğiniz gibi) ilişkisi.
Dürüst Abe

56

Python'da değişken yok

Parametre geçişini anlamanın anahtarı "değişkenler" hakkında düşünmeyi bırakmaktır. Python'da isimler ve nesneler var ve birlikte değişkenler gibi görünüyorlar, ancak her zaman üçünü ayırt etmek yararlıdır.

  1. Python'un adları ve nesneleri var.
  2. Atama, bir nesneye bir ad bağlar.
  3. Bir işleve bağımsız değişken iletmek, bir nesneye bir ad (işlevin parametre adı) da bağlar.

Hepsi bu kadar. Değişebilirlik bu soru ile ilgisizdir.

Misal:

a = 1

Bu, adı a1 değerini tutan tamsayı türünde bir nesneye bağlar .

b = x

Bu, adı b, o xanda bağlı olduğu nesneye bağlar . Daha sonra, badın xartık adla ilgisi yoktur .

Bkz. Bölüm 3.1 ve 4.2Python 3 dil referansındaki .

Sorudaki örnek nasıl okunur

Soruda gösterilen kodda ifade self.Change(self.variable), adı var(işlev kapsamında Change) değeri tutan nesneye bağlar 'Original've atama var = 'Changed'(işlev gövdesinde Change) aynı adı yeniden atar: başka bir nesneye (gerçekleşir) bir dize tutmak için ama tamamen başka bir şey olabilirdi).

Referans ile nasıl geçilir

Dolayısıyla, değiştirmek istediğiniz şey değiştirilebilir bir nesne ise, sorun yoktur, çünkü her şey referansla etkili bir şekilde geçirilir.

Bir ise değişmez nesne (örneğin bir mantıksal değer, sayı, dize), hareket yolu bir değişken nesne sarın etmektir.
Bunun hızlı ve kirli çözümü tek elemanlı bir listedir (yerine self.variablegeçmek [self.variable]ve işlevde değişiklik yapmak var[0]).
Daha pitonik yaklaşım önemsiz, tek özellikli bir sınıf oluşturmak olacaktır. İşlev sınıfın bir örneğini alır ve özniteliği değiştirir.


20
"Python'un değişkenleri yok" aptalca ve kafa karıştırıcı bir slogan ve keşke insanlar bunu söylemekten vazgeçmeyi dilerdim ... :( Bu cevabın geri kalanı iyi!
Ned Batchelder

9
Şok edici olabilir, ama saçma değil. Ve ben de kafa karıştırıcı olduğunu düşünmüyorum: Umarım gelen açıklama için alıcının zihnini açar ve onu yararlı bir "değişkenler yerine neye sahip olduklarını merak ediyorum" tutumuna sokar. (Evet, kilometreniz değişebilir.)
Lutz Prechelt

13
Javascript'in değişken olmadığını da söyleyebilir misiniz? Python'larla aynı şekilde çalışırlar. Ayrıca, Java, Ruby, PHP, .... Bence daha iyi bir öğretim tekniği, "Python değişkenleri C'den farklı çalışır."
Ned Batchelder

9
Evet, Java değişkenleri vardır. Python ve JavaScript, Ruby, PHP, vb. Öyle. Java'da intbir değişken bildiren söyleyemezsiniz , ama Integersöylemezsiniz. İkisi de değişken bildiriyor. IntegerDeğişken bir amacı, intdeğişken bir ilkel. Örnek olarak, değişkenlerinizin nasıl çalıştığını göstererek gösterdiniz a = 1; b = a; a++ # doesn't modify b. Bu Python için de geçerlidir (Python'da += 1olmadığı için kullanmak ++)!
Ned Batchelder

1
"Değişken" kavramı karmaşıktır ve genellikle belirsizdir: Değişken, bir adla tanımlanan bir değer kabıdır. Python'da değerler nesnelerdir, kaplar nesnelerdir (soruna bakın?) Ve adlar aslında ayrı şeylerdir. Değişkenlerin bu şekilde doğru bir şekilde anlaşılmasının çok daha zor olduğuna inanıyorum . Adlar ve nesneler açıklaması daha zor görünür, ancak aslında daha basittir.
Lutz Prechelt

43

Normalde kullandığım basit bir numara sadece bir listeye sarmaktır:

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

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

(Evet, bunun rahatsız edici olabileceğini biliyorum, ancak bazen bunu yapmak için yeterince basit.)


7
Python'un doğrudan başvuru olmaması sorununa temel çözümü veren az miktarda metin için +1. (Bu sayfada olduğu gibi bu sayfadaki herhangi bir yere de uyan bir yorum / soru olarak: Python'un neden C # gibi bir "ref" anahtar kelimesi sağlayamadığı açık değil, bu sadece arayanın argümanını aşağıdaki gibi sarar ve işlevin içindeki bağımsız değişkene listenin 0. öğesi olarak atıflar uygulayın.)
M Katz

5
Güzel. Ref ile geçmek için [] 'yi sarın.
Justas

38

(değiştir - Blair, son derece popüler cevabını güncelledi, böylece şimdi doğru oldu)

Bence en çok oyu alan (Blair Conrad tarafından) mevcut yazının sonucuna göre doğru olmasına rağmen yanıltıcı ve tanımlarına göre sınırda yanlış olduğunu belirtmek önemlidir. Kullanıcının referansla veya değere göre geçmesine izin veren birçok dil (C gibi) olsa da, Python bunlardan biri değildir.

David Cournapeau'nun cevabı gerçek cevabı işaret ediyor ve Blair Conrad'ın gönderisindeki davranışın neden tanımlar doğru olmasa da doğru göründüğünü açıklıyor.

Python değere göre geçtiği ölçüde, bir miktar veri (ister "değer" veya "referans" olsun) gönderilmesi gerektiğinden, tüm diller değere göre geçer. Bununla birlikte, bu, Python'un bir C programcısının düşüneceği anlamıyla değere göre geçtiği anlamına gelmez.

Davranışı istiyorsanız, Blair Conrad'ın cevabı iyidir. Ancak Python'un neden değerden geçmediği veya referans olarak geçmediğinin somunlarını ve cıvatalarını bilmek istiyorsanız, David Cournapeau'nun cevabını okuyun.


4
Tüm dillerin değere göre çağrıldığı doğru değildir. C ++ veya Pascal'da (ve kesinlikle bilmediğim diğerlerinin çoğunda), referans ile çağrı yapabilirsiniz. Örneğin, C ++ 'da void swap(int& x, int& y) { int temp = x; x = y; y = temp; }kendisine aktarılan değişkenleri değiştirir. Pascal'da, varyerine kullanın &.
cayhorstmann

2
Uzun zaman önce buna cevap verdiğimi sanıyordum ama görmüyorum. Bütünlük için - cayhorstmann cevabımı yanlış anladı. Çoğu insanın C / C ++ ile ilgili ilk öğrendiği terimlerle her şeyin değere göre çağrı olduğunu söylemiyordum . Basitçe bir değerin geçmesi (değer, isim, işaretçi, vb.) Ve Blair'in orijinal cevabında kullanılan terimlerin yanlış olmasıydı.
KobeJohn

24

Burada gerçekten iyi cevaplar aldınız.

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

2
evet, ancak x = [2, 4, 4, 5, 5], y = x, X [0] = 1 yaparsanız, x # [1, 4, 4, 5, 5] yazdır y # [1 , 4, 4, 5, 5]
laycat

19

Bu durumda, varyöntemde başlıklı değişkene Changebir başvuru atanır self.variableve hemen bir dize atarsınız var. Artık işaret etmiyor self.variable. Aşağıdaki kod snippet'i, işaret ettiği veri yapısını varve self.variablebu durumda bir listeyi değiştirirseniz ne olacağını gösterir :

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

Eminim başka biri bunu daha da netleştirebilir.


18

Python'un atama öteleme şeması, C ++ 'ın referans parametreleri seçeneğiyle aynı değildir, ancak pratikte C dilinin (ve diğerlerinin) argüman geçiş modeline çok benzemektedir:

  • Değişmez argümanlar etkin bir şekilde “ değere göre geçirilir” . Tamsayılar ve dizeler gibi nesneler kopyalama yerine nesne başvurusu ile iletilir, ancak değiştirilemeyen nesneleri yine de yerinde değiştiremediğiniz için, efekt bir kopya yapmak gibidir.
  • Değişken argümanlar etkin bir şekilde “ işaretçiile aktarılır . Listeler ve sözlükler gibi nesneler de, C'nin dizileri işaretçi olarak geçirme biçimine benzer olan nesne başvurusu ile iletilir; değişken diziler, işlevde C dizileri gibi değiştirilebilir.

16

Tahmin edebileceğiniz gibi değişebilir bir nesneye sahip olmanız gerekir, ancak size yardımcı olabileceği veya hatta bu tür bir sorunu çözebileceği için küresel değişkenleri kontrol etmenizi öneriyorum!

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

misal:

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

5
Benzer bir yanıt göndermeye cazip geldim - orijinal soru soran, istediği şeyin aslında fonksiyonlar arasında paylaşılan küresel bir değişken kullanmak olduğunu bilmiyor olabilir. Paylaştığım bağlantı şu şekildedir : stackoverflow.com/questions/423379/… @Tim'e yanıt olarak Yığın Taşması sadece bir soru ve cevap sitesi değil, sadece daha güçlü ve daha nüanslı hale gelen geniş bir referans bilgi deposu. aktif bir wiki gibi daha fazla girdi ile.
Max P Magee

13

Burada cevaplar bir sürü içgörü, ama bence burada ek bir nokta açıkça açıkça belirtilmemiş. Python belgelerinden alıntı https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

"Python'da, yalnızca bir işlev içinde başvurulan değişkenler dolaylı olarak globaldir. Bir değişkene işlevin gövdesinde herhangi bir yerde yeni bir değer atanırsa, yerel olduğu varsayılır. Bir değişkene işlev içinde yeni bir değer atanırsa, değişken, dolaylı olarak yereldir ve bunu açıkça 'global' olarak bildirmeniz gerekir.İlk başta biraz şaşırtıcı olsa da, bir anın düşünülmesi bunu açıklar.Öte yandan, atanan değişkenler için global gereksinimi, istenmeyen yan etkilere karşı bir bar sağlar. diğer yandan, eğer tüm global referanslar için global gerekiyorsa, her zaman global kullanırsınız, yerleşik bir fonksiyona veya içe aktarılan bir modülün bir bileşenine yapılan her referansı global olarak beyan etmeniz gerekir. küresel bildirimin yan etkileri tanımlamak için yararlılığını yenebilir. "

Değişken bir nesneyi bir işleve geçirirken bile bu hala geçerlidir. Ve bana, nesneye atama ile işlevdeki nesne üzerinde çalışma arasındaki davranış farkının nedenini açıkça açıklıyor.

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)

verir:

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

Genel olarak bildirilmeyen bir genel değişkene atama bu nedenle yeni bir yerel nesne oluşturur ve orijinal nesnenin bağlantısını keser.


10

İşte pass by objectPython'da kullanılan kavramın basit (umarım) açıklaması .
Bir nesneyi işleve ilettiğinizde, nesnenin kendisi iletilmez (Python'daki nesne aslında diğer programlama dillerinde bir değer olarak adlandırdığınız şeydir) bu nesnenin başvurusu değil. Başka bir deyişle, aradığınızda:

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

my_list = [0, 1]
change_me(my_list)

Asıl nesne - [0, 1] (diğer programlama dillerinde bir değer olarak adlandırılır) geçiriliyor. Aslında fonksiyon aşağıdaki change_megibi bir şey yapmaya çalışacaktır:

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

açıkçası, işleve iletilen nesneyi değiştirmez. İşlev şu şekilde görünüyorsa:

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

Sonra çağrı ile sonuçlanır:

[0, 1].append(2)

ki bu açıkça nesneyi değiştirecek. Bu cevap bunu iyi açıklıyor.


2
Sorun, atamanın beklediğinizden başka bir şey yapmasıdır. list = [1, 2, 3]Yeniden nedenleri listbaşka bir şey için isim ve orijinal olarak geçirilen nesne forgeting. Ancak deneyebileceğiniz list[:] = [1, 2, 3]bu arada ( listyanlış isim bir değişken için düşünürsek. [0, 1] = [1, 2, 3]Komple saçma Neyse, aracı sizce neyi. Nesnenin kendisi geçirilir sizce işlevine kopyalanır Ne??
pepr

@pepr nesneleri değişmez değerler değildir. Onlar nesneler. Onlar hakkında konuşmanın tek yolu onlara bazı isimler vermektir. Bu yüzden onu kavradığınızda çok basit, ama açıklamak çok karmaşık. :-)
Veky

@Veky: Bunun farkındayım. Her neyse, liste değişmezi liste nesnesine dönüştürülür. Aslında, Python'daki herhangi bir nesne bir isim olmadan var olabilir ve herhangi bir isim verilmemiş olsa bile kullanılabilir. Ve onları anonim nesneler olarak düşünebilirsiniz. Nesneleri bir listenin öğeleri olarak düşünün. Bir isme ihtiyaçları yok. Listeye indeksleme veya yineleme yoluyla erişebilirsiniz. Her neyse, ısrar ediyorum [0, 1] = [1, 2, 3]sadece kötü bir örnek. Python'da böyle bir şey yok.
pepr

@pepr: Python tanım adları demek istemiyorum, sadece sıradan isimler. Tabii ki alist[2], üçüncü bir alist elementinin adı olarak sayılır. Ama sanırım problemin ne olduğunu yanlış anladım. :-)
Veky

Ahh. İngilizcem açıkça Python'umdan çok daha kötü. :-) Bir kez daha deneyeceğim. Sadece nesneye onlar hakkında konuşmak için bazı isimler vermeniz gerektiğini söyledim. Bu "isimler" ile "Python tarafından tanımlanan isimler" demek istemedim. Python mekanizmalarını biliyorum, endişelenme.
Veky

8

Bu şeylerin Python'da nasıl çalıştığına dair tüm büyük açıklamaların yanı sıra, sorun için basit bir öneri görmüyorum. Nesneler ve örnekler oluşturduğunuz gibi, örnek değişkenlerini işlemenin ve bunları değiştirmenin pitonik yolu şudur:

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

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

Örnek yöntemlerinde, normalde selförnek niteliklerine erişmeyi ifade edersiniz . Örnek niteliklerini ayarlamak __init__ve örnek yöntemlerinde bunları okumak veya değiştirmek normaldir . Bu yüzden aynı zamanda selfilk argümanıdef Change .

Başka bir çözüm şöyle statik bir yöntem oluşturmak olacaktır:

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

6

Dil bir nesneyi mümkün kılmasa bile, nesneyi referans olarak iletmek için küçük bir hile vardır. Java'da da çalışır, tek bir öğeyle liste. ;-)

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

Bu çirkin bir hack, ama işe yarıyor. ;-P


p, nesneyi depolayan değişken bir liste nesnesine başvurudur obj. 'P' referansı aktarılır changeRef. İçeride changeRef, refişaret eden aynı liste nesnesini gösteren yeni bir başvuru oluşturulur (yeni başvuru çağrılır ) p. Ancak listeler değiştirilebilir olduğundan, listedeki değişiklikler her iki başvuru tarafından da görülebilir . Bu durumda, refbaşvuruyu daha sonra PassByReference('Michael')nesneyi depolayacak şekilde dizin 0'daki nesneyi değiştirmek için kullandınız . Liste nesnesindeki refdeğişiklik kullanılarak yapıldı, ancak bu değişiklik görünür durumda p.
Minh Tran

Şimdi, referanslar pve reftek nesneyi saklayan bir liste nesnesine işaret edin PassByReference('Michael'). Böylece p[0].namegeri döner Michael. Tabii ki, refşimdi kapsam dışına çıktı ve çöp toplanmış olabilir ama hepsi aynı olabilir.
Minh Tran

Sen gelmiş değil , özel örnek değişkeni değiştirildi nameorijinal, PassByReferencereferans ile ilişkili nesne objolsa. Aslında obj.namegeri dönecek Peter. Yukarıda bahsi geçen yorumlar, tanımın verildiğini varsayar Mark Ransom.
Minh Tran

Aslında, bunun bir hack olduğu konusunda hemfikir değilim . Basitçe bir PassByReferencenesneyi PassByReferencelistenizdeki başka bir nesneyle değiştirdiniz ve iki nesneyi ikincisine yönlendirdiniz.
Minh Tran

5

Birkaç Fortran kodunu Python'a hızlıca dönüştürmek için aşağıdaki yöntemi kullandım. Doğru, orijinal soru ortaya atıldığı için referans olarak geçilmez, ancak bazı durumlarda basit bir çalışmadır.

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

Evet, bu benim kullanım durumumdaki 'referansla geç' seçeneğini de çözer. Temelde bir değerleri temizler dictve sonra döndüren bir işlevi var dict. Bununla birlikte, temizlik sırasında sistemin bir parçasının yeniden inşası gerekli görünebilir. Bu nedenle, işlev yalnızca temizlenmiş olanı döndürmekle kalmamalı, dictaynı zamanda yeniden inşaa sinyal verebilmelidir. Bir boolreferans geçmeye çalıştım , ama bu işe yaramaz. Bunu nasıl çözeceğimizi anlayarak, çözümünüzü (temelde bir tuple döndürerek), aynı zamanda bir hack / geçici çözüm (IMHO) olmadan da en iyi şekilde çalışmak için buldum.
kasimir

3

Referans yoluyla geçiş, python'a iyi uyan ve nadiren kullanılması gereken bir şey olmasa da, aslında şu anda yerel bir değişkene atanan nesneyi almak için çalışabilecek veya hatta bir çağrılan fonksiyonun içinden yerel bir değişkeni yeniden atayabilecek bazı geçici çözümler vardır.

Temel fikir, bu erişimi gerçekleştirebilen ve nesne olarak diğer işlevlere geçirilebilen veya bir sınıfta saklanabilen bir işleve sahip olmaktır.

Bunun bir yolu, bir sarma işlevinde ( globalgenel değişkenler için) veya nonlocal(bir işlevdeki yerel değişkenler için ) kullanmaktır .

def change(wrapper):
    wrapper(7)

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

Aynı fikir, delbir değişkeni okumak ve tanımlamak için de geçerlidir.

Sadece okumak için, sadece lambda: xçağrıldığında x'in geçerli değerini döndüren bir çağrılabilir döndüren kullanmanın daha kısa bir yolu vardır . Bu biraz uzaktaki dillerde kullanılan "isimle çağrı" gibi bir şey.

Bir değişkene erişmek için 3 paket geçirmek biraz kullanışsızdır, böylece bunlar proxy özniteliğine sahip bir sınıfa sarılabilir:

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

Pythons "yansıma" desteği, belirli bir kapsamdaki bir adı / değişkeni, o kapsamdaki işlevleri açıkça tanımlamadan yeniden atayabilen bir nesnenin elde edilmesini mümkün kılar:

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)

Burada ByRefsınıf bir sözlük erişimini sarar. Böylece öznitelik erişimi wrapped, iletilen sözlükteki bir öğe erişimine çevrilir. Yerleşimin sonucunu localsve yerel bir değişkenin adını geçerek, yerel bir değişkene erişilir. 3.5'teki python belgeleri sözlüğü değiştirmenin işe yaramayabileceğini ama benim için işe yaradığını gösteriyor.


3

python'un değerleri ve bunlara referansları işleme şekli göz önüne alındığında, rastgele bir örnek niteliğine başvurabilmenin tek yolu ada göre:

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

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

gerçek kodda, elbette, dict aramasına hata kontrolü eklersiniz.


3

Sözlükler başvuru ile iletildiğinden, içinde başvurulan değerleri depolamak için bir dikte değişkeni kullanabilirsiniz.

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!" # reference any string (errors, e.t.c). ref['msg'] is string
    return result # return the sum

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the return value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value

3

Python'daki Referansla Geçiş, C ++ / Java'daki referansla geçiş kavramından oldukça farklıdır.

  • Java & C #: ilkel tipler (dize dahil) değere göre geçiş (kopya), Referans tipi referansla (adres kopyası) geçirilir, böylece çağrılan işlevde parametrede yapılan tüm değişiklikler arayan tarafından görülebilir.
  • C ++: Hem referans hem de by-pass değerine izin verilir. Bir parametre referansla iletilirse, parametrenin const olarak iletilip iletilmemesine bağlı olarak değiştirebilir veya değiştiremezsiniz. Bununla birlikte, const ya da değil, parametre nesneye başvuruyu korur ve çağrılan işlev içindeki farklı bir nesneyi işaret etmek için başvuru atanamaz.
  • Python: Python “nesne-nesne-referansı” dır ki, sıklıkla söylenir: “Nesne referansları değere göre geçmektedir.” 1. Hem arayan hem de işlev aynı nesneyi ifade eder, ancak işlevdeki parametre, arayanın içinde nesnenin bir kopyasını tutan yeni bir değişkendir. C ++ gibi, bir parametre de değiştirilebilir veya işlevde olmayabilir - Bu, iletilen nesnenin türüne bağlıdır. Örneğin; Değişmez bir nesne türü çağrılan işlevde değiştirilemezken, değiştirilebilir bir nesne güncellenebilir veya yeniden başlatılabilir. Değişken değişkenin güncellenmesi veya yeniden atanması / yeniden başlatılması arasındaki önemli bir fark, güncellenen değerin çağrılan fonksiyona geri yansıtılması, yeniden başlatılmış değerin olmamasıdır. Değişken bir değişkene herhangi bir yeni nesne atamasının kapsamı, pitondaki fonksiyon için yereldir. @ Blair-conrad tarafından sağlanan örnekler bunu anlamak için mükemmeldir.

1
Yaşlı ama bunu düzeltmek zorunda hissediyorum. Dizeler hem Java hem de C # 'ta referansla geçirilir, değere göre DEĞİL
John

2

Örneğiniz nesne yönelimli olduğundan, benzer bir sonuç elde etmek için aşağıdaki değişikliği yapabilirsiniz:

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
Bu işe yarıyor olsa da. Referans olarak geçilmez. 'Nesne referansıyla geç' dir.
Bishwas Mishra

1

Dahili nesne öznitelikleri bir örnek sözlüğünde depolandığından, başvuru nesnelerini depolamak için yalnızca boş bir sınıfı örnek olarak kullanabilirsiniz . Örneğe bakın.

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)

1

Örneğin, C ++ 'dan bilinen referansları simüle etmek için bir yaklaşımdan bahsedilmediği için, bir "güncelleme" işlevi kullanmak ve gerçek değişken (veya daha doğrusu "ad") yerine bunu iletmektir:

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

Bu çoğunlukla "yalnızca dış referanslar" için veya birden çok iş parçacığı / işlem içeren bir durumda (güncelleme işlevi iş parçacığı / çok işlemciliğini güvenli hale getirerek) yararlıdır.

Açıkçası, yukarıdaki değer okumaya izin vermez , sadece güncellenir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.