私の理解では、Python文字列は不変です。
私は次のコードを試しました:
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は割り当てを妨げてはなりませんか?私はおそらく何かが欠けています。
何か案が?
最初のa
は文字列「Dog」を指しています。次に、変数a
を変更して、新しい文字列「Dog eats treats」を指すようにしました。実際に文字列「Dog」を変更していません。文字列は不変であり、変数は必要なものを指すことができます。
文字列オブジェクト自体は不変です。
文字列を指す変数a
は可変です。
考慮してください:
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.
変数aは、オブジェクト「犬」を指しています。 Pythonの変数をタグと考えるのが最善です。 a = "dog"
をa = "dog eats treats"
に変更したときと同じように、タグを別のオブジェクトに移動できます。
ただし、不変性とは、タグではなくオブジェクトを指します。
a[1] = 'z'
を"dog"
にして"dzg"
にしようとすると、エラーが発生します。
TypeError: 'str' object does not support item assignment"
文字列はアイテムの割り当てをサポートしていないため、不変です。
メモリロケーション自体を変更せずに、メモリロケーションに保持されている値を変更できる場合にのみ、何かが可変になります。
秘isは次のとおりです。変更前と変更後のメモリ位置が同じであることがわかった場合、それは変更可能です。
たとえば、リストは変更可能です。どうやって?
>> 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.
文字列は不変です。どうやって証明しますか?
> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------
我々が得る
そのため、文字列の変更に失敗しました。文字列が不変であることを意味します。
再割り当てでは、新しい場所自体を指すように変数を変更します。ここでは、文字列を変更していませんが、変数自体を変更しています。以下はあなたがしていることです。
>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808
id
は再割り当ての前後で異なります。したがって、実際には変更ではなく、変数を新しい場所に向けていることがわかります。これはその文字列を変更するのではなく、その変数を変更することです。
変数は、オブジェクトを指す単なるラベルです。オブジェクトは不変ですが、必要に応じてラベルを完全に異なるオブジェクトにポイントすることができます。
考慮してください:
>>> 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>
同じ値を変数に2回保存しても、16進メモリの場所は変わらなかったことに注意してください。別の値を保存すると変更されました。文字列は不変です。熱心さのためではなく、メモリに新しいオブジェクトを作成することでパフォーマンスが低下するためです。変数a
は、そのメモリアドレスを指す単なるラベルです。何でも指すように変更できます。
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
ステートメントa = a + " " + b + " " + c
は、ポインターに基づいて分類できます。
a + " "
は、変更できないa
が指すものを教えてくれ、現在のワーキングセットに" "
を追加すると言います。
メモリ:
working_set = "Dog "
a = "Dog"
b = "eats"
c = "treats"
+ b
は、b
が指すもの(変更不可)を教えて、現在のワーキングセットに追加します。
メモリ:
working_set = "Dog eats"
a = "Dog"
b = "eats"
c = "treats"
+ " " + c
は、" "
を現在のセットに追加することを示します。次に、c
が指すもの(変更不可)を指定して、現在のワーキングセットに追加します。メモリ:
working_set = "Dog eats treats"
a = "Dog"
b = "eats"
c = "treats"
最後に、a =
は、結果セットを指すようにポインターを設定すると言います。
メモリ:
a = "Dog eats treats"
b = "eats"
c = "treats"
"Dog"
は、メモリのチャンクに接続するポインターがなくなるため、回収されます。 "Dog"
が常駐するメモリセクションを変更したことはありません。これは不変を意味します。ただし、メモリのそのセクションを指すラベルがある場合は、そのラベルを変更できます。
データとそれが関連付けられているラベルには違いがあります。たとえば
a = "dog"
データ"dog"
が作成され、ラベルa
の下に配置されます。ラベルは変更できますが、メモリにあるものは変更されません。データ"dog"
は、ガベージコレクターが削除するまでメモリに残っています。
a = "cat"
プログラムでa
が指す^^ "cat"
が、文字列"dog"
は変更されていません。
Python文字列は不変です。ただし、a
は文字列ではなく、文字列値を持つ変数です。文字列を変更することはできませんが、変数の値を新しい文字列に変更することはできます。
Python文字列オブジェクトは不変です。例:
>>> 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'
この例では、aに異なる値を割り当てても変更されないことがわかります。新しいオブジェクトが作成されます。
そして変更することはできません。例:
>>> a[0] = 'c'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
**TypeError**: 'str' object does not support item assignment
エラーが発生します。
変数は任意の場所を指すことができます。次の操作を行うと、エラーがスローされます。
a = "dog"
print a #dog
a[1] = "g" #ERROR!!!!!! STRINGS ARE IMMUTABLE
あなたの例にこの追加を検討してください
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
ブログで見つけたより正確な説明の1つは次のとおりです。
Pythonでは、(ほぼ)すべてがオブジェクトです。 Pythonで一般に「変数」と呼ぶものは、より適切に名前と呼ばれます。同様に、「割り当て」は実際にはオブジェクトへの名前のバインディングです。各バインディングには、その可視性を定義するスコープ(通常は名前の由来するブロック)があります。
例えば:
some_guy = 'Fred'
# ...
some_guy = 'George'
後でsome_guy = 'George'と言うとき、 'Fred'を含む文字列オブジェクトは影響を受けません。 some_guyという名前のバインディングを変更しました。ただし、「Fred」または「George」の文字列オブジェクトは変更していません。私たちに関する限り、彼らは無期限に生き続けるかもしれません。
ブログへのリンク: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/
「mutable」は文字列の内容を変更できることを意味し、「immutable」は余分な文字列を追加できないことを意味します。
>>> a = 'dogs'
>>> a.replace('dogs', 'dogs eat treats')
'dogs eat treats'
>>> print a
'dogs'
不変ですね。
変数変更部分についてはすでに説明しました。
上記の回答にもう少し追加します。
変数のid
は、再割り当て時に変更されます。
>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776
つまり、変数a
を変更して、新しい文字列を指すようにしました。 twostring
(str)オブジェクトが存在します:
'initial_string'
with id
= 139982120425648
そして
'new_string'
with id
= 139982120425776
以下のコードを検討してください。
>>> b = 'intitial_string'
>>> id(b)
139982120425648
現在、b
は'initial_string'
を指し、id
は再割り当て前と同じa
を持っています。
したがって、'intial_string'
は変更されていません。
組み込み関数id()
は、オブジェクトのIDを整数として返します。この整数は通常、メモリ内のオブジェクトの位置に対応します。
\>>a='dog'
\>>print(id(a))
139831803293008
\>>a=a+'cat'
\>>print(id(a))
139831803293120
文字列オブジェクトはpythonで不変であるため、最初に 'a'は139831803293008のメモリロケーションに格納されます。参照を変更して再割り当てしようとすると、参照が削除され、新しいメモリロケーションへのポインタになります(139831803293120 )。
Numpy配列を不変にし、最初の要素を使用できます:
numpyarrayname[0] = "write once"
その後:
numpyarrayname.setflags(write=False)
または
numpyarrayname.flags.writeable = False
要約:
a = 3
b = a
a = 3+2
print b
# 5
不変ではない:
a = 'OOP'
b = a
a = 'p'+a
print b
# OOP
不変:
a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
b[i] = a[i]+1
これは不変であるため、Python 3のエラーです。 Python 2のエラーではありません。明らかに不変ではないからです。