不変の型は何かについて混乱しています。 float
オブジェクトは不変であると考えられています。私の本のこのタイプの例では、
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
これはクラス構造/階層のために不変であると考えられますか?これはfloat
がクラスの最上位にあることを意味し、それ自身のメソッド呼び出しです。このタイプの例に似ています(私の本ではdict
は可変であると言っていますが)。
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
このタイプの例では、変更可能なものがクラス内にメソッドを持ちます。
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
また、最後のclass(SortedKeyDict_a)
については、このタイプのsetを渡すと、次のようになります。
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
example
メソッドを呼び出さずに、辞書を返します。 __new__
を含むSortedKeyDict
は、エラーとしてフラグを立てます。 __new__
を使用してRoundFloat
クラスに整数を渡してみましたが、エラーは発生しませんでした。
何?フロートは不変ですか?しかしできない
x = 5.0
x += 7.0
print x # 12.0
あの "mut" xですか?
さて、あなたは文字列が不変であることに同意しますか?しかし、あなたは同じことをすることができます。
s = 'foo'
s += 'bar'
print s # foobar
変数の値は変わりますが、変数の参照先を変えることで変わります。可変型はそのように変更することができ、それはまた "その場で"変更することができます。
これが違いです。
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
具体例
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]
Pythonはそのすべてのデータをオブジェクトとして表していることを理解しておく必要があります。リストや辞書など、これらのオブジェクトの中には変更可能なものがあります。つまり、IDを変更せずにコンテンツを変更できるということです。整数、浮動小数点数、文字列、タプルなどの他のオブジェクトは変更できないオブジェクトです。それを理解するための簡単な方法は、オブジェクトIDを見ればわかります。
その下には不変の文字列があります。内容を変更することはできません。変更しようとするとTypeError
が発生します。また、新しいコンテンツを割り当てると、コンテンツが変更される代わりに新しいオブジェクトが作成されます。
>>> 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
あなたはそれをリストで行うことができ、それはオブジェクトのアイデンティティを変えないでしょう
>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0]
1
>>> i[0] = 7
>>> id(i)
2146718700
Pythonのデータモデルについてもっと読むには、Python言語リファレンスを見てください。
一般的な不変型
int()
、float()
、complex()
str()
、Tuple()
、frozenset()
、bytes()
一般的な可変型(他のほとんどすべて):
list()
、bytearray()
set()
dict()
型が可変かどうかを素早くテストするための1つのトリックは、id()
組み込み関数を使うことです。
整数を使用した例
>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)
リストで使う、
>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
まず、クラスにメソッドがあるかどうか、またはクラス構造が何であるかは、可変性とは関係ありません。
int
sおよびfloat
sは、不変です。私が行った場合
a = 1
a += 5
名前のa
は、メモリ内の最初の行の1
を指します。 2行目では、1
を検索し、5
を追加し、6
を取得してから、メモリ内の6
をa
にポイントします。 t 変更1
を6
に変更します。同じロジックが、他のimmutableタイプを使用して、次の例に適用されます。
b = 'some string'
b += 'some other string'
c = ('some', 'Tuple')
c += ('some', 'other', 'Tuple')
mutableタイプの場合、実際にはメモリに保存されている値を変更するを実行できます。と:
d = [1, 2, 3]
メモリ内の1
、2
、および3
の場所のリストを作成しました。もしそうなら
e = d
私はe
を同じlist
d
を指すように指しています。その後、私は次のことができます:
e += [4, 5]
また、e
とd
の両方が指すリストは、メモリ内の4
と5
の場所も含むように更新されます。
immutableタイプに戻ってTuple
でそれを行うと:
f = (1, 2, 3)
g = f
g += (4, 5)
f
はまだ元のTuple
を指しているだけです-まったく新しいg
でTuple
を指しています=。
さて、あなたの例で
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
あなたが通る場所
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
(これはTuple
のtuples
です)val
として、Tuple
には.clear()
メソッドがないためエラーが発生します。 d dict(d)
をval
として渡さなければ動作しません。その場合、結果として空のSortedKeyDict
を取得します。
他の言語(RubyのようなPythonに非常に似ている言語を除く)からPythonにアクセスして、その他の言語の観点から理解することを要求する場合、通常、人々は混乱します。
>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!
Pythonでは、割り当てはPythonの突然変異ではありません。
C++では、a = 2
と記述する場合、a
に格納されているオブジェクトを変更するa.operator=(2)
を呼び出します。 (そしてwasがa
にオブジェクトが保存されていない場合、それはエラーです。)
Pythonでは、a = 2
はa
に保存されたものには何もしません。これは、代わりに2
がa
に保存されることを意味します。 (そしてwasにオブジェクトがa
に保存されていない場合、それで問題ありません。)
最終的に、これはさらに深い区別の一部です。
C++などの言語の変数は、メモリ内の型指定された場所です。 a
がint
である場合、コンパイラがint
として解釈されるはずであることがわかっている4バイトであることを意味します。したがって、a = 2
を実行すると、4バイトのメモリに保存されている内容が0, 0, 0, 1
から0, 0, 0, 2
に変更されます。別の場所に別のint変数がある場合、独自の4バイトがあります。
Pythonのような言語の変数は、独自の寿命を持つオブジェクトの名前です。番号1
のオブジェクトと、番号2
の別のオブジェクトがあります。 a
はint
として表される4バイトのメモリではなく、1
オブジェクトを指す名前にすぎません。 a = 2
が数字の1を数字の2に変えることは意味がありません(これにより、Pythonプログラマーに宇宙の基本的な仕組みを変えるほどの力が与えられます)。代わりにa
が1
オブジェクトを忘れて、代わりに2
オブジェクトを指すようにします。
それでは、割り当てが突然変異ではない場合、is突然変異とは何ですか?
a.append(b)
のような、変化するように文書化されているメソッドを呼び出す。 (これらのメソッドはほとんど常にNone
を返すことに注意してください)。不変型にはそのようなメソッドはありませんが、通常、可変型にはあります。a.spam = b
やa[0] = b
などのオブジェクトの一部への割り当て。不変型は属性または要素への割り当てを許可しませんが、可変型は通常どちらか一方を許可します。a += b
などの拡張割り当てを使用することもあれば、そうでないこともあります。可変型は通常、値を変更します。不変型は決して実行せず、代わりにコピーを提供します(a + b
を計算してから、結果をa
に割り当てます)。しかし、割り当てが突然変異ではない場合、オブジェクトの突然変異の一部にどのように割り当てますか?それはトリッキーになるところです。 a[0] = b
はnot変異a[0]
(C++とは異なり)、しかしdoes変異a
(C++とは異なり、間接的に) 。
これらすべてが、おそらくあなたが慣れている言語の観点からPythonのセマンティクスを入れて、代わりに独自の用語でPythonのセマンティクスを学習することをお勧めする理由ですnot.
オブジェクトが可変かどうかは、そのタイプによって異なります。これは、それが特定のメソッドを持っているかどうかにも依存せず、またクラス階層の構造にも依存しません。
ユーザ定義型(すなわちクラス)は一般に変更可能である。不変型の単純なサブクラスなど、いくつかの例外があります。その他の不変型には、int
、float
、Tuple
、str
などの組み込み型、およびCで実装されたPythonクラスがあります。
Python言語リファレンスの "データモデル"の章 からの一般的な説明:
一部のオブジェクトの値は変わる可能性があります。値が変わる可能性のあるオブジェクトは変更可能であると言われます。一度作成された値が変更不可能なオブジェクトは不変と呼ばれます。
(変更可能なオブジェクトへの参照を含む不変のコンテナオブジェクトの値は、変更可能なオブジェクトの値が変更されると変更される可能性があります。ただし、コンテナは、不変オブジェクトと見なされます。不変の値を持つのと同じ、それはもっと微妙です。)
オブジェクトの可変性はその種類によって決まります。たとえば、数字、文字列、タプルは不変ですが、辞書やリストは不定です。
可変オブジェクト:作成後に変更可能なオブジェクト。
Immutable object:作成後に変更できないオブジェクト.
Pythonでは不変オブジェクトの値を変更しようとしますが、それは新しいオブジェクトを与えます。
これは、可変型のpythonのリストオブジェクトです。
list
Dictionary
Set
bytearray
user defined classes
不変型のPythonのリストオブジェクトは次のとおりです。
int
float
decimal
complex
bool
string
Tuple
range
frozenset
bytes
質問:文字列は不変の型ですか?
答え:はいそうですが、説明できますか?証明1:
a = "Hello"
a +=" World"
print a
出力
"Hello World"
上記の例では、 "Hello"として作成された文字列が、ついに "Hello World"に変更されました。これは文字列が可変型であることを意味します。しかし、そのアイデンティティをチェックし、それが可変タイプであるかどうかをチェックすることはできません。
a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
print "String is Immutable"
出力
String is Immutable
証明2:
a = "Hello World"
a[0] = "M"
出力
TypeError 'str' object does not support item assignment
質問:Tupleは不変型ですか?
答え:はいそれは証明1:
Tuple_a = (1,)
Tuple_a[0] = (2,)
print a
出力
'Tuple' object does not support item assignment
インスタンス化時にそのクラスの各オブジェクトに _その後_ を変更できない固定値がある場合、クラスはimmutableです。
別のWordでは、その変数(name)
の値全体を変更するか、そのままにしてください。
例:
my_string = "Hello world"
my_string[0] = "h"
print my_string
hello worldが動作して印刷されることを期待していましたが、これは次のエラーをスローします。
Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment
インタプリタは言っています: この文字列の最初の文字を変更することはできません
うまく動作させるためにはstring
全体を変更する必要があります。
my_string = "Hello World"
my_string = "hello world"
print my_string #hello world
この表をチェックしてください。
この答えの目的は、あなたが変異/非変異(不変/変異)を扱っているかどうかを判断する方法についての良いアイデアをすべて見つけるための単一の場所を作成することです。突然変異が望ましくなく、この点に関するpythonの振る舞いは他の言語からそれに入ってくるコーダーにとって直感に反すると感じることがあります。
@ mina-gabrielによる便利な投稿によれば:
上記を分析し、@arrakëënによる投稿のある投稿を結合します。
予期せずに変更できないものは何ですか?
何ができますか?
「予想外に」私は他の言語のプログラマーはこの動作を期待しないかもしれないことを意味します(例外またはRuby、そしておそらく他のいくつかの「Pythonのような」言語を除く)。
この議論に追加する:
この動作は、メモリを大量に消費する大規模なデータ構造のコピーを誤ってコードに追加することを防ぐのに役立ちます。しかし、これが望ましくない場合、どうやって回避しますか?
リストでは、簡単な解決策は以下のように新しいものを作ることです。
list2 = list(list1)
他の構造では…解決策はもっとトリックになります。 1つの方法は、要素をループ処理して、それらを新しい空のデータ構造(同じ型)に追加することです。
可変構造体を渡すと、関数は元のものを変更できます。どうやって言うの?
非標準的なアプローチ(役に立つ場合):これはMITライセンスの下で公開されているgithubで見つけました:
カスタムクラスの場合、可変オブジェクトは通常__hash__()
関数を持つべきではないため、@semicolonは__hash__
関数があるかどうかをチェックすることを推奨します。
これは私が今のところこのトピックについてまとめたものです。他のアイデア、修正などは大歓迎です。ありがとう。
それは私には思えますあなたは可変/不変が実際に何を意味するのかという質問と闘っています。だからここに簡単な例です:
最初に私達は根拠の基礎となる基盤が必要です。
仮想オブジェクトとしてプログラムするもの、つまり2進数のシーケンスとしてコンピュータのメモリに保存されるものを考えてください。今はたいていのコンピュータ言語では、これらの2進数を直接扱うことはありませんが、2進数の解釈を使用するようになりました。
例えば。あなたは0x110、0xaf0278297319などのような数字については考えていませんが、代わりに6や "Hello、world"のような文字列について考えています。決してこれらの数字や文字列がコンピュータのメモリ内の2進数の解釈になることはありません。同じことが変数の値にも当てはまります。
一言で言えば:私たちしないでプログラムする実際の値ではなく、実際のバイナリ値の解釈
論理や他の「きちんとしたもの」のために変更されてはならない解釈がありますが、変更される可能性のある解釈があります。たとえば、都市のシミュレーション、つまり多くの仮想オブジェクトがあり、そのうちのいくつかが住宅であるプログラムを考えてみましょう。さて、これらの仮想オブジェクト(家)は変更されるかもしれません、そして、それらはまだ同じ家であると考えられることができますか?もちろん可能です。したがって、それらは変更可能です。「完全に」異なるオブジェクトにならずに変更できます。
整数について考えてみましょう。これらも仮想オブジェクト(コンピュータメモリ内の2進数のシーケンス)です。それで、もし私達がそれらのうちの一つを変えるならば、値を一つずつ増加させるように、それはまだ六ですか?もちろんそうではありません。したがって、どの整数も不変です。
つまり、仮想オブジェクトに何らかの変更が加えられても、それが実際に別の仮想オブジェクトになることを意味する場合は、不変と呼ばれます。
最後に
(1)現実世界でのミュータブルとイミュータブルの経験を特定の言語でのプログラミングと混同しないでください。
どのプログラミング言語にも、どのオブジェクトをミュートにし、どのオブジェクトをミュートにしないかについての定義があります。
そのため、意味の違いを理解しているかもしれませんが、それでも各プログラミング言語の実際の実装を学ぶ必要があります。 ...確かに、6が7になるようにミュートされる言語の目的があるかもしれません。それからこれもまた、パラレルユニバースのシミュレーションのように、かなりクレイジーで面白いものになるでしょう。^^
(2)この解明は確かに科学的なものではありません、それはあなたがミュータブルとイミュータブルの違いを把握するのに役立つことを意味しています。
違いを考える一つの方法:
Pythonの不変オブジェクトへの代入はディープコピーと考えることができますが、可変オブジェクトへの代入は浅いです
最も簡単な答え:
可変変数は、その値がその場で変更される可能性がある変数ですが、不変変数では、値の変更はその場で行われません。不変の変数を変更すると、同じ変数が再構築されます。
例:
>>>x = 5
Xによって参照される値5を作成します
x - > 5
>>>y = x
このステートメントはyにxの5を参照させます。
x -------------> 5 <----------- y
>>>x = x + y
Xが整数(不変型)であるため再構築されました。
ステートメントでは、RHSの式は値10になります。これがLHS(x)に割り当てられると、xは10に再構築されます。
x ---------> 10
y ---------> 5
不変オブジェクトの場合、例えば、代入は新しい値のコピーを作成します。
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)
可変オブジェクトの場合、代入は別の値のコピーを作成しません。例えば、
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