これはバグのように見えます。 The implementation is to convert the dict_keys
to a set
, then call .difference_update(arg)
on it.
彼らはちょうど"O"
のフォーマット文字列を渡すことで、_PyObject_CallMethodId
(PyObject_CallMethod
の最適化されたバリアント)を誤用ように見えます。 Thing is, PyObject_CallMethod
and friends are documented to require a Py_BuildValue
format string that "should produce a tuple
"。複数の書式コードを使用すると、値は自動的にtuple
にラップされますが、書式コードが1つのみの場合はtuple
ではなく、値を作成します(この場合はすでにPyObject*
です)。参照カウント)。
それがこれを行う可能性がありますどこ私がダウンして追跡していないが、私はどこかにそれが実際にそう呼ばれる関数をすることができtuple
を生成しないCallMethod
通話を識別し、一つの要素tuple
を作るためにそれらを包んだ内部の容疑者引数を期待される形式で受け取る。 tuple
を差し引くと、それはすでにtuple
です。この修正コードは決してアクティブになりません。 list
を渡すと、list
を含む1つの要素tuple
になります。
difference_update
は、(宣言されているかのように)def difference_update(self, *args)
となります。それは開封されたtuple
を受けたときに、自分自身を離れて減算する値として言わエントリを扱う、tuple
の各エントリから要素を離れないで引くことになっています考えています。
mydict.keys() - (1, 2)
バグが(大体)、それが何を引き起こしている:あなたがないとき、説明するために
result = set(mydict)
# We've got a tuple to pass, so all's well...
result.difference_update(*(1, 2)) # Unpack behaves like difference_update(1, 2)
# OH NO!
中:
mydict.keys() - [1, 2]
することはありません:
result = set(mydict)
# [1, 2] isn't a tuple, so wrap
result.difference_update(*([1, 2],)) # Behaves like difference_update([1, 2])
# All's well
だからこそtuple
のstr
作品(間違って)、- ('abc', '123')
はへの呼び出しに相当を実行している:
result.difference_update(*('abc', '123'))
# or without unpacking:
result.difference_update('abc', '123')
とstr
sが自分のキャラクターの反復可能オブジェクトなので、それだけで軽率代わり'abc'
と'123'
のなど'a'
、'b'
、'c'
、のエントリを削除します期待通り。
これはバグです(私がチャンスを得たとき)、私はCPythonの人々に対してそれを提出します。
正しい行動は、おそらく(このId
バリアントは、このAPIのために存在すると仮定)を呼び出すされている必要があります:すべての梱包上の問題を持っていないだろう、と高速ブートに実行します
_PyObject_CallMethodObjArgsId(result, &PyId_difference_update, other, NULL);
。最小の変更はフォーマット文字列を"(O)"
に変更して、単一の項目に対してもtuple
を強制的に作成することですが、フォーマット文字列は何も得られないため、_PyObject_CallMethodObjArgsId
が優れています。
タプルは不変であるため、辞書自体のキーになる可能性があります。その場合、文法的でなくても少なくともプログラマの心には曖昧です。 – L3viathan
@ L3viathan dict.fromkeys( '0123')。keys() - '02''はまだ動作しているので、私は確信していません – wim
うん、良い点。 – L3viathan