dict
からサブクラス化されたオブジェクトのキーを反復処理すると、Python 3.6.3で奇妙な動作をしました。 dict.keys()
の動作がPython 2からPython 3に変更されて、dict_keys
オブジェクトを返すようになったので、見た目の浅いコピーの動作がわかります。私が理解できないのは、dict_keys
の要素の1つが明示的な検索で検出されるが、dict_keys
オブジェクトを反復するときには表示されない理由です。実験1では`dict_keys`を反復処理するときに、サブクラス化されたdictからキーが消えるのはなぜですか?
Test 1: Not static
Unnormalized:
{'N2': 78.084, 'O2': 20.947, 'Ar': 0.934, 'CO2': 0.035}
Normalizing:
raw_chems is dict_keys(['N2', 'O2', 'Ar', 'CO2'])
Found Argon!
Checking N2
Checking O2
Checking CO2
Checking _N2
Checking _O2
Checking _CO2
Normalized:
{'Ar': 0.934, '_N2': 78.084, '_O2': 20.947, '_CO2': 0.035}
Test 2: Not static
Unnormalized:
{'N2': 78.084, 'O2': 20.947, 'Ar': 0.934, 'CO2': 0.035}
Normalizing:
raw_chems is ('N2', 'O2', 'Ar', 'CO2')
Found Argon!
Checking N2
Checking O2
Checking Ar
Checking CO2
Normalized:
{'_N2': 78.084, '_O2': 20.947, '_Ar': 0.934, '_CO2': 0.035}
は、要素'Ar'
が明示的にraw_chems
でそれを検索することによって発見された:
#!/usr/bin/env python
from __future__ import print_function
class chemdist(dict):
def normalize_names(self, force_static=False):
if force_static:
raw_chems = tuple(self.keys())
else:
raw_chems = self.keys()
print("raw_chems is " + repr(raw_chems))
if 'Ar' in raw_chems:
print("Found Argon!")
for old_chem in raw_chems:
print("Checking {:s}".format(old_chem))
if old_chem.startswith('_'):
new_chem = old_chem
else:
new_chem = '_' + old_chem
if old_chem != new_chem:
curr_keys = self.keys()
if new_chem in curr_keys:
self[new_chem] += self[old_chem]
else:
self[new_chem] = self[old_chem]
del self[old_chem]
def main():
h_dryair = {
'N2' : 78.084,
'O2' : 20.947,
'Ar' : 0.934,
'CO2' : 0.0350
}
print("Test 1: Not static")
cd_dryair = chemdist(h_dryair)
print(" Unnormalized:")
print(cd_dryair)
print("\n Normalizing:")
cd_dryair.normalize_names()
print("\n Normalized:")
print(cd_dryair)
print("\n\nTest 2: Static")
cd_dryair = chemdist(h_dryair)
print(" Unnormalized:")
print(cd_dryair)
print("\n Normalizing:")
cd_dryair.normalize_names(force_static=True)
print("\n Normalized:")
print(cd_dryair)
main()
そして、ここでは結果である:
はここMWEです。ただし、raw_chems
を反復すると、要素'Ar'
は表示されません("Checking Ar"
は表示されません)。
テスト2では、raw_chems
がタプルにキャストされ、"Checking Ar"
が予想通りに表示されます。
また、テスト1では、'Ar'
のキーは、テスト2と同じように'_Ar'
に置き換えられていません。'Ar'
は、テスト1の下線が付けられていない唯一のキーです。
私はこの問題の原因で2つの推定を持っている:dict_keys
が持っているいくつかの明らかツー誰も - しかし、私行動や私がdict
をサブクラス化していますので、いくつかのすごみが起こっています。おそらく2つの組み合わせ。
そして、誰かが無償で私が求めている質問を変更しようとする前に、私が解決しようとしているビッグ・ピクチャーの問題は、標準的な形式(HH
、H2
にdictのキーの名前を変更することで、molecular hydrogen
すべてが同じものを表しています)。そのアドレスにはいくつかのためのより興味深い問題であるかもしれないが代わりにの述べたように、私はそうXに焦点を当ててください、消滅キーについて聞いてるのよYあなたは...想像:)
これはよく説明されていますが、あなたのロジックに従って、なぜO2もスキップされませんか?この場合、処理される最初の要素はN2です。ではなぜArだけがスキップされますか? – scharette
'dict'実装に依存して、いくつかの状況で実際に同じスロットに入る可能性があるため、私は少し単純化しました。要点は、それらを反復処理している間は、確実にdictsを変更することはできません。注意が必要な場合はリストを使用することは可能ですが、明細書の注文については何も保証しません。 – kindall
本質的に、 'dict_keys'の下にあるデータ構造は、' dict'を変更することによって、ユーザーとコードの間の契約に違反して、乱雑になります。新しい 'dict'を構築する際の問題は、' dict'がオブジェクト内から置き換え可能ではないように見える 'self'です。私はそれを最初に試してみました。そして、 'dict'エントリを置き換えることに戻りました。代替案は、恐ろしい内部プログラミングかひどいAPIのいずれかに見える。 – arclight