web-dev-qa-db-ja.com

不変タイプと可変タイプ

不変の型は何かについて混乱しています。 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クラスに整数を渡してみましたが、エラーは発生しませんでした。

166
user1027217

何?フロートは不変ですか?しかしできない

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]
218
morningstar

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言語リファレンスを見てください。

175
sebs

一般的な不変型

  1. 番号:int()float()complex()
  2. 不変シーケンス:str()Tuple()frozenset()bytes()

一般的な可変型(他のほとんどすべて):

  1. 可変シーケンス:list()bytearray()
  2. セットタイプ:set()
  3. マッピング型:dict()
  4. クラス、クラスインスタンス
  5. 等.

型が可変かどうかを素早くテストするための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)
99
Pei

まず、クラスにメソッドがあるかどうか、またはクラス構造が何であるかは、可変性とは関係ありません。

intsおよびfloatsは、不変です。私が行った場合

a = 1
a += 5

名前のaは、メモリ内の最初の行の1を指します。 2行目では、1を検索し、5を追加し、6を取得してから、メモリ内の6aにポイントします。 t 変更16に変更します。同じロジックが、他のimmutableタイプを使用して、次の例に適用されます。

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

mutableタイプの場合、実際にはメモリに保存されている値を変更するを実行できます。と:

d = [1, 2, 3]

メモリ内の12、および3の場所のリストを作成しました。もしそうなら

e = d

私はe同じlistdを指すように指しています。その後、私は次のことができます:

e += [4, 5]

また、edの両方が指すリストは、メモリ内の45の場所も含むように更新されます。

immutableタイプに戻ってTupleでそれを行うと:

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

fはまだ元のTupleを指しているだけです-まったく新しいgTupleを指しています=。

さて、あなたの例で

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

あなたが通る場所

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

(これはTupletuplesです)valとして、Tupleには.clear()メソッドがないためエラーが発生します。 d dict(d)valとして渡さなければ動作しません。その場合、結果として空のSortedKeyDictを取得します。

33
agf

他の言語(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)を呼び出します。 (そしてwasaにオブジェクトが保存されていない場合、それはエラーです。)

Pythonでは、a = 2aに保存されたものには何もしません。これは、代わりに2aに保存されることを意味します。 (そしてwasにオブジェクトがaに保存されていない場合、それで問題ありません。)


最終的に、これはさらに深い区別の一部です。

C++などの言語の変数は、メモリ内の型指定された場所です。 aintである場合、コンパイラがintとして解釈されるはずであることがわかっている4バイトであることを意味します。したがって、a = 2を実行すると、4バイトのメモリに保存されている内容が0, 0, 0, 1から0, 0, 0, 2に変更されます。別の場所に別のint変数がある場合、独自の4バイトがあります。

Pythonのような言語の変数は、独自の寿命を持つオブジェクトの名前です。番号1のオブジェクトと、番号2の別のオブジェクトがあります。 aintとして表される4バイトのメモリではなく、1オブジェクトを指す名前にすぎません。 a = 2が数字の1を数字の2に変えることは意味がありません(これにより、Pythonプログラマーに宇宙の基本的な仕組みを変えるほどの力が与えられます)。代わりにa1オブジェクトを忘れて、代わりに2オブジェクトを指すようにします。


それでは、割り当てが突然変異ではない場合、is突然変異とは何ですか?

  • a.append(b)のような、変化するように文書化されているメソッドを呼び出す。 (これらのメソッドはほとんど常にNoneを返すことに注意してください)。不変型にはそのようなメソッドはありませんが、通常、可変型にはあります。
  • a.spam = ba[0] = bなどのオブジェクトの一部への割り当て。不変型は属性または要素への割り当てを許可しませんが、可変型は通常どちらか一方を許可します。
  • a += bなどの拡張割り当てを使用することもあれば、そうでないこともあります。可変型は通常、値を変更します。不変型は決して実行せず、代わりにコピーを提供します(a + bを計算してから、結果をaに割り当てます)。

しかし、割り当てが突然変異ではない場合、オブジェクトの突然変異の一部にどのように割り当てますか?それはトリッキーになるところです。 a[0] = bnot変異a[0](C++とは異なり)、しかしdoes変異a(C++とは異なり、間接的に) 。

これらすべてが、おそらくあなたが慣れている言語の観点からPythonのセマンティクスを入れて、代わりに独自の用語でPythonのセマンティクスを学習することをお勧めする理由ですnot.

20
abarnert

オブジェクトが可変かどうかは、そのタイプによって異なります。これは、それが特定のメソッドを持っているかどうかにも依存せず、またクラス階層の構造にも依存しません。

ユーザ定義型(すなわちクラス)は一般に変更可能である。不変型の単純なサブクラスなど、いくつかの例外があります。その他の不変型には、intfloatTuplestrなどの組み込み型、およびCで実装されたPythonクラスがあります。

Python言語リファレンスの "データモデル"の章 からの一般的な説明:

一部のオブジェクトの値は変わる可能性があります。値が変わる可能性のあるオブジェクトは変更可能であると言われます。一度作成された値が変更不可能なオブジェクトは不変と呼ばれます。

(変更可能なオブジェクトへの参照を含む不変のコンテナオブジェクトの値は、変更可能なオブジェクトの値が変更されると変更される可能性があります。ただし、コンテナは、不変オブジェクトと見なされます。不変の値を持つのと同じ、それはもっと微妙です。)

オブジェクトの可変性はその種類によって決まります。たとえば、数字、文字列、タプルは不変ですが、辞書やリストは不定です。

18
taleinat

可変オブジェクトと不変オブジェクトの違い

定義

可変オブジェクト:作成後に変更可能なオブジェクト。
Immutable object:作成後に変更できないオブジェクト.

Pythonでは不変オブジェクトの値を変更しようとしますが、それは新しいオブジェクトを与えます。

可変オブジェクト

これは、可変型のpythonのリストオブジェクトです。

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

不変オブジェクト

不変型のPythonのリストオブジェクトは次のとおりです。

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. Tuple
  8. range
  9. frozenset
  10. 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
11
anand tripathi

インスタンス化時にそのクラスの各オブジェクトに _その後_ を変更できない固定値がある場合、クラスは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

この表をチェックしてください。

enter image description here

source

4
Mina Gabriel

この答えの目的は、あなたが変異/非変異(不変/変異)を扱っているかどうかを判断する方法についての良いアイデアをすべて見つけるための単一の場所を作成することです。突然変異が望ましくなく、この点に関するpythonの振る舞いは他の言語からそれに入ってくるコーダーにとって直感に反すると感じることがあります。

@ mina-gabrielによる便利な投稿によれば:

上記を分析し、@arrakëënによる投稿のある投稿を結合します。

予期せずに変更できないものは何ですか?

  • スカラー(単一の値を格納する変数型)は予期せずには変更されません
    • 数値の例:int()、float()、complex()
  • いくつかの "可変配列"があります:
    • str()、Tuple()、frozenset()、bytes()

何ができますか?

  • オブジェクトのようなリスト(リスト、辞書、セット、bytearray())
  • ここへの投稿ではクラスとクラスインスタンスについても述べていますが、これはクラスの継承元や構築方法によって異なります。

「予想外に」私は他の言語のプログラマーはこの動作を期待しないかもしれないことを意味します(例外またはRuby、そしておそらく他のいくつかの「Pythonのような」言語を除く)。

この議論に追加する:

この動作は、メモリを大量に消費する大規模なデータ構造のコピーを誤ってコードに追加することを防ぐのに役立ちます。しかし、これが望ましくない場合、どうやって回避しますか?

リストでは、簡単な解決策は以下のように新しいものを作ることです。

list2 = list(list1)

他の構造では…解決策はもっとトリックになります。 1つの方法は、要素をループ処理して、それらを新しい空のデータ構造(同じ型)に追加することです。

可変構造体を渡すと、関数は元のものを変更できます。どうやって言うの?

  • このスレッドの他のコメントにいくつかのテストがありますが、それからこれらのテストが完全な証拠ではないことを示すコメントがあります
  • object.function()は元のオブジェクトのメソッドですが、これらのうちの一部のみが変更されています。彼らが何も返さなければ、彼らはおそらくそうするでしょう。 .append()は、名前を与えられてテストすることなく変更することを期待するでしょう。 .union()はset1.union(set2)の和集合を返し、変更はしません。疑わしい場合は、関数で戻り値を確認できます。 return = Noneの場合、変化しません。
  • 場合によっては、sorted()が回避策になることがあります。それはオリジナルのソートされたバージョンを返すので、それはあなたが他の方法でオリジナルの作業を始める前にあなたが突然変異していないコピーを保存することを可能にします。ただし、このオプションでは、元の要素の順序を気にしなくてもよいと想定しています(そうした場合は、別の方法を見つける必要があります)。対照的に、.sort()はオリジナルを変更します(ご想像のとおり)。

非標準的なアプローチ(役に立つ場合):これはMITライセンスの下で公開されているgithubで見つけました:

  • githubリポジトリの下に:tobgu名前付き:pyrsistent
  • それが何であるか:Python永続データ構造コードは、突然変異が望ましくないときにコアデータ構造の代わりに使用されるように書かれて

カスタムクラスの場合、可変オブジェクトは通常__hash__()関数を持つべきではないため、@semicolonは__hash__関数があるかどうかをチェックすることを推奨します。

これは私が今のところこのトピックについてまとめたものです。他のアイデア、修正などは大歓迎です。ありがとう。

4
TMWP

それは私には思えますあなたは可変/不変が実際に何を意味するのかという質問と闘っています。だからここに簡単な例です:

最初に私達は根拠の基礎となる基盤が必要です。

仮想オブジェクトとしてプログラムするもの、つまり2進数のシーケンスとしてコンピュータのメモリに保存されるものを考えてください。今はたいていのコンピュータ言語では、これらの2進数を直接扱うことはありませんが、2進数の解釈を使用するようになりました。

例えば。あなたは0x110、0xaf0278297319などのような数字については考えていませんが、代わりに6や "Hello、world"のような文字列について考えています。決してこれらの数字や文字列がコンピュータのメモリ内の2進数の解釈になることはありません。同じことが変数の値にも当てはまります。

一言で言えば:私たちしないでプログラムする実際の値ではなく、実際のバイナリ値の解釈

論理や他の「きちんとしたもの」のために変更されてはならない解釈がありますが、変更される可能性のある解釈があります。たとえば、都市のシミュレーション、つまり多くの仮想オブジェクトがあり、そのうちのいくつかが住宅であるプログラムを考えてみましょう。さて、これらの仮想オブジェクト(家)は変更されるかもしれません、そして、それらはまだ同じ家であると考えられることができますか?もちろん可能です。したがって、それらは変更可能です。「完全に」異なるオブジェクトにならずに変更できます。

整数について考えてみましょう。これらも仮想オブジェクト(コンピュータメモリ内の2進数のシーケンス)です。それで、もし私達がそれらのうちの一つを変えるならば、値を一つずつ増加させるように、それはまだ六ですか?もちろんそうではありません。したがって、どの整数も不変です。

つまり、仮想オブジェクトに何らかの変更が加えられても、それが実際に別の仮想オブジェクトになることを意味する場合は、不変と呼ばれます。

最後に

(1)現実世界でのミュータブルとイミュータブルの経験を特定の言語でのプログラミングと混同しないでください。

どのプログラミング言語にも、どのオブジェクトをミュートにし、どのオブジェクトをミュートにしないかについての定義があります。

そのため、意味の違いを理解しているかもしれませんが、それでも各プログラミング言語の実際の実装を学ぶ必要があります。 ...確かに、6が7になるようにミュートされる言語の目的があるかもしれません。それからこれもまた、パラレルユニバースのシミュレーションのように、かなりクレイジーで面白いものになるでしょう。^^

(2)この解明は確かに科学的なものではありません、それはあなたがミュータブルとイミュータブルの違いを把握するのに役立つことを意味しています。

4
Markus Alpers

違いを考える一つの方法:

Pythonの不変オブジェクトへの代入はディープコピーと考えることができますが、可変オブジェクトへの代入は浅いです

3
Aditya Sihag

最も簡単な答え:

可変変数は、その値がその場で変更される可能性がある変数ですが、不変変数では、値の変更はその場で行われません。不変の変数を変更すると、同じ変数が再構築されます。

例:

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

2
Amit Upadhyay

不変オブジェクトの場合、例えば、代入は新しい値のコピーを作成します。

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
0
Ravi Gurnatham