Değişken ve Değişken Tipler


186

Değişmez bir türün ne olduğu konusunda kafam karıştı. floatKitabımdaki bu tür bir örnekle nesnenin değişmez olarak kabul edildiğini biliyorum :

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))

Sınıf yapısı / hiyerarşisi nedeniyle bunun değişmez olduğu düşünülüyor mu? Anlam floatsınıfın en üstünde ve kendi yöntem çağrısıdır. Bu tür bir örneğe benzer şekilde (kitabım dictsöylenebilir olsa bile ):

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Değişken bir şeyin sınıf içinde, bu tür bir örnekle yöntemleri vardır:

class SortedKeyDict_a(dict):
    def example(self):
        return self.keys()

Ayrıca, son olarak class(SortedKeyDict_a), bu tür bir kümeyi ona aktarırsam:

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

exampleyöntemi çağırmadan bir sözlük döndürür. SortedKeyDictİle __new__hata olarak bayraklar onu. RoundFloatSınıfa tamsayı geçmeyi denedim __new__ve hiçbir hata işaretledi.


Ayrıca , değiştirilebilirlik hakkında daha fazla bilgi için cevapladığım copy.copy'yi ne zaman kullanacağımı [:] ve python ile Liste atamasına da göz atabilirsiniz .
agf

Yanıtlar:


232

Ne? Şamandıralar değişmez mi? Ama yapamam

x = 5.0
x += 7.0
print x # 12.0

Bu "mut" x değil mi?

Dizelerin değişmez olduğuna katılıyorsunuz değil mi? Ama aynı şeyi yapabilirsiniz.

s = 'foo'
s += 'bar'
print s # foobar

Değişkenin değeri değişir, ancak değişkenin neyi ifade ettiğini değiştirerek değişir. Değişken tip bu şekilde değişebilir ve ayrıca "yerinde" de değişebilir.

İşte fark.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Somut örnekler

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]

5
Açıkladığınız şey bana göre: değişebilir değişkenler referansla, değişmez değişkenler değere göre geçer. Bu doğru mu ?
Lorenz Meyer

17
Neredeyse ama tam olarak değil. Teknik olarak, tüm değişkenler Python'da referans olarak geçirilir, ancak C'de değere göre daha fazla değere benzer bir semantiğe sahiptir def f(my_list): my_list = [1, 2, 3]. C'de başvuru yoluyla, bağımsız değişkenin değeri bu işlevi çağırarak değişebilir. Python'da bu işlev hiçbir şey yapmaz. def f(my_list): my_list[:] = [1, 2, 3]bir şey yapardı.
morningstar

6
Değişken tipler yerinde değiştirilebilir. Değişmez tipler yerinde değişemez. Python dünyayı böyle görüyor. Değişkenlerin fonksiyonlara nasıl aktarıldığına bakılmaksızın.
Şubat

13
Python'un semantiği ile C ++ referans by pass semantiği arasındaki temel fark, atamanın Python'da mutasyon olmaması ve C ++'da olmasıdır. (Ama elbette bu, artırılmış atamanın a += bbazen olduğu gibi mutasyon olmasıyla karmaşıktır . Ve daha büyük bir nesnenin bir kısmına atamanın bazen daha büyük nesnenin mutasyonu anlamına gelmesi, parçanın asla mutasyona a[0] = buğramaması anlamına gelmez - örneğin, mutasyona uğramaz a[0], ama muhtemelen mutasyona uğruyor a… Bu yüzden bir şeyleri C ++ cinsinden koymaya çalışmak yerine Python'un kendi terimleriyle ne yaptığını açıklamak daha iyi olabilir…)
abarnert

2
Bu cevabı yanıltıcı buldum çünkü değişmez ne anlama geldiğini anlamak için gerekli olan id () kullanmıyor.
pawel_winzig

185

Python'un tüm verilerini nesne olarak temsil ettiğini anlamalısınız. Listeler ve sözlükler gibi bu nesnelerin bazıları değiştirilebilir, yani kimliklerini değiştirmeden içeriklerini değiştirebilirsiniz. Tamsayı, kayan nokta, dize ve tuples gibi diğer nesneler değiştirilemeyen nesnelerdir. Bunu anlamanın kolay bir yolu, bir nesne kimliğine bakmanızdır.

Aşağıda değişmez bir dize görüyorsunuz. İçeriğini değiştiremezsiniz. TypeErrorDeğiştirmeye çalışırsanız bir yükselecektir . Ayrıca, yeni içerik atarsak, değiştirilen içerik yerine yeni bir nesne oluşturulur.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

Bunu bir liste ile yapabilirsiniz ve nesnelerin kimliğini değiştirmez

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Python'un veri modeli hakkında daha fazla bilgi edinmek için Python dil referansına bakabilirsiniz:


4
+1 Python belgelerine bağlantı için. Ancak bugün Python 2 ve 3'ü farklılaştırmanız gerektiğini fark edene kadar biraz zaman aldı - Bunu vurgulamak için cevabı güncelledim.
benjamin

107

Ortak değişmez tip:

  1. numaraları: int(), float(),complex()
  2. değişmez sekansları str(), tuple(), frozenset(),bytes()

Ortak değişebilir tip (hemen hemen her şey):

  1. kesilebilir sekansları list(),bytearray()
  2. set türü: set()
  3. eşleme türü: dict()
  4. sınıflar, sınıf örnekleri
  5. vb.

Bir türün değiştirilebilir olup olmadığını hızlı bir şekilde test etmenin bir püf noktası id()yerleşik işlevi kullanmaktır.

Tamsayı üzerinde kullanılan örnekler,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

listede kullanmak,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)

11
İyi açıkladı. Tarafından kontrol kavramı sevdim id(). +1.
Parag Tyagi

4
Aslında burada kullanımı id()yanıltıcı. Belirli bir nesne kullanım ömrü boyunca her zaman aynı kimliğe sahip olur, ancak farklı zamanlarda var olan farklı nesneler çöp toplama nedeniyle aynı kimliğe sahip olabilir.
augurar

37

Her şeyden önce, bir sınıfın yöntemleri olup olmadığı veya sınıf yapısının ne olduğu değişebilirlikle ilgisi yoktur.

ints ve floats değişmezdir . Eğer yaparsam

a = 1
a += 5

Adı , ilk satırdaki bellekte abir 1yere işaret eder . İkinci satırda, o bakar 1, ekler 5alır, 6daha sonra puan aŞuna 6bellekte - bu yoktu değiştirmek1 bir için 6herhangi bir şekilde. Aynı mantık, diğer değişmez tipler kullanılarak aşağıdaki örnekler için de geçerlidir :

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

İçin değişken türleri, ben actallly şeyi yapabiliriz bellekte depolanan değeri değiştirin . İle:

d = [1, 2, 3]

Ben yerlerin listesini oluşturduk 1, 2ve 3bellekte. Eğer yaparsam

e = d

Sadece işaret eetmek aynılist d at noktaları. Sonra yapabilirim:

e += [4, 5]

Hem eve hem de dişaret eden listenin konumları 4ve 5hafızası olacak şekilde güncellenecektir .

Değişmez bir türe geri dönüp bunu bir ile yaparsam tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Sonra fhala sadece orijinalituple işaret gediyor - tamamen yenituple bir noktaya işaret ettiniz .

Şimdi, örneğinizle

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Nereden geçiyorsun

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(a hangi tuplebir tuplesşekilde) val, çünkü bir hata alıyorsanız tupleler bir yok .clear()yöntemi - Geçmek olurdu dict(d)olarak valişe bunun için boş bir alırsınız, bu durumda, SortedKeyDictsonuç olarak.


2
Bu çok iyi bir açıklama. Bu soruyu ve açıklamak için birçok ilginç (yeni) bakış açısını sevdim.
Başarısız Bilim İnsanı

25

Python'a başka bir dilden geliyorsanız (Ruby gibi Python'a çok benzeyen bir dil hariç) ve diğer dil açısından anlamaya ısrar ediyorsanız, insanların genellikle karıştığı yerler:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

Python'da atama Python'da mutasyon değildir.

C ++ 'da, yazarsanız a = 2, a.operator=(2)depolanan nesneyi değiştirecek olan çağırırsınız a. (Ve eğer orada oldu saklanan hiçbir nesne abir hatadır.)

Python'da a = 2depolananlara hiçbir şey yapmaz a; sadece bunun yerine 2depolandığı anlamına gelir a. (Ve içinde depolanmış bir nesne yoksa ,a sorun değil.)


Sonuçta, bu daha da derin bir ayrımın bir parçası.

C ++ gibi bir dildeki değişken, bellekte yazılan bir konumdur. Eğer bir aise int, bu derleyicinin bildiği bir yerde 4 bayt olduğu anlamına gelir int. Böylece, bunu yaptığınızda a = 2, bu 4 baytlık bellekte depolananları ile arasında 0, 0, 0, 1değiştirir 0, 0, 0, 2. Başka bir yerde int değişkeni varsa, kendi 4 baytı vardır.

Python gibi bir dilde değişken, kendi hayatı olan bir nesnenin adıdır. Sayı için bir nesne ve sayı 1için başka bir nesne var 2. Ve bir aolarak temsil edilen 4 bayt bellek değil int, sadece 1nesneye işaret eden bir isim . a = 21 sayısını 2 numarasına çevirmek mantıklı değildir (bu, herhangi bir Python programcısına evrenin temel işleyişini değiştirmek için çok fazla güç verir); bunun yerine sadece nesneyi aunutun ve 1nesneyi işaret edin 2.


Atama bir mutasyon değilse Yani, ne olduğunu bir mutasyon?

  • Mutasyona uğradığı belgelenmiş bir yöntemi çağırmak gibi a.append(b). (Bu yöntemlerin neredeyse her zaman geri döndüğünü unutmayın None). Değişmez tiplerin böyle bir yöntemi yoktur, değişebilir tipler genellikle vardır.
  • a.spam = bVeya gibi nesnenin bir kısmına atama a[0] = b. Değişmez türler niteliklere veya öğelere atamaya izin vermez, değişebilir türler genellikle birine veya diğerine izin verir.
  • Bazen artırılmış ödev kullanarak a += b, bazen değil. Değişken tipler genellikle değeri değiştirir; değişmez tipler asla yapmaz ve bunun yerine size bir kopya verir (hesaplar a + b, sonra sonucu atarlar a).

Ancak ödev mutasyon değilse, nesne mutasyonunun bir kısmına atama nasıl yapılır? Zorlaştığı yer burası. a[0] = bdoes not mutasyon a[0](yine C aksine ++), ancak does mutasyon a(C aksine ++, dolaylı hariç).

Tüm bunlar muhtemelen daha iyi değil alışık bir dil açısından Python'un anlambilim koymak deneyin, bunun yerine kendi şartlarda Python'un semantiğini öğrenmek için.


2
A = 'merhaba' deyin. a [0] = 'f' bir 'print out' fi 'yazdıracaktır (Şimdiye kadar haklı mıyım?). ? [N] 'nin de şimdi kendi yeri var mı ve değerini değiştirmek farklı bir değere mi işaret ediyor?
Daniel Springer

19

Bir nesnenin değişip değişmeyeceği, türüne bağlıdır. Bu, belirli yöntemlere sahip olup olmamasına veya sınıf hiyerarşisinin yapısına bağlı değildir.

Kullanıcı tanımlı tipler (yani sınıflar) genellikle değiştirilebilir. Değişmez tipte basit alt sınıflar gibi bazı istisnalar vardır. Diğer iletmenin bazı türleri gibi türleri dahili içerir int, float, tupleve strde bazı Python sınıfları C uygulanan şekilde,

Python Dil Başvurusu'ndaki "Veri Modeli" bölümünden genel bir açıklama :

Bazı nesnelerin değeri değişebilir. Değeri değişebilen nesnelerin değişebilir olduğu söylenir; değeri oluşturulduktan sonra değişmeyen nesnelere değişmez denir.

(Değişken bir nesneye başvuru içeren değişmez bir kapsayıcı nesnesinin değeri, ikincisinin değeri değiştirildiğinde değişebilir; ancak içerdiği nesnelerin toplanması değiştirilemeyeceği için kap yine de değişmez olarak kabul edilir. değişmez bir değere sahip olmakla aynı, daha incedir.)

Bir nesnenin değişebilirliği türüne göre belirlenir; örneğin, sayılar, dizeler ve tupller değiştirilemezken, sözlükler ve listeler değiştirilebilir.


+1 Sadece bazı uzantı türlerinin (bunun tanımını gözden geçirmek isteyebilirsiniz, Python'un yerleşik türlerinin tümünün C içinde uygulandığını) değişmez olduğunu unutmayın. Diğerleri (çoğu, söylemeye cesaret edebilirim) tamamen değişebilir.

@delnan "Uzantı türleri" ne diyorsunuz ?
eyquem

@eyquem: Cevabımda "uzantı türleri" terimini yanlış kullandım ve delnan buna değiniyordu. Yorumundan sonra cevabımı gözden geçirdim ve bu terimi kullanmaktan kaçındım.
taleinat

19

Değişken ve Değişken Nesneler Arasındaki Fark

Tanımlar

Değişken nesne : Oluşturulduktan sonra değiştirilebilen nesne.
Değişmez nesne : Oluşturulduktan sonra değiştirilemeyen nesne.

Python'da değişmez nesnenin değerini değiştirirseniz, yeni bir nesne oluşturulur.

Değişken Nesneler

Python'da değiştirilebilir türdeki nesneler şunlardır:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Değişmez Nesneler

Python'da değişmez tipte nesneler şunlardır:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Cevaplanmamış Bazı Sorular

Sorular : Dize değişmez bir tip midir?
Cevap : evet , ama bunu açıklayabilir misiniz: Kanıt 1 :

a = "Hello"
a +=" World"
print a

Çıktı

"Hello World"

Yukarıdaki örnekte dize bir kez "Merhaba" olarak oluşturulmuş ve daha sonra "Merhaba Dünya" olarak değiştirilmiştir. Bu, dizenin değişebilir tipte olduğu anlamına gelir. Ama değişebilir tipte olup olmadığını görmek için kimliğini kontrol ettiğimizde değil.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Çıktı

String is Immutable

Kanıt 2 :

a = "Hello World"
a[0] = "M"

Çıktı

TypeError 'str' object does not support item assignment

Sorular : Tuple değişmez bir tip midir?
Cevap : evet , öyle. Kanıt 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Çıktı

'tuple' object does not support item assignment

[46]: a = "Merhaba" Gir [47]: id (a) Çıkış [47]: 140071263880128 [48] 'de: a = a.replace ("H", "g") [49]: a Çıkan [49]: 'gello' In [50]: id (a) Out [50]: 140071263881040
Argus Malware

yukarıdaki örnek
Argus Malware

değişmez tiplerde öğe ataması yapılmaz. Sizin durumunuzda a dizesini değiştirirsiniz, ancak bellekte yeni bir değişkene atanır. Benim durumumdaki öğe ataması, liste veya sözlükte olduğu gibi değişkenin belleğini değiştirmez. eğer yenisini yapıyorsanız mevcut değişkeni değiştirmeyen yeni bir değişken oluşturuyorsunuz
anand tripathi

@ArgusMalware sizin durumunuzda, birincisi GC tarafından geri dönüştürüldüğünden iki kimlik eşittir, bu yüzden ikincisi belleği yeniden kullanır.
Cologler

11

Değişken bir nesnenin, nesneyi mutasyona uğratabilen en az bir yöntemi olması gerekir. Örneğin, listnesnenin nesneyi appendgerçekten değiştirecek yöntemi vardır :

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

ancak sınıfın floatbir kayan nokta nesnesini mutasyona uğratma yöntemi yoktur. Yapabilirsin:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

ancak =işlenen bir yöntem değildir. Sadece değişken ile sağındaki her şey arasında bir bağ kurar, başka bir şey değildir. Asla değişmez veya nesne yaratmaz. O zamandan beri değişkenin neye işaret edeceğinin bir açıklamasıdır.

Bunu yaptığınızda işlenen te sonuçla oluşturulan wich yeni şamandıra, değişkeni bağlar .b = b + 0.1=5 + 0.1

Var olan bir nesneye değişebilir (değişken veya değil) bir değişken atadığınızda, =işlenen değişkeni o nesneye bağlar. Ve başka bir şey olmaz

Her iki durumda da, =sadece bağlamayı yapın. Nesneleri değiştirmez veya oluşturmaz.

Bunu yaptığınızda a = 1.0, =işlenen şamandırayı değil 1.0, çizginin bir parçasını oluşturur. Aslında yazdığınızda bir float nesnesi döndüren bir yapıcı çağrısı 1.0için float(1.0)bir kısayol . (Bu nedenle, 1.0enter ve enter tuşuna basarsanız, 1.0aşağıda "echo" elde edersiniz ; aradığınız yapıcı işlevinin dönüş değeri budur)

Şimdi, eğer bbir şamandıra olduğunu ve atamak a = b, her iki değişken aynı nesneye işaret ancak can comunicate değil betweem kendileri nesne inmutable olduğundan ve bunu yaparsanız aslında değişkenler b += 1, şimdi byeni bir nesneye gelin ve abir hala oldone'u gösteriyor ve neye bişaret ettiğini bilemiyor .

ama eğer varsa c, diyelim ki, a list, ve a = cşimdi atayabilir ave c"comunicate" yapabilirsiniz, çünkü listdeğişebilir ve eğer yaparsanız c.append('msg'), o zaman sadece amesajı almak kontrol .

(Bu arada, her nesnenin ilişkili olabileceği benzersiz bir kimlik numarası vardır id(x). Böylece, bir nesnenin aynı olup olmadığını veya benzersiz kimliğinin değişip değişmediğini kontrol edebilirsiniz.)


6

Bir sınıf değişmez bu sınıfın her nesne olamaz örnekleme üzerine sabit bir değere sahip ise sonradan oluştuğu değiştirilebilir

Başka bir deyişle, bu değişkenin tüm değerini değiştirin (name)veya yalnız bırakın.

Misal:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

bunun çalışmasını ve merhaba dünyasını yazdırmasını beklediniz, ancak bu aşağıdaki hatayı atacaktır:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

Tercüman diyor ki: Bu dizenin ilk karakterini değiştiremiyorum

stringçalışmasını sağlamak için bütünü değiştirmek zorunda kalacaksınız :

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

bu tabloyu kontrol et:

resim açıklamasını buraya girin

kaynak


Bir python dizesinin bileşenlerini yukarıda gösterilenden daha özlü bir şekilde nasıl değiştirebilirim?
Luke Davis

@LukeDavis Yapabilirdin my_string = 'h' + my_string[1:]. Bu, my_string adlı yeni bir dize oluşturur ve orijinal my_string gitti ( id(my_string)bunu görmek için yazdır ). Tabii ki bu çok esnek değil, daha genel bir durum için listeye ve arkaya dönüştürebilirsiniz:l = list(my_string) l[0] = 'h' my_string = ''.join(l)
danio

5

Bana öyle geliyor ki , değişebilir / değişmez aslında ne anlama geliyor sorusuyla savaşıyorsunuz . İşte basit bir açıklama:

İlk olarak, açıklamayı dayandıracak bir vakfa ihtiyacımız var.

Bu nedenle, sanal bir nesne olarak programladığınız her şeyi, bilgisayar belleğine ikili sayılar dizisi olarak kaydedilen bir şeyi düşünün. (Bunu çok zor hayal etmeye çalışmayın. ^^) Şimdi çoğu bilgisayar dilinde bu ikili sayılarla doğrudan çalışmazsınız, daha çok ikili sayıların yorumunu kullanırsınız.

Örneğin, 0x110, 0xaf0278297319 veya benzeri sayıları düşünmezsiniz, bunun yerine 6 veya "Merhaba, dünya" gibi Dizeleri düşünürsünüz. Asla daha az tez sayısı veya Dizeleri bilgisayar belleğindeki bir ikili sayının yorumlanması değildir. Aynı şey bir değişkenin herhangi bir değeri için de geçerlidir.

Kısaca: Biz yok ile programlamak gerçek değerler ancak sahip gerçek bir ikili değerlerin yorumların.

Şimdi mantık ve diğer “temiz şeyler” uğruna değiştirilmemesi gereken yorumlarımız var, ancak değiştirilebilecek yorumlar da var. Örneğin bir şehrin simülasyonunu düşünün, diğer bir deyişle birçok sanal nesnenin olduğu ve bunların bazılarının ev olduğu bir program. Şimdi bu sanal nesneler (evler) değiştirilebilir ve hala aynı evler olarak kabul edilebilir mi? Tabii ki yapabilirler. Böylece değişebilirler: "Tamamen" farklı bir nesne haline gelmeden değiştirilebilirler.

Şimdi tamsayıları düşünün: Bunlar aynı zamanda sanal nesnelerdir (bilgisayar belleğindeki ikili sayı dizileri). Yani onlardan birini değiştirirsek, altı değeri birer birer artırmak gibi, hala altı mı? Tabii ki hayır. Böylece herhangi bir tam sayı değişmezdir.

Yani: Bir sanal nesnede yapılan herhangi bir değişiklik, onun aslında başka bir sanal nesne haline gelmesi anlamına gelirse, o zaman değişmez olarak adlandırılır.

Son açıklamalar:

(1) Gerçek dünyadaki değişebilir ve değişmez deneyiminizi asla belirli bir dilde programlama ile karıştırmayın:

Her programlama dilinin, hangi nesnelerin sesinin kapatılabileceği ve hangilerinin kapatılamayabileceği konusunda kendi tanımı vardır.

Artık anlamdaki farkı anlayabiliyor olsanız da, yine de her programlama dili için gerçek uygulamayı öğrenmek zorundasınız. ... Gerçekten de, 6'nın 7 olması için sessizleştirilebileceği bir dilin bir amacı olabilir. O zaman bu, paralel evrenlerin simülasyonları gibi oldukça çılgın veya ilginç şeyler olacaktır.

(2) Bu açıklama kesinlikle bilimsel değildir, değişebilir ve değişmez arasındaki farkı kavramanıza yardımcı olmak içindir.


5

Bu cevabın amacı, mutasyona uğramak / mutasyona uğramakla (değişmez / değişmez) başa çıkıp çıkmadığınızı nasıl anlayacağınızla ilgili tüm iyi fikirleri bulmak için tek bir yer yaratmaktır ve mümkün olduğunda bu konuda ne yapmalı? Mutasyonun istenmeyen olduğu ve python'un bu konudaki davranışının diğer dillerden gelen kodlayıcılara karşı sezgisel olabileceği zamanlar vardır.

@ Mina-gabriel tarafından yazılmış faydalı bir gönderiye göre:

Yukarıdakileri analiz etmek ve @ arrakëën tarafından bir gönderiyi birleştirmek:

Beklenmedik bir şekilde ne değişemez?

  • skaler (tek bir değer depolayan değişken türleri) beklenmedik şekilde değişmez
    • sayısal örnekler: int (), float (), complex ()
  • bazı "değişebilir diziler" vardır:
    • str (), tuple (), frozenset (), bayt ()

Ne yapabilirim?

  • nesneler gibi liste (listeler, sözlükler, kümeler, bytearray ())
  • Buradaki bir gönderi de sınıfları ve sınıf örneklerini söylüyor, ancak bu, sınıfın neyi miras aldığına ve / veya nasıl inşa edildiğine bağlı olabilir.

"beklenmedik bir şekilde" kastediyorum, diğer dillerden programcılar bu davranışı beklemeyebilirler (istisna veya Ruby ve belki birkaç "Python benzeri" dil).

Bu tartışmaya ekleniyor:

Bu davranış, yanlışlıkla bellek yiyen büyük veri yapılarının birden fazla kopyasıyla kodunuzu yanlışlıkla doldurmanızı engellediğinde bir avantajdır. Ancak bu istenmeyen bir durum olduğunda, bunun üstesinden nasıl gelebiliriz?

Listelerle, basit çözüm şöyle yeni bir tane oluşturmaktır:

list2 = liste (liste1)

diğer yapılarla ... çözüm daha zor olabilir. Bunun bir yolu, öğeler arasında dolaşmak ve bunları yeni bir boş veri yapısına (aynı türden) eklemektir.

Değişken yapılardan geçerken işlevler orijinali değiştirebilir. Nasıl söylesem?

  • Bu konudaki diğer yorumlarda verilen bazı testler var, ancak bu testlerin tam kanıt olmadığını belirten yorumlar var
  • object.function (), orijinal nesnenin bir yöntemidir, ancak bu mutasyonun yalnızca bir kısmıdır. Eğer hiçbir şey geri getirmezlerse, muhtemelen geri dönerler. .Append () 'in adını vermeden test etmeden değişmesini bekleyebilirsiniz. .union (), set1.union (set2) birleşimini döndürür ve değişmez. Şüphe duyduğunuzda, işlev bir dönüş değeri için kontrol edilebilir. Return = None ise, mutasyona uğramaz.
  • sort () bazı durumlarda geçici bir çözüm olabilir. Orijinalin sıralı bir sürümünü döndürdüğü için, orijinal üzerinde başka şekillerde çalışmaya başlamadan önce mutasyona uğramamış bir kopyayı saklamanıza izin verebilir. Ancak, bu seçenek orijinal öğelerin sırasını umursamadığınızı varsayar (eğer yaparsanız, başka bir yol bulmanız gerekir). Buna karşılık .sort () orijinali değiştirir (beklendiği gibi).

Standart Dışı Yaklaşımlar (yardımcı olması durumunda): Bunu bir MIT lisansı altında yayınlanan github'da buldu:

  • altında github deposu: tobgu adlı: pyrsistent
  • Nedir? Mutasyon istenmediğinde çekirdek veri yapılarının yerine kullanılmak üzere yazılan Python kalıcı veri yapısı kodu

Özel sınıflar için @semicolon, __hash__değiştirilebilen nesnelerin genellikle bir __hash__()işlevi olmaması gerektiği için bir işlev olup olmadığını kontrol etmenizi önerir .

Şimdilik bu konuda topladığım tek şey bu. Diğer fikirler, düzeltmeler vb. Teşekkürler.


3

Farkı düşünmenin bir yolu:

Python'daki değişmez nesnelere atamalar derin kopyalar olarak düşünülebilirken, değiştirilebilir nesnelere atamalar sığdır


1
Bu yanlış. Python'daki tüm ödevler referans amaçlıdır. Herhangi bir kopyalama yoktur.
augurar

3

En basit cevap:

Değişken bir değişken, değeri yerinde değişebilen bir değişkendir, değişmez bir değişkente ise değer değişikliği olmaz. Değişmez bir değişkeni değiştirmek aynı değişkeni yeniden oluşturur.

Misal:

>>>x = 5

X tarafından referans verilen 5 değerini oluşturur

x -> 5

>>>y = x

Bu ifade x'in 5'ine atıfta bulunur

x -------------> 5 <----------- y

>>>x = x + y

X bir tamsayı olarak (değişmez tip) yeniden inşa edilmiştir.

İfadede, RHS'deki ifade 10 değeriyle sonuçlanacaktır ve bu LHS (x) 'e atandığında, x 10 olarak yeniden oluşturulacaktır.

x ---------> 10

Y ---------> 5


-1

Tüm cevapları okumadım, ancak seçilen cevap doğru değil ve yazarın bir değişkeni yeniden atayabilme fikrinin, veri türünün değişebilir olduğu anlamına geldiğini düşünüyorum. Durum böyle değil. Değişebilirlik, değere göre geçmek yerine referansla geçmekle ilgilidir.

Bir Liste oluşturduğunuzu varsayalım

a = [1,2]

Eğer şunu söyleseydin:

b = a
b[1] = 3

B'de bir değeri yeniden atamış olsanız bile, a üzerindeki değeri yeniden atar. Çünkü "b = a" atadığınızda. "Başvuru" değerini değerin bir kopyası yerine nesneye geçiriyorsunuz. Bu dizeler, yüzer vb. İle durum böyle değil.


-1

Değişmez nesneler için atama, örneğin değerlerin yeni bir kopyasını oluşturur.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

Değişken nesneler için atama, değerlerin başka bir kopyasını oluşturmaz. Örneğin,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list

1
Kesinlikle yanlış. Atama asla bir kopya oluşturmaz . Lütfen okuyun nedbatchelder.com/text/names.html İlk durumda, x=10basitçe başka atama ise, x[2] = 5aramaların bir mutatör yöntemi. intnesneler sadece mutator yöntemlerinden yoksundur , ancak python atamasının semantiği tipe bağlı değildir
juanpa.arrivillaga

-2

Python'da bilmenin kolay bir yolu var:

Immutable:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

değişken:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

Ve:

>>> s=abs
>>> s is abs
True

Bu yüzden yerleşik fonksiyonun Python'da da değişmez olduğunu düşünüyorum.

Ama şamandıranın nasıl çalıştığını gerçekten anlamıyorum:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

Çok garip.


Ancak bu kesinlikle geçerli değil. Çünkü tupller değişmez. Yazın x = (1, 2)ve sonra mutasyona xuğramaya çalışın , bu mümkün değil. Değişebilirliği kontrol etmenin bir yolu hash, en azından yerleşik nesneler için çalışıyor olmasıdır. hash(1) hash('a') hash((1, 2)) hash(True)tüm işler ve hash([]) hash({}) hash({1, 2})hepsi çalışmıyor.
noktalı virgül

@semicolon Kullanıcı tanımlı sınıflar hash()için __hash__(), kullanıcı tanımlı sınıflar genellikle değiştirilebilir olsa da , nesne bir yöntem tanımlarsa çalışır .
augurar

1
@augurar Evet demek istiyorum, ama Python'daki hiçbir şey hiçbir şeyi garanti etmeyecektir, çünkü Python'un gerçek statik yazımı veya resmi garantisi yoktur. Ancak hashyöntem hala oldukça iyi bir yöntemdir, çünkü değişebilir nesnelerin genellikle bir __hash__()yöntemi olmamalıdır , çünkü bunları sözlükte anahtar yapmak sadece tehlikelidir.
noktalı virgül

1
@augurar ve noktalı virgül (ya da biliyorlarsa diğerleri): __hash __ () çözümü ... özel bir sınıfın yaratıcısı orada olması için onu eklemek zorunda mı? Eğer öyleyse, kural varsa, nesne değişmez olmalıdır; mevcut değilse, içerik oluşturucunun kapalı olması durumunda yalnızca bırakılmış olabileceğini söyleyemeyiz.
TMWP
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.