質問

このことを考慮 コード:

a = {...} # a is an dict with arbitrary contents
b = a.copy()
  1. Dictsのキーと値では、変動はどのような役割を果たしますか?
  2. 一方のdictのキーまたは値の変更が他方に反映されないことを確認するにはどうすればよいですか?
  3. これはハッシュアブルとどのように関係していますか 制約 DICTキーの?
  4. Python 2.xとPython 3.xの間で動作に違いはありますか?

Pythonでタイプが可変であるかどうかを確認するにはどうすればよいですか?

役に立ちましたか?

解決

1)キーが可変であってはなりません、 そうでもなければ ハッシュ可能であるが可変性のあるユーザー定義のクラスがあります。それがあなたに強制されているすべてです。 ただし、HashableのMutableオブジェクトをDICTキーとして使用するのは悪い考えかもしれません。

2)2つのディクト間で値を共有しないことにより。キーを共有しても構いません。なぜなら、キーは不変である必要があるからです。辞書をコピーします copy モジュール感覚は間違いなく安全です。ここでDICTコンストラクターを呼ぶこともできます: b = dict(a). 。不変の値を使用することもできます。

3)すべての内蔵の不変のタイプはハッシュ可能です。すべての組み込みの可変タイプはハッシュ可能ではありません。オブジェクトがハッシュ可能であるためには、たとえ変異しても、生涯にわたって同じハッシュを持つ必要があります。

4)私が知っているわけではありません。 2.xについて説明しています。

タイプは不変でない場合に可変です。組み込みの不変のタイプの場合、タイプは不変です。 str, int, long, bool, float, tuple, 、そしておそらく私が忘れている他のいくつか。ユーザー定義の型は常に可変です。

オブジェクトは不変でない場合に変換可能です。オブジェクトは、再帰的に、不変の型式サブオブジェクトのみで構成されている場合、不変です。したがって、リストのタプルは可変です。タプルの要素を交換することはできませんが、リストインターフェイスを介してそれらを変更して、データ全体を変更できます。

他のヒント

Pythonの言語レベルでは、実際には可変性や不変性などのものはありません。一部のオブジェクトは、それらを変更する方法を提供しません(たとえば、文字列やタプル)、そしてそうです 効果的に 不変ですが、それは純粋に概念的です。言語レベルでは、これを示すプロパティはありません。コードもPython自体も示すものではありません。

不変性は、実際にはthictsに関連していません。可変値をキーとして使用することはまったく問題ありません。重要なのは比較とハッシュ:オブジェクトは常にそれ自体と等しいままでなければなりません。例えば:

class example(object):
    def __init__(self, a):
        self.value = a
    def __eq__(self, rhs):
        return self.value == rhs.value
    def __hash__(self):
        return hash(self.value)

a = example(1)
d = {a: "first"}
a.data = 2
print d[example(1)]

ここ、 exampleいいえ 不変;私たちはそれを修正しています a.data = 2. 。しかし、私たちはそれを問題なくハッシュの鍵として使用しています。なんで?私たちが変化しているプロパティは、平等に影響を与えません。ハッシュは変更されておらず、 example(1) 常に等しい example(1), 、他のプロパティを無視します。

これの最も一般的な用途は、キャッシュとメモ化です。プロパティをキャッシュするかどうかは、オブジェクトを論理的に変更することはなく、通常は平等に影響を与えません。

(ここでやめます。一度に5つの質問をしないでください。)

モジュールには、ミュータブセイク、ミューテセット、ミュータブルマッピングがあります コレクション. 。これは、事前のタイプの可変性を確認するために使用できます。

issubclass(TYPE, (MutableSequence, MutableSet, MutableMapping))

これをユーザー定義のタイプで使用したい場合、タイプはそのうちの1つから継承されるか、仮想サブクラスとして登録する必要があります。

class x(MutableSequence):
    ...

また

class x:
    ...

abc.ABCMeta.register(MutableSequence,x)

本当にありません 保証 ハッシュ可能なタイプも不変ですが、少なくとも、正しく実装していること __hash__ そのタイプは、それ自体のハッシュに関して、そして平等に関して不変であることが必要です。これは特定の方法で強制されません。

しかし、私たちはすべて大人です。実装するのは賢明ではありません __hash__ あなたが本当にそれを意味していない限り。大まかに言えば、これは、タイプを実際に辞書キーとして使用できる場合、その方法で使用することを意図していると言うことになります。

あなたが何かを探しているなら お気に入り Dictだけでなく、不変でもあります namedtuple 標準的なライブラリにあるものからの最善の策かもしれません。確かにそれはあまり良い近似ではありませんが、それは始まりです。

  1. dict キー ハッシュ可能でなければなりません、それは彼らが不変を持っていることを意味します ハッシュ 価値。 dict 可変性がある場合とそうでない場合があります。ただし、それらが可変性がある場合、これはあなたの2番目の質問に影響します。

  2. 「キーへの変更」は、2つのdictの間で反映されません。文字列などの不変の値の変更も反映されません。オブジェクトがIDによって保存されているため、ユーザー定義のクラスなどの可変オブジェクトの変更が反映されます(IE参照)。

    class T(object):
      def __init__(self, v):
        self.v = v
    
    
    t1 = T(5)
    
    
    d1 = {'a': t1}
    d2 = d1.copy()
    
    
    d2['a'].v = 7
    d1['a'].v   # = 7
    
    
    d2['a'] = T(2)
    d2['a'].v   # = 2
    d1['a'].v   # = 7
    
    
    import copy
    d3 = copy.deepcopy(d2) # perform a "deep copy"
    d3['a'].v = 12
    d3['a'].v   # = 12
    d2['a'].v   # = 2
    
  3. これは最初の2つの答えで説明されていると思います。

  4. この点で私が知っているわけではありません。

いくつかの追加の考え:

の行動を理解するために知っておくべき2つの主なことがあります キー: :キーはそうでなければなりません ハッシュ可能 (それは彼らが実装することを意味します object.__hash__(self))そして彼らはまた「同等の」ものでなければなりません(つまり、彼らはのようなものを実装することを意味します object.__cmp__(self))。ドキュメントからの重要なテイクアウト:デフォルトでは、ユーザー定義のオブジェクトのハッシュ関数が返されます id().

この例を考えてみましょう。

class K(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y

k1 = K(1, 2)
d1 = {k1: 3}
d1[k1] # outputs 3
k1.x = 5
d1[k1] # KeyError!  The key's hash has changed!
k2 = K(2, 1)
d1[k2] # KeyError!  The key's hash is right, but the keys aren't equal.
k1.x = 1
d1[k1] # outputs 3

class NewK(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y
  def __cmp__(self, other):
     return self.x - other.x

nk1 = NewK(3, 4)
nd1 = {nk1: 5}
nd1[nk1] # outputs 5
nk2 = NewK(3, 7)
nk1 == nk2 # True!
nd1[nk2] # KeyError! The keys' hashes differ.
hash(nk1) == hash(nk2) # False
nk2.y = 4
nd1[nk2] # outputs 5

# Where this can cause issues:
nd1.keys()[0].x = 5
nd1[nk1] # KeyError! nk1 is no longer in the dict!
id(nd1.keys()[0]) == id(nk1)  # Yikes. True?!
nd1.keys()[0].x = 3
nd1[nk1]  # outputs 5
id(nd1.keys()[0]) == id(nk1)  # True!

DICTはオブジェクトへの参照を保存するのがはるかに簡単です。 Hashableのセクションをお読みください。文字列のようなものは不変です。あなたがそれらを「変更」すると、あなたがそれを変更したのは、今では新しいオブジェクトを参照しています。可変性のあるオブジェクトは「在籍中」に変更できます。したがって、両方のDICTの値が変更されます。

d1 = {1: 'a'}
d2 = d1.copy()
id(d1[1]) == id(d2[1]) # True
d2[1] = 'z'
id(d1[1]) == id(d2[1]) # False

# the examples in section 2 above have more examples of this.

とにかく、これがすべての主要なポイントです:

  • にとって キー, 、そうではないかもしれません 可変性, 、 むしろ ハッシュ性と比較可能性, 、あなたが気にかけていること。
  • 定義上、可変オブジェクトの値を変更することなく変更することができるため、値の可変性を気にします。

これらのポイントのいずれかをテストする一般的な方法はないと思います。適合性のテストは、ユースケースに依存します。たとえば、オブジェクトが実装または実装していないことを確認するだけで十分かもしれません __hash__ と比較(__eq__ また __cmp__) 関数。同様に、あなたはオブジェクトを「チェック」できるかもしれません __setattr__ 何らかの方法で、それが可変であるかどうかを判断する方法。

dictは、キーの順序付けられていないセットです:バリューペア。キーは不変である必要があり、したがってハッシュ可能です。オブジェクトがハッシュ可能かどうかを判断するには、 hash() 働き:

>>> hash(1)
1
>>> hash('a')
12416037344
>>> hash([1,2,3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash((1,2,3))
2528502973977326415
>>> hash({1: 1})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

一方、値は任意のオブジェクトにすることができます。オブジェクトが不変かどうかを確認する必要がある場合は、使用します hash().

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top