Python dizeleri değişmez değil mi? Öyleyse neden a + “” + b çalışıyor?


110

Anladığım kadarıyla Python dizeleri değişmez.

Aşağıdaki kodu denedim:

a = "Dog"
b = "eats"
c = "treats"

print a, b, c
# Dog eats treats

print a + " " + b + " " + c
# Dog eats treats

print a
# Dog

a = a + " " + b + " " + c
print a
# Dog eats treats
# !!!

Python'un atamayı engellemesi gerekmez miydi? Muhtemelen bir şeyi kaçırıyorum.

Herhangi bir fikir?


55
Dizenin kendisi değişmezdir ancak etiket değişebilir.
mitch

6
Mevcut bir değişkene yeni bir değer atamak tamamen geçerlidir. Python'da sabitler yoktur. Bu, veri türü değişkenliğinden bağımsızdır.
Felix Kling

14
İşleve bir göz atmak isteyebilirsiniz id(). aatamadan önce ve sonra farklı nesnelere işaret ettiğini gösteren farklı bir kimliğe sahip olacaktır. Benzer şekilde, benzer bir kodla, b = abunu bulacaksınız ave baynı nesneyi referans gösterdiklerini belirten aynı kimliğe sahip olacaksınız.
DRH


Delnan'dan gelen bağlantı tam olarak benim bahsettiğim şey.
mitch

Yanıtlar:


182

İlk aönce "Dog" dizesini gösterdi. Sonra değişkeni ayeni bir "Köpek yiyecekleri yiyor" dizesini gösterecek şekilde değiştirdiniz . Aslında "Dog" dizesini değiştirmedin. Dizeler değişmezdir, değişkenler istedikleri her şeye işaret edebilir.


34
X = 'abc' gibi bir şey denemek daha da ikna edici; x [1] = Python
repl'de

1
İç işleri biraz daha anlamak isterseniz cevabıma bakın. stackoverflow.com/a/40702094/117471
Bruno Bronosky

54

Dize nesnelerinin kendileri değişmezdir.

Değişken, adizenin hangi noktaları, değişkendir.

Düşünmek:

a = "Foo"
# a now points to "Foo"
b = a
# b points to the same "Foo" that a points to
a = a + a
# a points to the new string "FooFoo", but b still points to the old "Foo"

print a
print b
# Outputs:

# FooFoo
# Foo

# Observe that b hasn't changed, even though a has.

@jason, a.append (3) 'ün a = a + "Foo" ya karşılık geldiğini görmek için listelerle (değiştirilebilir) aynı tür işlemleri deneyin
jimifiki

1
@jimifiki a.append(3) ile aynı şey değildira = a + 3 . Çift değil a += 3(yerinde ekleme eşdeğerdir, şuna .extenddeğil .append).

@delnan ve ne var? Dizelerin ve listelerin farklı davrandığını göstermek adına, a = a + "Foo" nun a.append (bir şey) ile aynı olduğunu varsayabilirsiniz. Her durumda aynı değil. Açıkçası. A.append (bir şey) yerine a.extend ([bir şey]) okurken daha mutlu muydunuz? Bu bağlamda o kadar büyük bir fark görmüyorum. Ama muhtemelen bir şeyi kaçırıyorum. Thruth bağlama bağlıdır
jimifiki

@jimifiki: Neden bahsediyorsun? +listeler ve dizeler için aynı şekilde davranır - yeni bir kopya oluşturur ve her iki işleneni de değiştirmez.

6
Tüm bunlardan çıkarılması gereken gerçekten önemli nokta, dizelerin bir append işlevi olmadığıdır çünkü değişmezler.
Lily Chung

46

A değişkeni "Köpek" nesnesini işaret ediyor. Python'daki değişkeni bir etiket olarak düşünmek en iyisidir. Eğer değişince ne yaptığını olan farklı nesnelere etiketi taşıyabilirsiniz a = "dog"için a = "dog eats treats".

Bununla birlikte, değişmezlik, etikete değil nesneye atıfta bulunur.


Eğer çalıştı a[1] = 'z'yapmak için "dog"içine "dzg"hatayı alacağı:

TypeError: 'str' object does not support item assignment" 

çünkü dizeler öğe atamasını desteklemez, dolayısıyla değişmezler.


19

Yalnızca bellek konumunda tutulan değerleri bellek konumunu değiştirmeden değiştirebildiğimizde bir şey değiştirilebilir.

İşin püf noktası şudur: Değişiklikten önceki ve sonraki bellek konumunun aynı olduğunu fark ederseniz, değiştirilebilir.

Örneğin, liste değiştirilebilir. Nasıl?

>> a = ['hello']
>> id(a)
139767295067632

# Now let's modify
#1
>> a[0] = "hello new"
>> a
['hello new']
Now that we have changed "a", let's see the location of a
>> id(a)
139767295067632
so it is the same as before. So we mutated a. So list is mutable.

Bir dizge değişmezdir. Bunu nasıl kanıtlarız?

> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------

anlıyoruz

TypeError: 'str' nesnesi öğe atamasını desteklemiyor

Bu yüzden dizeyi değiştirmede başarısız olduk. Bir dizenin değişmez olduğu anlamına gelir.

Yeniden atarken, değişkeni yeni bir konumu gösterecek şekilde değiştirirsiniz. Burada dizgeyi değiştirmediniz, değişkenin kendisini değiştirdiniz. Aşağıdaki, yaptığınız şeydir.

>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808

idYeniden atamadan önce ve sonra farklıdır, bu nedenle bu aslında mutasyona uğramadığınızı, ancak değişkeni yeni konuma yönlendirdiğinizi kanıtlar. Bu dizeyi mutasyona uğratmak değil, değişkeni değiştirmek.


11

Değişken, sadece bir nesneye işaret eden bir etikettir. Nesne değişmez, ancak isterseniz etiketin tamamen farklı bir nesneye işaret etmesini sağlayabilirsiniz.


8

Düşünmek:

>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='qwer'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x109198490>

Aynı değeri değişkende iki kez sakladığımda onaltılık bellek konumunun değişmediğine dikkat edin. Farklı bir değer kaydettiğimde değişti. Dize değişmezdir. Bağnazlıktan değil, bellekte yeni bir nesne yaratmanın performans cezasını ödediğiniz için. Değişken a, sadece bu bellek adresine işaret eden bir etikettir. Herhangi bir şeye işaret etmek için değiştirilebilir.


7

Deyim a = a + " " + b + " " + cişaretçiler dayalı bölünebilir.

a + " "bana adeğiştirilemeyecek noktaları ver ve " "mevcut çalışma setime ekle diyor .

hafıza:

working_set = "Dog "
a = "Dog" 
b = "eats"
c = "treats"

+ bbana hangi bnoktaları değiştirilemeyeceğini ver ve mevcut çalışma setine ekle diyor.

hafıza:

working_set = "Dog eats"
a = "Dog" 
b = "eats"
c = "treats"

+ " " + c" "geçerli kümeye ekle diyor . Sonra bana neyin cdeğiştirilemeyeceğini ver ve mevcut çalışma setine ekle. hafıza:

working_set = "Dog eats treats"
a = "Dog" 
b = "eats"
c = "treats"

Son olarak, a =işaretçimi sonuçtaki kümeyi gösterecek şekilde ayarla diyor.

hafıza:

a = "Dog eats treats"
b = "eats"
c = "treats"

"Dog"geri kazanıldı, çünkü onun bellek yığınına daha fazla işaretçi bağlanmıyor. "Dog"Değişmez ile kastedilen, içinde yer alan bellek bölümünü asla değiştirmedik . Ancak, varsa hangi etiketlerin belleğin o bölümünü işaret ettiğini değiştirebiliriz.


6
l = [1,2,3]
print id(l)
l.append(4)
print id(l) #object l is the same

a = "dog"
print id(a)
a = "cat"
print id(a) #object a is a new object, previous one is deleted

5

Veriler ile ilişkili olduğu etiket arasında bir fark vardır. Örneğin yaptığınızda

a = "dog"

veriler "dog"oluşturulur ve etiketin altına yerleştirilir a. Etiket değişebilir ama bellekte olanlar değişmez. Veriler "dog", siz yaptıktan sonra (çöp toplayıcı onu silene kadar) bellekte olmaya devam edecektir.

a = "cat"

Programınızda aşimdi ^ işareti ^ işaretidir, "cat"ancak dize "dog"değişmemiştir.


3

Python dizeleri değişmezdir. Ancak, abir dizge değildir: dizge değerine sahip bir değişkendir. Dizeyi değiştiremezsiniz, ancak değişkenin hangi değerini yeni bir dizeye değiştirebilirsiniz.


2

Değişkenler istedikleri herhangi bir yere işaret edebilir. Aşağıdakileri yaparsanız bir hata atılır:

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE

2

Python dize nesneleri değişmezdir. Misal:

>>> a = 'tanim'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281536'
>>> a = 'ahmed'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281600'

Bu örnekte, bir a'ya farklı bir değer atadığımızda değişmediğini görebiliriz. Yeni bir nesne yaratılır.
Ve değiştirilemez. Misal:

  >>> a[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

Bir hata meydana gelir.


2

'değişken', dizenin içeriğini değiştirebileceğimiz anlamına gelir, 'değişmez' ise fazladan bir dize ekleyemeyeceğimiz anlamına gelir.

fotoğraf kanıtı için tıklayın


1

>>> a = 'dogs'

>>> a.replace('dogs', 'dogs eat treats')

'dogs eat treats'

>>> print a

'dogs'

Değişmez, değil mi ?!

Değişken değişim kısmı zaten tartışılmıştır.


1
Bu, python dizelerinin değişkenliğini kanıtlamaz veya çürütmez, yalnızca replace()yöntemin yeni bir dizge döndürdüğünü gösterir.
Brent Hronik

1

Örneğinize bu ilaveyi düşünün

 a = "Dog"
 b = "eats"
 c = "treats"
 print (a,b,c)
 #Dog eats treats
 d = a + " " + b + " " + c
 print (a)
 #Dog
 print (d)
 #Dog eats treats

Bir blogda bulduğum daha kesin açıklamalardan biri şudur:

Python'da (neredeyse) her şey bir nesnedir. Python'da genellikle "değişkenler" olarak adlandırdığımız şeylere daha uygun şekilde adlar denir. Aynı şekilde, "atama" da bir adın bir nesneye bağlanmasıdır. Her bağlamanın görünürlüğünü tanımlayan bir kapsamı vardır, genellikle adın geldiği blok.

Örneğin:

some_guy = 'Fred'
# ...
some_guy = 'George'

Daha sonra some_guy = 'George' dediğimizde, 'Fred' içeren dizge nesnesi etkilenmez. Az önce some_guy adının bağlantısını değiştirdik. Bununla birlikte, 'Fred' veya 'George' dizgi nesnelerini değiştirmedik. Bize göre, sonsuza kadar yaşayabilirler.

Bloga bağlantı: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/


1

Yukarıda belirtilen cevaplara biraz daha fazla eklemek.

id yeniden atama üzerine değişken değişiklikler.

>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776

Bu, değişkeni ayeni bir dizgeye işaret edecek şekilde değiştirdiğimiz anlamına gelir . Şimdi iki tane var string (str) nesne var:

'initial_string'ile id= 139982120425648

ve

'new_string'ile id= 139982120425776

Aşağıdaki kodu göz önünde bulundurun:

>>> b = 'intitial_string'
>>> id(b)
139982120425648

Şimdi, bişaret 'initial_string've aynı var idolarak ayeniden görevlendirme önce vardı.

Böylece, 'intial_string'mutasyona uğramamıştır.


0

Özetleme:

a = 3
b = a
a = 3+2
print b
# 5

Değişmez değil:

a = 'OOP'
b = a
a = 'p'+a
print b
# OOP

Değişmez:

a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
    b[i] = a[i]+1

Bu Python 3'te bir hatadır çünkü değişmezdir. Ve Python 2'de bir hata değil çünkü açıkça değişmez değil.


0

Yerleşik işlev id(), bir nesnenin kimliğini bir tamsayı olarak döndürür. Bu tam sayı genellikle nesnenin bellekteki konumuna karşılık gelir.

\>>a='dog'
\>>print(id(a))

139831803293008

\>>a=a+'cat'
\>>print(id(a))

139831803293120

Başlangıçta 'a', 139831803293008 bellek konumunda saklanır, çünkü dize nesnesi python'da değişmezdir, eğer referansı değiştirmeye ve yeniden atamaya çalışırsanız, referansı kaldırılacak ve yeni bir bellek konumuna (139831803293120) bir işaretçi olacaktır.


0
a = 'dog'
address = id(a)
print(id(a))

a = a + 'cat'
print(id(a))      #Address changes

import ctypes
ctypes.cast(address, ctypes.py_object).value    #value at old address is intact

2
Bu kod OP'nin sorununu çözebilirken, kodunuzun OP sorununu nasıl ele aldığına dair bir açıklama eklemek en iyisidir. Bu şekilde, gelecekteki ziyaretçiler gönderinizden öğrenebilir ve kendi kodlarına uygulayabilir. SO bir kodlama hizmeti değil, bilgi için bir kaynaktır. Ayrıca, yüksek kaliteli, eksiksiz yanıtların olumlu oy kullanma olasılığı daha yüksektir. Bu özellikler, tüm gönderilerin bağımsız olması gerekliliğinin yanı sıra, onu forumlardan ayıran bir platform olarak SO'nun güçlü yönlerinden bazılarıdır. Ek bilgi eklemek ve / veya açıklamalarınızı kaynak belgelerle desteklemek için düzenleme yapabilirsiniz
SherylHohman

-1

Bu görüntü cevabı veriyor. Lütfen onu oku.

görüntü açıklamasını buraya girin


-1

Sadece iki dize değerini birleştiriyoruz. (A) 'nın değerini asla değiştirmeyiz. Şu anda (a) "dogdog" değerine sahip başka bir bellek bloğunu temsil eder. Çünkü arka uçta, bir değişken asla aynı anda iki bellek bloğunu temsil etmez. Birleştirmeden önce (a) 'nın değeri "köpek" idi. Ama ondan sonra (a) "dogdog" u temsil eder, çünkü şimdi (a) arka uç temsilinde "dogdog" değerine sahip blok. Ve "köpek" rep. (b) ve "köpek", (b) "köpeği" temsil edene kadar çöp değeri olarak sayılmaz.

Karışıklık, arka uçtaki bellek bloklarını (veri veya bilgi içeren) aynı değişken adı ile temsil etmemizdir.


-2

Uyuşmuş bir diziyi değişmez yapabilir ve ilk öğeyi kullanabilirsiniz:

numpyarrayname[0] = "write once"

sonra:

numpyarrayname.setflags(write=False)

veya

numpyarrayname.flags.writeable = False
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.