2012-02-01 33 views
62

Sự hiểu biết của tôi là các chuỗi Python không thay đổi được.Không phải là chuỗi Python không thay đổi? Vậy tại sao một + "" + b hoạt động?

Tôi đã thử các mã sau:

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

nên không Python đã ngăn chặn việc chuyển nhượng? Tôi có thể thiếu một cái gì đó.

Bất kỳ ý tưởng nào?

+34

Chuỗi chính nó là bất biến nhưng nhãn có thể thay đổi. – mitch

+4

Việc gán một giá trị mới cho biến hiện tại là hoàn toàn hợp lệ. Python không có hằng số. Điều này độc lập với khả năng biến đổi loại dữ liệu. –

+5

Bạn có thể muốn xem xét hàm 'id()'. 'a' sẽ có một id khác trước và sau khi gán, chỉ ra rằng nó đang trỏ vào các đối tượng khác nhau. Tương tự như vậy với mã như 'b = a' bạn sẽ thấy rằng' a' và 'b' sẽ có cùng id, cho biết chúng đang tham chiếu cùng một đối tượng. – DRH

Trả lời

118

Đầu tiên a chỉ vào chuỗi "Chó". Sau đó, bạn đã thay đổi biến a để trỏ vào chuỗi mới "Chó ăn xử lý". Bạn đã không thực sự thay đổi chuỗi "Dog". Các chuỗi không thay đổi, các biến có thể trỏ đến bất kỳ thứ gì chúng muốn.

+12

Thậm chí còn thuyết phục hơn khi thử một thứ gì đó như x = 'abc'; x [1] = 'x' trong Python repl – xpmatteo

+0

Nếu bạn muốn hiểu nội bộ hơn một chút, hãy xem câu trả lời của tôi. https://stackoverflow.com/a/40702094/117471 –

38

Chính các đối tượng chuỗi là không thay đổi.

Biến, a, trỏ đến chuỗi, có thể thay đổi.

xem xét:

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. 
+0

@jason thử cùng loại hoạt động với danh sách (có thể thay đổi) để thấy sự khác biệt a.append (3) tương ứng với a = a + "Foo" – jimifiki

+1

@jimifiki 'a.append (3)' ** không ** giống như 'a = a + 3'. Nó không phải là 'a + = 3' (bổ sung tại chỗ tương đương với' .extend', không phải '.append'). – delnan

+0

@delnan và như vậy, cái gì? Để hiển thị các chuỗi và danh sách hoạt động khác nhau, bạn có thể giả định rằng a = a + "Foo" giống như a.append (cái gì đó). Trong mọi trường hợp, nó không giống nhau. Chắc chắn. Bạn có hạnh phúc hơn khi đọc a.extend ([something]) thay vì a.append (cái gì đó)? Tôi không thấy sự khác biệt lớn trong ngữ cảnh này. Nhưng có lẽ tôi đang thiếu một cái gì đó. Thruth phụ thuộc vào ngữ cảnh – jimifiki

11

Một biến chỉ là một nhãn trỏ đến một đối tượng. Đối tượng là không thay đổi, nhưng bạn có thể làm cho điểm nhãn thành một đối tượng hoàn toàn khác nếu bạn muốn.

3

Chuỗi Python không thay đổi được. Tuy nhiên, a không phải là một chuỗi: đó là một biến có giá trị chuỗi. Bạn không thể thay đổi chuỗi, nhưng có thể thay đổi giá trị của biến thành chuỗi mới.

5

Có sự khác biệt giữa dữ liệu và nhãn được liên kết với. Ví dụ khi bạn làm

a = "dog" 

dữ liệu "dog" được tạo ra và đặt dưới nhãn a. Nhãn có thể thay đổi nhưng những gì có trong bộ nhớ thì không. Các dữ liệu "dog" vẫn sẽ tồn tại trong bộ nhớ (cho đến khi thu gom rác xóa nó) sau khi bạn làm

a = "cat" 

Trong programm bạn a bây giờ^^ điểm để "cat" nhưng chuỗi "dog" vẫn không thay đổi.

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

Tuyên bố a = a + " " + b + " " + c có thể được chia nhỏ dựa trên con trỏ.

a + " " cho tôi biết số a trỏ đến, không thể thay đổi và thêm " " vào bộ làm việc hiện tại của tôi.

bộ nhớ:

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

+ b nói cho tôi những gì b điểm đến, mà không thể thay đổi, và thêm nó vào hiện tại làm việc thiết lập. bộ nhớ

:

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

+ " " + c nói thêm " " để các thiết lập hiện.Sau đó, hãy cho tôi những gì c điểm để không thể thay đổi và thêm nó vào bộ làm việc hiện tại. bộ nhớ:

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

Cuối cùng, a = nói thiết lập con trỏ của tôi để trỏ đến tập kết quả.

bộ nhớ:

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

"Dog" được khai hoang, vì không có nhiều gợi ý kết nối với nó là đoạn bộ nhớ. Chúng tôi không bao giờ sửa đổi phần bộ nhớ "Dog" cư trú, đó là những gì có nghĩa là không thay đổi. Tuy nhiên, chúng tôi có thể thay đổi nhãn nào, nếu có, trỏ đến phần đó của bộ nhớ.

23

Biến a đang trỏ vào đối tượng "Chó". Tốt nhất là hãy suy nghĩ về biến trong Python dưới dạng thẻ. Bạn có thể di chuyển thẻ đến các đối tượng khác nhau mà bạn đã làm khi bạn thay đổi a = "dog" thành a = "dog eats treats".

Tuy nhiên, bất biến đề cập đến đối tượng, không phải thẻ.


Nếu bạn đã cố gắng để làm cho a[1] = 'z'"dog" vào "dzg", bạn sẽ nhận được lỗi:

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

vì dây không hỗ trợ giao hàng, do đó họ là không thay đổi.

+0

Điều này rõ ràng hơn so với những người khác! –

0

Tóm tắt:

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

Không bất biến:

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

Immutable:

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

Đây là một lỗi trong Python 3 vì nó là không thay đổi. Và không phải là lỗi trong Python 2 vì rõ ràng nó không phải là bất biến.

11

Điều gì đó chỉ có thể thay đổi khi chúng tôi có thể thay đổi các giá trị được giữ trong vị trí bộ nhớ mà không thay đổi chính vị trí bộ nhớ.

Bí quyết là: Nếu bạn thấy rằng vị trí bộ nhớ trước và sau khi thay đổi giống nhau, nó có thể thay đổi.

Ví dụ: danh sách có thể thay đổi. Làm sao?

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

Chuỗi không thay đổi. Làm thế nào để chúng tôi chứng minh điều đó?

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

chúng tôi nhận

TypeError: 'str' object does not support item assignment

Vì vậy, chúng tôi không đột biến chuỗi. Nó có nghĩa là một chuỗi là bất biến.

Khi bạn chỉ định lại, bạn thay đổi biến để trỏ đến một vị trí mới. Ở đây bạn chưa tắt chuỗi, nhưng biến đổi chính biến đó. Sau đây là những gì bạn đang làm.

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

id trước và sau khi giao lại là khác nhau, vì vậy nó điều này chứng tỏ rằng bạn đang thực sự không biến đổi, nhưng chỉ biến đến vị trí mới. Mà không phải là đột biến chuỗi đó, nhưng biến đổi biến đó.

1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

Bất biến, không phải là nó ?!

Phần thay đổi biến đã được thảo luận.

+0

Điều này không chứng minh hoặc loại bỏ tính đột biến của chuỗi python, chỉ cần phương thức 'replace()' trả về một chuỗi mới. –

4

xem xét:

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

Chú ý rằng vị trí bộ nhớ hex không thay đổi khi tôi được lưu trữ cùng giá trị trong biến hai lần. Nó đã thay đổi khi tôi lưu trữ một giá trị khác. Chuỗi là bất biến. Không phải vì cuồng nhiệt, mà bởi vì bạn trả tiền phạt hiệu suất của việc tạo ra một đối tượng mới trong bộ nhớ. Biến số a chỉ là nhãn trỏ đến địa chỉ bộ nhớ đó. Nó có thể được thay đổi để trỏ đến bất cứ điều gì.

2

Biến thể trỏ đến bất cứ nơi nào họ muốn .. lỗi sẽ được ném nếu bạn làm như sau:

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

Xem xét bổ sung này để dụ bạ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 

Một trong những chính xác hơn giải thích tôi tìm thấy trong blog là:

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.

Eg:

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

When we later say some_guy = 'George', the string object containing 'Fred' is unaffected. We've just changed the binding of the name some_guy. We haven't, however, changed either the 'Fred' or 'George' string objects. As far as we're concerned, they may live on indefinitely.

liên kết đến blog: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/

0

Bạn có thể làm cho một mảng NumPy bất biến và sử dụng các yếu tố đầu tiên:

numpyarrayname[0] = "write once" 

thì:

numpyarrayname.setflags(write=False) 

hoặc

numpyarrayname.flags.writeable = False 
Các vấn đề liên quan