title: dict_keysの話
author: Amane Katagiri
summary: 誰も使わないコーナーケース
date: 2015-09-20T02:43:00+09:00
category: tech
license: CC BY 4.0
rating: sfw
ai_summary: Pythonの辞書メソッドdict.keys()が返すビューオブジェクトの集合演算について検証した記事です。リストやセットとの減算は正常に動作する一方で、タプルとの減算では「'int' object is not iterable」という不可解なエラーが発生する現象を報告しています。イテラブルオブジェクトごとの挙動の違いや、加算演算子がサポートされていない点など、言語仕様上の挙動に関する疑問を投げかけています。
ai_keywords: Python, dict.keys, ビューオブジェクト, 集合演算, イテラブル, TypeError, タプル, リスト, セット, 仕様検証

[Python文法詳解](http://www.amazon.co.jp/dp/4873116880)で次のような記述を見ました。

> `dict.keys()`メソッドは、キーの**ビューオブジェクト**を返します。ビューオブジェクトは集合オブジェクトに似たイテラブルオブジェクトで、全てのキーを列挙したり、要素の存在チェックを行ったりできます。（コード例略）他の集合やイテラブルオブジェクトと、集合演算も行えます。

コード例ではリストとの減算しか行っていなかったので、いろいろやってみることにしたのですが……。

```python
dictionary = {1: 'spam', 2: 'ham', 3: 'egg'}
dictionary.keys()

dictionary.keys() - [1, 2]
dictionary.keys() + [1, 2]

dictionary.keys() - {1, 2}
dictionary.keys() + {1, 2}

dictionary.keys() - (1, 2)
dictionary.keys() + (1, 2)
```

適当な辞書とリスト、セット、タプルとの演算のテストコードです。結果を見てみましょう。

```python
>>> dictionary.keys() - [1, 2]
{3}
>>> dictionary.keys() + [1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>;
TypeError: unsupported operand type(s) for +: 'dict_keys' and 'list'

>>> dictionary.keys() - {1, 2}
{3}
>>> dictionary.keys() + {1, 2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_keys' and 'set'
```

ここまで、2つのイテラブルオブジェクトとの演算により、`dict_keys`がイテラブルオブジェクトに対して減算を定義していることが予測できます。

しかし、タプルとの演算では、謎のエラーに悩まされることになったのでした。

```python
>>> dictionary.keys() - (1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>;
TypeError: 'int' object is not iterable
>>> dictionary.keys() + (1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>;
TypeError: unsupported operand type(s) for +: 'dict_keys' and 'tuple'
```

dict_keysとタプルの間の減算でもエラーが発生してしまいます。

タプルがどうこういう問題の前にタプルの要素である整数型のオブジェクトが呼ばれているらしく。

Python-forumで質問してみても、どうも納得できる回答は得られず。

Subtraction tuple from dict.keys()[^python-forum]

[^python-forum]: http://www.python-forum.org/viewtopic.php?f=10&t=16998

3つのビルトインのイテラブルオブジェクトには、どういう関係があるんでしょうね。どなたか知ってる方がいらっしゃったら、教えてもらえれば幸いです。
