初心者向け - 静かなる名辞
pythonとプログラミングのこと
2020-05-07T20:42:34+09:00
hayataka2049
Hatena::Blog
hatenablog://blog/10328537792367869878
list, tuple, dict, setの基本的な使い方、相違点、使い分け、応用など
hatenablog://entry/26006613383865753
2019-08-09T00:05:31+09:00
2019-08-31T22:14:38+09:00 pythonでよく使う組み込みのコレクション型には、list, tuple, dict, setなどがあります。ただ、なんとなく使っている、いつもlist、それぞれ微妙に使い勝手が違って困る、という人も多いと思います。そこで、これらについて解説します。
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> pythonでよく使う組み込みのコレクション型には、list, tuple, dict, setなどがあります。ただ、なんとなく使っている、いつもlist、それぞれ微妙に使い勝手が違って困る、という人も多いと思います。そこで、これらについて解説します。</p><p>目次</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#コレクション型ってなに">コレクション型ってなに?</a></li>
<li><a href="#listについて">listについて</a><ul>
<li><a href="#基本">基本</a></li>
<li><a href="#内包表記">内包表記</a></li>
</ul>
</li>
<li><a href="#tupleについて">tupleについて</a><ul>
<li><a href="#基本-1">基本</a></li>
<li><a href="#応用">応用</a></li>
</ul>
</li>
<li><a href="#dict">dict</a><ul>
<li><a href="#基本-2">基本</a></li>
<li><a href="#重要な性質">重要な性質</a></li>
<li><a href="#内包表記-1">内包表記</a></li>
<li><a href="#眷属たち">眷属たち</a></li>
</ul>
</li>
<li><a href="#set">set</a><ul>
<li><a href="#基本-3">基本</a></li>
<li><a href="#内包表記-2">内包表記</a></li>
<li><a href="#frozenset">frozenset</a></li>
</ul>
</li>
<li><a href="#まとめ">まとめ</a></li>
</ul>
</div>
<div class="section">
<h3 id="コレクション型ってなに">コレクション型ってなに?</h3>
<p> とりあえず、「コレクション型」という用語は公式に使われているものではなく、便宜的にそう読んでいるだけなので注意してください。「中にオブジェクトを格納できる型(クラス)」程度の意味です。</p><p> ドキュメントによれば、pythonの主要な組み込み型には以下のような区別があります。</p>
<blockquote>
<p>主要な組み込み型は、数値、シーケンス、マッピング、クラス、インスタンス、および例外です。</p><p><a href="https://docs.python.org/ja/3/library/stdtypes.html">組み込み型 — Python 3.7.4 ドキュメント</a></p>
</blockquote>
<p>(なお、上のページはつらつらと読むとそれだけで勉強になります。この記事を読んで物足りないと思った人におすすめです。)</p><p> さて、タイトルに含めた4つのうち、listとtupleはシーケンス、dictはマッピングです。setはどれにも当てはまりません。</p><p> シーケンス、マッピングという言葉の意味は、なんとなくわかる人も多いと思います。シーケンスは順番があって連続的に、あるいはインデックスを指定したりしてアクセス可能なもの、マッピングはシーケンスと異なって順番を持ちませんが、dictのように任意のキーと値の対応付けを記録可能なものです(というか、基本的にdictとその亜種しかないと思います)。</p><p> こういう「コレクション型」はpythonでプログラミングをする上ではとても重要なので、とりあえず組み込みの主だったものはすべて覚えておきましょう。どんなコードでも何らかの形で利用していたりするので、知らないと困ります。</p>
</div>
<div class="section">
<h3 id="listについて">listについて</h3>
<div class="section">
<h4 id="基本">基本</h4>
<p> コレクション型の中でもっとも代表的なのはlist(リスト)ですね。色々な場面で汎用的に使われます。初心者の方はとりあえずlistを覚えて、慣れないうちはなんでもlistで書くと良いと思います。</p><p> リテラル<a href="#f-b5be7345" name="fn-b5be7345" title="これも説明が難しい概念ですが、わからなければ頑張って調べてください。この記事では触れません。">*1</a>で書く場合はこんな感じです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>(lst1) <span class="synComment"># 空のリスト</span>
[]
>>> lst2 = [<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>]
>>> <span class="synIdentifier">print</span>(lst2)
[<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>]
</pre><p> 要素を末尾に追加したければ、appendが使えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst1.append(<span class="synConstant">4</span>)
>>> lst2.append(<span class="synConstant">5</span>)
>>> <span class="synIdentifier">print</span>(lst1)
[<span class="synConstant">4</span>]
>>> <span class="synIdentifier">print</span>(lst2)
[<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">5</span>]
</pre><p> 逆にlist以外でappendが使えるものはあまり(というか恐らくまったく)ありません。ついでに書いておくと、numpyやpandasにもappendがありますが、あれはあれでまた違った挙動になります。</p><p> 「拡張」というか、listを含む他のコレクション型など<a href="#f-e0bcc1a5" name="fn-e0bcc1a5" title="iterableなら何でもいいのですが、iterableが何であるのかについてもこの記事では触れません。">*2</a>の中身をまとめて突っ込みたいときは、extendというメソッドが使えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst1.extend(lst2)
>>> <span class="synIdentifier">print</span>(lst1)
[<span class="synConstant">4</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">5</span>]
</pre><p> あとは普通にインデックスで要素を取得したり、for文に渡してループしたりもできます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>(lst1[<span class="synConstant">0</span>])
<span class="synConstant">4</span>
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst1:
... <span class="synIdentifier">print</span>(x)
...
<span class="synConstant">4</span>
<span class="synConstant">1</span>
<span class="synConstant">2</span>
<span class="synConstant">3</span>
<span class="synConstant">5</span>
</pre><p> インデックスで要素を削除したい場合はdel文で行えます。また、pop(こちらもインデックスで指定し、除去した要素を返す), remove(こちらはオブジェクトの値が一致するものを除去)などで取り除くこともできます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">del</span> lst1[<span class="synConstant">3</span>]
>>> <span class="synIdentifier">print</span>(lst1)
[<span class="synConstant">4</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">5</span>]
</pre><p> ただ、あまり使っているのを見ませんね。これをやるとインデックスが狂う上、ループと組み合わせると面倒くさい問題もあります。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2018%2F06%2F02%2F163415" title="【python】listをforループで回してremoveしたら思い通りにならない - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2018/06/02/163415">【python】listをforループで回してremoveしたら思い通りにならない - 静かなる名辞</a></p><br />
<p> append以外でlistの長さが減るような処理は積極的にやらない、という傾向が強いのではないでしょうか。</p><p> listは「ミュータブルなシーケンス」という分類になり、実はとてもたくさんの操作が行えます。すべてはカバーできないので、ここ↓を見てください。</p><p><a href="https://docs.python.org/ja/3/library/stdtypes.html#sequence-types-list-tuple-range">組み込み型 — Python 3.7.4 ドキュメント | シーケンス型 --- list, tuple, range</a></p><p> 繰り返しになりますが、これを読むととても勉強になります。</p>
</div>
<div class="section">
<h4 id="内包表記">内包表記</h4>
<p> listといえばリスト内包表記というくらいよく使われるものです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>([x + <span class="synConstant">100</span> <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">5</span>)])
[<span class="synConstant">100</span>, <span class="synConstant">101</span>, <span class="synConstant">102</span>, <span class="synConstant">103</span>, <span class="synConstant">104</span>]
</pre><p> 難しいものではないので、慣れましょう。</p>
</div>
</div>
<div class="section">
<h3 id="tupleについて">tupleについて</h3>
<div class="section">
<h4 id="基本-1">基本</h4>
<p> tuple(タプル)はlistの中身を一切変更できなくしたような使い勝手です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> tup1 = () <span class="synComment"># 空のtuple</span>
>>> tup2 = (<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>)
>>> <span class="synIdentifier">print</span>(tup1)
()
>>> <span class="synIdentifier">print</span>(tup2)
(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>)
</pre><p> 注意しないといけないのは、外側の丸括弧()はtupleの本質<b>ではない</b>という点です。カンマがあればtupleは作れます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> tup2 = <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>
>>> tup2
(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>)
</pre><p> え、カンマなんかあちこちで使うじゃん(関数の引数リストとか)と思うと思いますが、原則的には「他の構文とみなせないときはtupleとみなす」というルールです。なんかややこしいですね。</p><p> では丸括弧は何か? というと、数式で(a + b) * 2とかやるときの丸括弧と同じで、評価の順番を決めているだけです。これがあることで、関数の引数リストなどの他の構文と混同されないようにtupleを表すことができます。</p><p> このことを知らないと、要素数1つのtupleを作りたいとき、こういうものを書いてしまいます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> this_is_not_tuple = (<span class="synConstant">4</span>)
>>> <span class="synIdentifier">print</span>(<span class="synIdentifier">type</span>(this_is_not_tuple), this_is_not_tuple)
<<span class="synStatement">class</span> <span class="synConstant">'int'</span>> <span class="synConstant">4</span>
</pre><p> 要素数1のtupleは、下のようにしてください。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> this_is_tuple = (<span class="synConstant">4</span>, )
>>> <span class="synIdentifier">print</span>(<span class="synIdentifier">type</span>(this_is_tuple), this_is_tuple)
<<span class="synStatement">class</span> <span class="synConstant">'tuple'</span>> (<span class="synConstant">4</span>,)
</pre>
</div>
<div class="section">
<h4 id="応用">応用</h4>
<p> 中身の変更できないtupleなんか何に使えるんだと思われるかもしれませんが、tupleのようなイミュータブル(変更不可能)なオブジェクトはhashableという大切な性質を持っています。後述のdictやsetのキー、要素にしたいとき、データをtupleで表現するということがよく行われます。</p><p> tupleには内包表記はありません。内包表記的なことをしたい場合は、ジェネレータ式と組み合わせて以下のように書くと手っ取り早いでしょう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">tuple</span>(x - <span class="synConstant">100</span> <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">5</span>))
(-<span class="synConstant">100</span>, -<span class="synConstant">99</span>, -<span class="synConstant">98</span>, -<span class="synConstant">97</span>, -<span class="synConstant">96</span>)
</pre>
</div>
</div>
<div class="section">
<h3 id="dict">dict</h3>
<div class="section">
<h4 id="基本-2">基本</h4>
<p> dict(ディクトと呼びますが、辞書という訳の方が一般的です)はキーと値の対応付けを保持します。</p><p> リテラルではこう書きます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> dct1 = {} <span class="synComment"># 空のdict</span>
>>> dct2 = {<span class="synConstant">"hoge"</span>:<span class="synConstant">0</span>, <span class="synConstant">"fuga"</span>:<span class="synConstant">1</span>}
>>> <span class="synIdentifier">print</span>(<span class="synIdentifier">type</span>(dct1), dct1)
<<span class="synStatement">class</span> <span class="synConstant">'dict'</span>> {}
>>> <span class="synIdentifier">print</span>(dct2)
{<span class="synConstant">'hoge'</span>: <span class="synConstant">0</span>, <span class="synConstant">'fuga'</span>: <span class="synConstant">1</span>}
</pre><p> {キー:値, ...}という感じの構文です。簡単ですね。</p><p> 値の追加には普通は代入を使います。また、累積代入文なども使えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> dct2[<span class="synConstant">"piyo"</span>] = <span class="synConstant">2</span>
>>> <span class="synIdentifier">print</span>(dct2)
{<span class="synConstant">'hoge'</span>: <span class="synConstant">0</span>, <span class="synConstant">'fuga'</span>: <span class="synConstant">1</span>, <span class="synConstant">'piyo'</span>: <span class="synConstant">2</span>}
>>> dct2[<span class="synConstant">"piyo"</span>] += <span class="synConstant">999</span>
>>> <span class="synIdentifier">print</span>(dct2)
{<span class="synConstant">'hoge'</span>: <span class="synConstant">0</span>, <span class="synConstant">'fuga'</span>: <span class="synConstant">1</span>, <span class="synConstant">'piyo'</span>: <span class="synConstant">1001</span>}
</pre><p> 削除はdel文でいいのですが、あまり使わないでしょう。</p><p> 直接for文などに渡すと、キーだけが出てきます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> dct2:
... <span class="synIdentifier">print</span>(x)
...
hoge
fuga
piyo
</pre><p> keys, values, itemsというメソッドでそれぞれキー、値、キーと値のペアを取り出せます。必要に応じて活用してください。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">for</span> k <span class="synStatement">in</span> dct2.keys():
... <span class="synIdentifier">print</span>(k)
...
hoge
fuga
piyo
>>> <span class="synStatement">for</span> v <span class="synStatement">in</span> dct2.values():
... <span class="synIdentifier">print</span>(v)
...
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">1001</span>
>>> <span class="synStatement">for</span> k, v <span class="synStatement">in</span> dct2.items():
... <span class="synIdentifier">print</span>(k, v)
...
hoge <span class="synConstant">0</span>
fuga <span class="synConstant">1</span>
piyo <span class="synConstant">1001</span>
</pre><p><br />
<a href="https://docs.python.org/ja/3/library/stdtypes.html#dictionary-view-objects">組み込み型 — Python 3.7.4 ドキュメント</a><br />
</p>
</div>
<div class="section">
<h4 id="重要な性質">重要な性質</h4>
<p> dictにはいくつか覚えておかないといけない性質があります。</p><p> まず、tupleのところでも述べたとおり、キーにはimmutableなオブジェクトしか使えません。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> dct3 = {[<span class="synConstant">1</span>, <span class="synConstant">2</span>]:<span class="synConstant">3</span>}
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: unhashable <span class="synIdentifier">type</span>: <span class="synConstant">'list'</span>
>>> dct3 = {(<span class="synConstant">1</span>, <span class="synConstant">2</span>):<span class="synConstant">3</span>}
>>> <span class="synIdentifier">print</span>(dct3)
{(<span class="synConstant">1</span>, <span class="synConstant">2</span>): <span class="synConstant">3</span>}
</pre><p> また、基本的には順番の概念はない、ということも知っておく必要があります。伝統的なPythonでは、辞書のキー・値の順番は適当にシャッフルされていました(内部的には意味があったのですが、割愛)。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synComment"># Python 3.5で実行</span>
>>> d = {<span class="synConstant">"hoge"</span>:<span class="synConstant">123</span>, <span class="synConstant">"fuga"</span>:<span class="synConstant">456</span>, <span class="synConstant">"piyo"</span>:<span class="synConstant">789</span>}
>>> <span class="synIdentifier">print</span>(d)
{<span class="synConstant">'fuga'</span>: <span class="synConstant">456</span>, <span class="synConstant">'hoge'</span>: <span class="synConstant">123</span>, <span class="synConstant">'piyo'</span>: <span class="synConstant">789</span>}
</pre><p> 最近のPython<a href="#f-57bcfd9d" name="fn-57bcfd9d" title="3.6でCPythonの実装が変わり、3.7から正式な言語仕様になりました">*3</a>では順番を保持しますが、それでもappendのような順序を前提としたオペレーションは弱いので、扱いは以前とさほど変わりません。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synComment"># Python 3.6で実行</span>
>>> d = {<span class="synConstant">"hoge"</span>:<span class="synConstant">123</span>, <span class="synConstant">"fuga"</span>:<span class="synConstant">456</span>, <span class="synConstant">"piyo"</span>:<span class="synConstant">789</span>}
>>> <span class="synIdentifier">print</span>(d)
{<span class="synConstant">'hoge'</span>: <span class="synConstant">123</span>, <span class="synConstant">'fuga'</span>: <span class="synConstant">456</span>, <span class="synConstant">'piyo'</span>: <span class="synConstant">789</span>}
</pre><p> まだあります。上で書いたkeys, values, itemsはとても便利ですが、これらは辞書ビューオブジェクトという集合っぽいオブジェクトで、しかもリアルタイムで辞書の中身を反映してくれます。ただし、ループ中にいじったりすると意図しない結果になったり、エラーが出たりします。</p><p><a href="https://www.haya-programming.com/entry/2018/11/12/053313">ループで辞書の要素を削除しようと思ったらRuntimeError: dictionary changed size during iteration - 静かなる名辞</a></p><p> 便利ですが、扱いには少し気をつけた方が良いのが辞書です。</p>
</div>
<div class="section">
<h4 id="内包表記-1">内包表記</h4>
<p> dictにも内包表記があります。書き方はリスト内包表記と辞書のリテラルを混ぜた感じです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> dct4 = {i:i**<span class="synConstant">2</span> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">5</span>)}
>>> <span class="synIdentifier">print</span>(dct4)
{<span class="synConstant">0</span>: <span class="synConstant">0</span>, <span class="synConstant">1</span>: <span class="synConstant">1</span>, <span class="synConstant">2</span>: <span class="synConstant">4</span>, <span class="synConstant">3</span>: <span class="synConstant">9</span>, <span class="synConstant">4</span>: <span class="synConstant">16</span>}
</pre><p> まあ、これといって難しいことはないかと。</p>
</div>
<div class="section">
<h4 id="眷属たち">眷属たち</h4>
<p> dictには覚えておくと便利な標準の亜種がいくつかあります。collectionsモジュールから使えます。</p><p> 筆頭はdefaultdictでしょう。これはキーの初期値を適当に設定できるもので、データの集計などで威力を発揮します。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synComment"># 長さの異なる文字列ごとにグルーピングする処理</span>
>>> lst = [<span class="synConstant">"a"</span>, <span class="synConstant">"b"</span>, <span class="synConstant">"ab"</span>, <span class="synConstant">"abc"</span>, <span class="synConstant">"bcd"</span>]
>>> d = {} <span class="synComment"># defaultdictを使わない場合</span>
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... l = <span class="synIdentifier">len</span>(x)
... <span class="synStatement">if</span> l <span class="synStatement">in</span> d:
... d[l].append(x)
... <span class="synStatement">else</span>:
... d[l] = [x]
...
>>> <span class="synIdentifier">print</span>(d)
{<span class="synConstant">1</span>: [<span class="synConstant">'a'</span>, <span class="synConstant">'b'</span>], <span class="synConstant">2</span>: [<span class="synConstant">'ab'</span>], <span class="synConstant">3</span>: [<span class="synConstant">'abc'</span>, <span class="synConstant">'bcd'</span>]}
<span class="synComment"># defaultdictを使う場合</span>
>>> <span class="synPreProc">from</span> collections <span class="synPreProc">import</span> defaultdict
>>> d = defaultdict(<span class="synIdentifier">list</span>)
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... l = <span class="synIdentifier">len</span>(x)
... d[l].append(x) <span class="synComment"># d[l]がなければ勝手に空のリストを初期値にしてくれる</span>
...
>>> <span class="synIdentifier">print</span>(d)
defaultdict(<<span class="synStatement">class</span> <span class="synConstant">'list'</span>>, {<span class="synConstant">1</span>: [<span class="synConstant">'a'</span>, <span class="synConstant">'b'</span>], <span class="synConstant">2</span>: [<span class="synConstant">'ab'</span>], <span class="synConstant">3</span>: [<span class="synConstant">'abc'</span>, <span class="synConstant">'bcd'</span>]})
</pre><p> 他の使い方はdictとほぼ同じです。</p><p> また、Counterは引数の頻度を勝手に集計してくれます。これも辞書の眷属みたいなものです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synPreProc">from</span> collections <span class="synPreProc">import</span> Counter
>>> lst = [<span class="synConstant">1</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">3</span>, <span class="synConstant">2</span>, <span class="synConstant">5</span>]
>>> cnt = Counter(lst)
>>> <span class="synIdentifier">print</span>(cnt)
Counter({<span class="synConstant">1</span>: <span class="synConstant">2</span>, <span class="synConstant">2</span>: <span class="synConstant">2</span>, <span class="synConstant">3</span>: <span class="synConstant">2</span>, <span class="synConstant">4</span>: <span class="synConstant">1</span>, <span class="synConstant">5</span>: <span class="synConstant">1</span>})
>>> <span class="synIdentifier">print</span>(cnt[<span class="synConstant">0</span>])
<span class="synConstant">0</span>
>>> <span class="synIdentifier">print</span>(cnt[<span class="synConstant">1</span>])
<span class="synConstant">2</span>
</pre><p> このあたりを知っているかどうかでコードのクオリティが変わるので、覚えておきましょう。<br />
<a href="https://docs.python.org/ja/3/library/collections.html">collections --- コンテナデータ型 — Python 3.7.4 ドキュメント</a><br />
</p>
</div>
</div>
<div class="section">
<h3 id="set">set</h3>
<div class="section">
<h4 id="基本-3">基本</h4>
<p> トリを飾るのはsetです(セットとも呼びますが、表記するときは集合型とするかsetとそのまま書くかのどちらかです)。</p><p> setは数学的な集合を表現できます。あるいは、dictをkeyだけにしたようなものと考えてもいいでしょう(内部ではどちらもハッシュテーブルを使っています)。</p><p> リテラルで書くとき注意しないといけないのは、空のsetをリテラルで表現する手段が基本的にないということです。コンストラクタを使ってset()で作ります(これまで触れていませんでしたが、list(), tuple(), dict()でそれぞれ空のコレクションを作れます)。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s1 = <span class="synIdentifier">set</span>()
>>> <span class="synIdentifier">print</span>(s1)
<span class="synIdentifier">set</span>()
>>> s2 = {<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}
>>> <span class="synIdentifier">print</span>(s2)
{<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}
</pre><p> 集合なので、要素は重複しません。強制的に1つにまとめられます。これを利用して、list→setに変換してユニークな要素の数を数えるというテクニックもよく使われます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s3 = {<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">3</span>}
>>> <span class="synIdentifier">print</span>(s3)
{<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}
>>> lst = [<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">3</span>]
>>> <span class="synIdentifier">print</span>(<span class="synIdentifier">len</span>(<span class="synIdentifier">set</span>(lst)))
<span class="synConstant">3</span>
</pre><p> 集合なので、様々な演算が行なえます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s1 = {<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>}
>>> s2 = {<span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>}
>>> <span class="synIdentifier">print</span>(s1 & s2) <span class="synComment"># AND</span>
{<span class="synConstant">3</span>, <span class="synConstant">4</span>}
>>> <span class="synIdentifier">print</span>(s1 | s2) <span class="synComment"># OR</span>
{<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>}
>>> <span class="synIdentifier">print</span>(s1 - s2) <span class="synComment"># 引き算</span>
{<span class="synConstant">1</span>, <span class="synConstant">2</span>}
>>> <span class="synIdentifier">print</span>(s2 - s1)
{<span class="synConstant">5</span>, <span class="synConstant">6</span>}
>>> <span class="synIdentifier">print</span>(s1 ^ s2) <span class="synComment"># 排他的論理和</span>
{<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>}
</pre><p> 集合型を使う場面というのはこういう演算を使うことを期待している場合で、逆にそれ以外だと上のように「重複を除く」などで使う可能性がある以外には、あまり使いみちはありません。</p><p> 要素の追加はaddメソッドを使います。取り除くときはremoveかdiscardを使うことになるでしょう(存在しない要素に対して行った場合にエラーになるかどうかだけが異なります)。listの操作とはまったく互換性がないので、注意してください。appendは使えません。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synIdentifier">set</span>()
>>> s.add(<span class="synConstant">1</span>)
>>> <span class="synIdentifier">print</span>(s)
{<span class="synConstant">1</span>}
>>> s.discard(<span class="synConstant">1</span>)
>>> <span class="synIdentifier">print</span>(s)
<span class="synIdentifier">set</span>()
</pre><p><a href="https://docs.python.org/ja/3/library/stdtypes.html#set-types-set-frozenset">組み込み型 — Python 3.7.4 ドキュメント</a></p><p> dictのキーと同じく、中に入れられるのはimmutable(厳密にはhashableであればよいが)だけです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = {[<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>], [<span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>]}
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: unhashable <span class="synIdentifier">type</span>: <span class="synConstant">'list'</span>
</pre>
</div>
<div class="section">
<h4 id="内包表記-2">内包表記</h4>
<p> setには内包表記があります。めったに使わないのですが、dictの内包表記と間違えて書かないために覚えておく必要があります。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = {i**<span class="synConstant">2</span> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">5</span>)}
>>> <span class="synIdentifier">print</span>(s)
{<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">4</span>, <span class="synConstant">9</span>, <span class="synConstant">16</span>}
</pre>
</div>
<div class="section">
<h4 id="frozenset">frozenset</h4>
<p> これも知っておいた方が良いでしょう。</p><p> 集合の中に集合を入れる、あるいはsetを辞書のキーにする、という場面がたまにあります。でも、setはmutableなので、そのままでは使えません。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = {{<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}, {<span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>}}
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: unhashable <span class="synIdentifier">type</span>: <span class="synConstant">'set'</span>
</pre><p> この場合、frozensetが使えます。これも組み込み型です。listに対するtupleだと思えば良いでしょう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = {<span class="synIdentifier">frozenset</span>({<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}), <span class="synIdentifier">frozenset</span>({<span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>})}
>>> <span class="synIdentifier">print</span>(s)
{<span class="synIdentifier">frozenset</span>({<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>}), <span class="synIdentifier">frozenset</span>({<span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>})}
</pre>
</div>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> Pythonの基本的なコレクション型4つについて説明してみました。</p><p> この記事の内容程度のことを知っておくと、コーディングがはかどります。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-b5be7345" name="f-b5be7345" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">これも説明が難しい概念ですが、わからなければ頑張って調べてください。この記事では触れません。</span></p>
<p class="footnote"><a href="#fn-e0bcc1a5" name="f-e0bcc1a5" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">iterableなら何でもいいのですが、iterableが何であるのかについてもこの記事では触れません。</span></p>
<p class="footnote"><a href="#fn-57bcfd9d" name="f-57bcfd9d" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">3.6でCPythonの実装が変わり、3.7から正式な言語仕様になりました</span></p>
</div>
hayataka2049
TypeError: list indices must be integers or slices, not ***等の原因と対処法
hatenablog://entry/26006613375457295
2019-07-21T05:01:28+09:00
2019-07-21T05:01:28+09:00 はじめに pythonを触り始めたばかりの人は、よくこんなエラーに遭遇すると思います。 TypeError: list indices must be integers or slices, not *** ***の部分はfloatだったりlistだったりstrだったりといろいろありますが、とにかくこんなエラーです。 また、次のも見たことがあるかもしれません。 TypeError: slice indices must be integers or None or have an __index__ method これはスライス(:を使ってリストの特定範囲だけ抜き出すやつ)を使ったときに出てき…
<div class="section">
<h3>はじめに</h3>
<p> pythonを触り始めたばかりの人は、よくこんなエラーに遭遇すると思います。</p>
<ul>
<li>TypeError: list indices must be integers or slices, not ***</li>
</ul><p> ***の部分はfloatだったりlistだったりstrだったりといろいろありますが、とにかくこんなエラーです。</p><p> また、次のも見たことがあるかもしれません。</p>
<ul>
<li>TypeError: slice indices must be integers or None or have an __index__ method</li>
</ul><p> これはスライス(:を使ってリストの特定範囲だけ抜き出すやつ)を使ったときに出てきます。まあ、似たようなものです。</p><p> この記事ではこういうエラーの原因と対処法について説明します。</p>
</div>
<div class="section">
<h3>原因</h3>
<p> さて、簡単にこのエラーを再現してみましょう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>]
>>> lst[<span class="synConstant">"hoge"</span>]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">list</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">str</span>
</pre><p> 出ましたね。</p><p> 今回は***の部分はstrになっていますが、これは「indices」([]の中に入るもの)として渡されたものが文字列で、でもlistのindicesは整数かスライスじゃないとだめだよ、というエラーです。</p><p> また、スライスについても同様で、このように再現できます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst[<span class="synConstant">"fuga"</span>:]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">slice</span> indices must be integers <span class="synStatement">or</span> <span class="synIdentifier">None</span> <span class="synStatement">or</span> have an __index__ method
</pre><p> もうある程度は気づいたと思いますが、[](添字表記と言ったりします)の中に入れられるものは型が決まっています。そして、それ以外の型のオブジェクトを入れるとエラーになります。</p>
</div>
<div class="section">
<h3>対処法</h3>
<p> 上述のような理由で出てくるので、はっきり言って対処法はケースバイケースです。なので、状況に応じてデバッグをする必要があります。</p><p> とりあえず、変数を使っているようなケースでは、printしてみましょう。一番単純なデバッグです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synConstant">"hoge"</span>: <span class="synComment"># エラーになってしまう</span>
... <span class="synIdentifier">print</span>(lst[i])
...
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">2</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">list</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">str</span>
>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synConstant">"hoge"</span>:
... <span class="synIdentifier">print</span>(<span class="synIdentifier">type</span>(i), i) <span class="synComment"># iの型と値をprintするコードを追加</span>
... <span class="synIdentifier">print</span>(lst[i])
...
<<span class="synStatement">class</span> <span class="synConstant">'str'</span>> h <span class="synComment"># str型のhが渡っていることがわかる</span>
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">3</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">list</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">str</span>
</pre><p> これを見ればなんとなくわかることもありますが、もう少し想像力が必要なケースも多いでしょう。</p><p> ありがちなのは、インデックスでループさせたつもりだったけど元のリストをループさせていたとかでしょうか。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = [<span class="synConstant">"hoge"</span>, <span class="synConstant">"fuga"</span>]
>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> s:
... <span class="synIdentifier">print</span>(s[i])
...
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">2</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">list</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">str</span>
</pre><p> pythonのforはループ対象から1つずつ要素を取り出す、という動作をします(他の言語のforeachなどを想像されるとわかりやすいかもしれません)。</p><p> この場合は、以下のように書きます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = [<span class="synConstant">"hoge"</span>, <span class="synConstant">"fuga"</span>]
>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synIdentifier">len</span>(s)): <span class="synComment"># rangeとlenを組み合わせてインデックスを作る</span>
... <span class="synIdentifier">print</span>(s[i])
...
hoge
fuga
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> s: <span class="synComment"># 単にこれも可</span>
... <span class="synIdentifier">print</span>(x)
...
hoge
fuga
</pre><p> rangeは「0から引数の整数-1のイテラブル(ループで要素を取り出して使えるもの)を作るクラス」、lenは「イテラブルの長さを取得する関数」ですね。下の方法の方がスマートですが、インデックスを使った複雑なループでは上の方法にも分があるケースがあります。</p><p> あるいは、「割り算や掛け算の結果をインデックスに使ってしまった」場合も、こういうエラーは起こりえます。特に割り算には注意です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = <span class="synIdentifier">list</span>(<span class="synIdentifier">range</span>(<span class="synConstant">10</span>))
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>, <span class="synConstant">7</span>, <span class="synConstant">8</span>, <span class="synConstant">9</span>]
>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">10</span>):
... <span class="synIdentifier">print</span>(lst[i/<span class="synConstant">2</span>])
...
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">2</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">list</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">float</span>
</pre><p> 「整数/整数」は浮動小数点数を返します。整数で結果を得たいときは//を使うか、int, math.floor, math.ceil, roundなどを使って丸めてください。</p><p><a href="https://docs.python.org/ja/3/library/math.html">math --- 数学関数 — Python 3.7.4 ドキュメント</a><br />
<a href="https://docs.python.org/ja/3/library/functions.html#round">組み込み関数 — Python 3.7.4 ドキュメント</a></p><p></p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">10</span>):
... <span class="synIdentifier">print</span>(lst[x//<span class="synConstant">2</span>])
...
<span class="synConstant">0</span>
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">1</span>
<span class="synConstant">2</span>
<span class="synConstant">2</span>
<span class="synConstant">3</span>
<span class="synConstant">3</span>
<span class="synConstant">4</span>
<span class="synConstant">4</span>
</pre><p> また、掛け算はどちらかのオペランドが浮動小数点数なら結果も浮動小数点数になりますので、やはりint型への変換が必要になります。</p>
</div>
<div class="section">
<h3>似たようなもの</h3>
<p> 大半のイテラブルは添字表記で整数型しか使えません。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> (<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>)[<span class="synConstant">"hoge"</span>]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synIdentifier">tuple</span> indices must be integers <span class="synStatement">or</span> slices, <span class="synStatement">not</span> <span class="synIdentifier">str</span>
>>> <span class="synConstant">"hoge"</span>[<span class="synConstant">"hoge"</span>]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: string indices must be integers
</pre><p> 対処の方針は同じです。</p><p> 辞書のつもりでリストを作成していた、あるいはsetを作成していたというケースもありそうです。そういったケースでは、そもそも添字表記の対象とするオブジェクトの作り方が間違っていないのかというところから見直す必要があります。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> わかってしまえばなんてことはないエラーなのですが、ぱっと見なにを言っているのかよくわからないので戸惑う、ということも初心者の方にはありがちだと思います。とにかくlistや大半のイテラブルは添字表記に整数、またはスライス(これも整数しか受け付けません)しか受け付けない、そこに整数以外が入るとエラーになる、ということを理解してコードを書くことが大切だと思います。</p>
</div>
hayataka2049
TypeError: '***' object is not subscriptableの対処法
hatenablog://entry/17680117127205446321
2019-06-25T01:33:31+09:00
2019-09-05T03:12:45+09:00 はじめに Pythonを始めてからしばらく時間が経って、ある程度自力で複雑なプログラムを書くようになると、タイトルのようなエラーに遭遇することが多いと思います。 このエラーが出たときは、たいていはロジックに問題があります。一概に通用する対処法がないので、地道にデバッグをするのが基本です。 ただ、見慣れない単語が並んでいると思考が停止してしまう人も多いと思います。そこで、大まかな意味と対処法を書いておこうと思います。 目次 はじめに 原因 対処 まとめ 原因 まず、subscriptというのは添字のことです。subscriptionという形にすると添字表記という訳になり、これはlistやdict…
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> Pythonを始めてからしばらく時間が経って、ある程度自力で複雑なプログラムを書くようになると、タイトルのようなエラーに遭遇することが多いと思います。</p><p> このエラーが出たときは、たいていはロジックに問題があります。一概に通用する対処法がないので、地道にデバッグをするのが基本です。</p><p> ただ、見慣れない単語が並んでいると思考が停止してしまう人も多いと思います。そこで、大まかな意味と対処法を書いておこうと思います。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#原因">原因</a></li>
<li><a href="#対処">対処</a></li>
<li><a href="#まとめ">まとめ</a></li>
</ul>
</div>
<div class="section">
<h3 id="原因">原因</h3>
<p> まず、subscriptというのは添字のことです。subscriptionという形にすると添字表記という訳になり、これはlistやdictやstrなどから要素を取り出す、あれのことです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> a = [<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>]
>>> a[<span class="synConstant">0</span>] <span class="synComment"># これが添字表記</span>
<span class="synConstant">0</span>
>>> d[<span class="synConstant">"hoge"</span>] <span class="synComment"># これも添字表記</span>
<span class="synConstant">0</span>
>>> <span class="synConstant">"hoge"</span>[<span class="synConstant">0</span>] <span class="synComment"># これも添字表記</span>
<span class="synConstant">'h'</span>
</pre><p> Pythonの型には、添字表記に対応しているものと対応していないものがあります。上であげたlist, dict, strはすべて添字表記に対応しています。一方、対応していないものの代表例はint, floatなどの数値型です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> i = <span class="synConstant">0</span>
>>> i[<span class="synConstant">0</span>]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synConstant">'int'</span> <span class="synIdentifier">object</span> <span class="synStatement">is</span> <span class="synStatement">not</span> subscriptable
>>> j = <span class="synConstant">0.1</span>
>>> j[<span class="synConstant">0</span>]
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synConstant">'float'</span> <span class="synIdentifier">object</span> <span class="synStatement">is</span> <span class="synStatement">not</span> subscriptable
</pre><p> 「int型/float型のオブジェクトに対して添字表記を使うことはできませんよ」と言ってくれている訳です。これがこのエラーの出る原因です。</p><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><br />
<p></p>
</div>
<div class="section">
<h3 id="対処">対処</h3>
<p> さて、こういうエラーですので、様々なシチュエーションで出てくる可能性がある、ということはなんとなくわかると思います。</p><p> ありがちなのは、listのlist(俗に言う二次元配列)を作ったつもりで、うまくいっていないみたいなケースでしょうか。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [[<span class="synConstant">0</span>,<span class="synConstant">1</span>], <span class="synConstant">2</span>, <span class="synConstant">3</span>] <span class="synComment"># うまく要素が入っていない</span>
>>> <span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">2</span>):
... <span class="synStatement">for</span> j <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">2</span>):
... <span class="synIdentifier">print</span>(lst[i][j])
...
<span class="synConstant">0</span>
<span class="synConstant">1</span>
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">3</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synConstant">'int'</span> <span class="synIdentifier">object</span> <span class="synStatement">is</span> <span class="synStatement">not</span> subscriptable
</pre><p> 他にも、listみたいなものが返ってくるつもりで書いた関数が実際にはlist以外のものを返していた、みたいなパターンもあるかもしれません。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">pow_lst</span>(lst):
... result = [x**<span class="synConstant">2</span> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst] <span class="synComment"># returnするのを忘れた</span>
...
>>> pow_lst([<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>])[<span class="synConstant">0</span>] <span class="synComment"># なにも返さなければNoneというオブジェクトが返る</span>
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: <span class="synConstant">'NoneType'</span> <span class="synIdentifier">object</span> <span class="synStatement">is</span> <span class="synStatement">not</span> subscriptable
</pre><p> とにかく色々なケースで出てくるので、対処法としては、</p>
<ul>
<li>エラーメッセージを見て、どの行で出てきたのかを突き止める</li>
<li>添字表記を使おうとしたオブジェクトがどんな型なのかを覚えておく</li>
<li>それが自分のコーディング意図と一致しているのかを調べる</li>
<li>場合によっては添字表記を分解し、printデバッグなどをすることで原因を究明する。つまり、たとえば以下のようにする。</li>
</ul><pre class="code lang-python" data-lang="python" data-unlink><span class="synComment"># 変更前</span>
result = 何らかの関数など()[<span class="synConstant">0</span>] <span class="synComment"># ここでエラーが出たとする</span>
<span class="synComment"># 変更後</span>
tmp = 何らかの関数など()
<span class="synIdentifier">print</span>(tmp, <span class="synIdentifier">type</span>(tmp))
result = tmp[<span class="synConstant">0</span>]
</pre><p> 頑張って検証すればなんとかなることが多い印象ですので、トライしてみてください。</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 基本的ですが、こういうところで戸惑う人が減るようにと解説を書いてみました。お役に立てれば幸いです。</p>
</div>
hayataka2049
【python】print関数を使いこなそう
hatenablog://entry/17680117126995260457
2019-03-18T03:00:56+09:00
2019-03-20T04:31:47+09:00 ぼくたちは本当のprintを知らない pythonのprint関数については、たかがprintと思っている人も多いと思いますが、しかしオプションをすべて言える人はあまりいないと思います。把握しておくと出力の細かい制御をしたいとき役立ちます。 そこで、printの使いこなしについて書きます。なお、念のために先に断っておくと、新し目のpython3のprint関数の話です。python2のprint文とはまったく異なります。 printのオプション ドキュメントによると以下の引数を取ります。 print(*objects, sep=' ', end='\n', file=sys.stdout, f…
<div class="section">
<h3>ぼくたちは本当のprintを知らない</h3>
<p> pythonのprint関数については、たかがprintと思っている人も多いと思いますが、しかしオプションをすべて言える人はあまりいないと思います。把握しておくと出力の細かい制御をしたいとき役立ちます。</p><p> そこで、printの使いこなしについて書きます。なお、念のために先に断っておくと、新し目のpython3のprint関数の話です。python2のprint文とはまったく異なります。</p>
</div>
<div class="section">
<h3>printのオプション</h3>
<p> ドキュメントによると以下の引数を取ります。</p>
<blockquote>
<p>print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)</p><p><a href="https://docs.python.org/ja/3/library/functions.html#print">組み込み関数 — Python 3.7.3rc1 ドキュメント</a></p>
</blockquote>
<p> *objectsは任意個のオブジェクトをprintできることを示します。sep=' 'は、オブジェクトの区切り文字が半角スペースになるということです。これは*objectsに渡したオブジェクトの数-1個表示されます。また、end='\n'は行末に何を置くかを指定しており、デフォルトは改行です。これは行末に1つだけ置かれます。</p><p> 特殊なのはfile引数とflush引数です。file引数は出力ストリームに対応し、デフォルトのsys.stdoutはいわゆる標準出力です。任意のファイルオブジェクトを与えられるので、ファイルに書き込むといった用途に使えます。flushはいわゆる出力バッファのフラッシュの挙動になります。何もしなければ標準出力は改行時にフラッシュされますが、これをTrueにするとprintを呼ぶたびにフラッシュされるようになります。</p>
<div class="section">
<h4>sepの使い方</h4>
<p> 何も指定しないと半角スペースになるので、次のような見慣れた挙動になります。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>)
<span class="synConstant">1</span> <span class="synConstant">2</span> <span class="synConstant">3</span>
</pre><p> 空の文字列にすることで間を詰めることが可能です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, sep=<span class="synConstant">""</span>)
<span class="synConstant">123</span>
</pre><p> あるいは好きな文字列を渡すことも可能です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">print</span>(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, sep=<span class="synConstant">","</span>)
<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>
>>> <span class="synIdentifier">print</span>(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, sep=<span class="synConstant">"***"</span>)
<span class="synConstant">1</span>***<span class="synConstant">2</span>***<span class="synConstant">3</span>
</pre><p> リストの要素を適当な区切り文字で区切って表示したいというような場合、str.joinで頑張るより、リストのアンパックとprintのsep引数を組み合わせて使った方がスマートだったりします。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> l = [<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>]
>>> <span class="synIdentifier">print</span>(<span class="synConstant">","</span>.join(<span class="synIdentifier">map</span>(<span class="synIdentifier">str</span>, l))) <span class="synComment"># こちらの場合は型変換も必要</span>
<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>
>>> <span class="synIdentifier">print</span>(*l, sep=<span class="synConstant">","</span>) <span class="synComment"># これだけ</span>
<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>
</pre><p> 裏を返せば表示形式はすべて__str__任せになるので、細かい出力フォーマットは指定できないということでもあるのですが、簡易的に使いたい場合はsepの方が便利です。</p>
</div>
<div class="section">
<h4>endの使い方</h4>
<p> 改行させたくないときにendを空文字列にする、というのがよくあるユースケースです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">4</span>):
... <span class="synIdentifier">print</span>(x)
...
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">2</span>
<span class="synConstant">3</span>
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">4</span>):
... <span class="synIdentifier">print</span>(x, end=<span class="synConstant">""</span>)
...
<span class="synConstant">0123</span>
</pre><p> 最後に一回改行するために、もう一回printを呼ぶと良いと思います。</p><p> プログレスバー的な進捗表示を簡単にやりたいとき重宝しますが、それっぽく見せるためには後述のflush引数も併用する必要があります。</p>
</div>
<div class="section">
<h4>fileの使い方</h4>
<p> fileはたとえばファイル出力に使えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">with</span> <span class="synIdentifier">open</span>(<span class="synConstant">"hoge.txt"</span>, <span class="synConstant">"w"</span>) <span class="synStatement">as</span> f:
... <span class="synStatement">for</span> x <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">4</span>):
... <span class="synIdentifier">print</span>(x, <span class="synIdentifier">file</span>=f)
...
>>> (ctrl-dでpythonを終了)
$ cat hoge.txt
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">2</span>
<span class="synConstant">3</span>
</pre><p> その気になればcsvファイルの文字列を手動で作って吐き出すといった用途に使えます。あるいはソケットを叩いたりするのにも使えると思います。ただ、濫用しすぎないことをおすすめします(通常は他に良い方法がある)。</p>
</div>
<div class="section">
<h4>flushの使い方</h4>
<p> flushは前述した通りendと組み合わせると便利です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synPreProc">import</span> time
>>> <span class="synStatement">for</span> _ <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">10</span>):
... <span class="synIdentifier">print</span>(<span class="synConstant">"*"</span>, end=<span class="synConstant">""</span>)
... time.sleep(<span class="synConstant">0.5</span>)
...
**********
</pre><p> 進捗表示をやりたくてこんなコードを書く人も多いと思いますが、これは期待通り動作しないと思います。確かに最終的な結果は同じでも、5秒ほどしてから出力が一気に出てくるという挙動になるはずです。これはsys.stdoutが改行されるまでフラッシュされないからです。</p><p> flush=Trueで解決します。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synPreProc">import</span> time
>>> <span class="synStatement">for</span> _ <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">10</span>):
... <span class="synIdentifier">print</span>(<span class="synConstant">"*"</span>, end=<span class="synConstant">""</span>, flush=<span class="synIdentifier">True</span>)
... time.sleep(<span class="synConstant">0.5</span>)
...
**********
</pre><p> これでおよそ0.5秒おきに1つずつ表示されるはずです。</p>
</div>
</div>
<div class="section">
<h3>本当のprintを理解したあとの感想</h3>
<p> print一つとっても、意外といろいろな使い方があるということがわかるかと思います。出力の制御にけっこう使えます。</p><p> こういう仕様はすべて公式ドキュメントに書いてあります。ドキュメントに普段から慣れ親しんでおくと、スムーズにコーディングできる、行き詰まったとき打開策が思い浮かぶ、ライバルと差が付けられる、といった利益があります。ドキュメントを読むのに慣れていない方は、printなど単純なものから読んでみると楽しいと思います。</p>
</div>
hayataka2049
【python】引数のデフォルト値は定義時評価なので注意
hatenablog://entry/10257846132664842412
2018-11-06T01:55:06+09:00
2018-11-28T19:07:51+09:00 はじめに pythonでは関数の引数にデフォルト値を設定することができます。 この機能を使うと、引数が与えられなかったときの挙動を定義することができ、とても便利です。 >>> def f(x="hoge"): ... print(x) ... >>> f("aiu") aiu >>> f(x="aiu") aiu >>> f() hoge ただし、デフォルト値にlistやdictなどのmutableな型を使うと容易にハマります。それについて説明します。 ハマる例 デフォルト値に空のリストを追加したとします。 >>> def g(x, l=[]): ... l.append(x) ... ret…
<div class="section">
<h3>はじめに</h3>
<p> pythonでは関数の引数にデフォルト値を設定することができます。</p><p> この機能を使うと、引数が与えられなかったときの挙動を定義することができ、とても便利です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>(x=<span class="synConstant">"hoge"</span>):
... <span class="synIdentifier">print</span>(x)
...
>>> f(<span class="synConstant">"aiu"</span>)
aiu
>>> f(x=<span class="synConstant">"aiu"</span>)
aiu
>>> f()
hoge
</pre><p> ただし、デフォルト値にlistやdictなどのmutableな型を使うと容易にハマります。それについて説明します。</p>
</div>
<div class="section">
<h3>ハマる例</h3>
<p> デフォルト値に空のリストを追加したとします。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">g</span>(x, l=[]):
... l.append(x)
... <span class="synStatement">return</span> l
...
>>> g(<span class="synConstant">10</span>)
[<span class="synConstant">10</span>]
>>> g(<span class="synConstant">20</span>)
[<span class="synConstant">10</span>, <span class="synConstant">20</span>]
</pre><p> さっそくおかしな感じになっています。lが呼び出しのたびに更新されていないようです。そのせいで、前の値が残ってしまうようです。</p>
</div>
<div class="section">
<h3>検証</h3>
<p> listを継承したクラスを作り、コンストラクタが呼ばれるとメッセージを表示するようにします。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">class</span> <span class="synIdentifier">mylist</span>(<span class="synIdentifier">list</span>):
... <span class="synStatement">def</span> <span class="synIdentifier">__init__</span>(self, *args, **kargs):
... <span class="synIdentifier">print</span>(<span class="synConstant">"__init__ of mylist"</span>)
... <span class="synIdentifier">list</span>.__init__(self, *args, **kargs)
...
>>> l = mylist()
__init__ of mylist
>>> l
[]
>>> l.append(<span class="synConstant">1</span>)
>>> l
[<span class="synConstant">1</span>]
</pre><p> __init__にメッセージを挟んだ以外は何もいじっていないので、元のlistと同様に扱えます。</p><p> このインスタンスをデフォルト値にしてみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">h</span>(x, l=mylist()):
... l.append(x)
... <span class="synStatement">return</span> l
...
__init__ of mylist
>>> h(<span class="synConstant">10</span>)
[<span class="synConstant">10</span>]
>>> h(<span class="synConstant">20</span>)
[<span class="synConstant">10</span>, <span class="synConstant">20</span>]
</pre><p> なんということでしょう、defが実行されたタイミングで評価されて、それっきりです。</p>
</div>
<div class="section">
<h3>解説と対策</h3>
<p> これは、実はドキュメントにも説明がある事項です。</p>
<blockquote>
<p>重要な警告: デフォルト値は 1 度だけしか評価されません。デフォルト値がリストや辞書のような変更可能なオブジェクトの時にはその影響がでます。</p><p><a href="https://docs.python.jp/3/tutorial/controlflow.html#default-argument-values">4. その他の制御フローツール — Python 3.6.5 ドキュメント</a></p>
</blockquote>
<p> 要するに「仕様」ということですね。</p><p> 対策は、これも上のページに書いてあることですが、デフォルト値はNoneにしておき、都度関数の中でインスタンス化することです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">i</span>(x, l=<span class="synIdentifier">None</span>): <span class="synComment"># ここは定義時評価</span>
... <span class="synStatement">if</span> l <span class="synStatement">is</span> <span class="synIdentifier">None</span>: <span class="synComment"># ここは実行時評価</span>
... l = []
... l.append(x)
... <span class="synStatement">return</span> l
...
>>> i(<span class="synConstant">10</span>)
[<span class="synConstant">10</span>]
>>> i(<span class="synConstant">20</span>)
[<span class="synConstant">20</span>]
>>> i(<span class="synConstant">10</span>, l=[-<span class="synConstant">10</span>, <span class="synConstant">0</span>])
[-<span class="synConstant">10</span>, <span class="synConstant">0</span>, <span class="synConstant">10</span>]
</pre><p> わかってしまえば簡単な話ですが、気づかないと大変なミスをやらかすので注意してください。</p><p> 逆に、これを利用してクロージャもどきとして使ったり、難読コードを書くことも可能です(やらないけど)。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> 再帰的にリストを処理するような関数を書くとき、def f(l=[]):のように書きたくなってしまいますが、バグを産むので注意してください。<br />
</p>
</div>
hayataka2049
【python】missing 1 required positional argument: 'self'などの対処法
hatenablog://entry/10257846132646365636
2018-10-05T23:34:18+09:00
2019-06-16T18:54:25+09:00 はじめに pythonに不慣れな方は、よくタイトルのようなエラーを見かけると思います。 実際には、このエラーはTypeErrorで、全体は以下のようなものです。 TypeError: メソッドの名前 missing 1 required positional argument: 'self' では、どうしてこのエラーは出るのでしょうか。そして、どうすれば良いのでしょうか。 簡単に解説していきます。なおpython3を使っていることを前提とします。 クラスをインスタンス化していない このエラーは、なんとなくエラーの文面だけ見ると、引数を渡してあげれば良いのかな? というような気がします。実際、引…
<div class="section">
<h3>はじめに</h3>
<p> pythonに不慣れな方は、よくタイトルのようなエラーを見かけると思います。</p><p> 実際には、このエラーはTypeErrorで、全体は以下のようなものです。</p>
<pre class="code" data-lang="" data-unlink>TypeError: メソッドの名前 missing 1 required positional argument: 'self'</pre><p> では、どうしてこのエラーは出るのでしょうか。そして、どうすれば良いのでしょうか。</p><p> 簡単に解説していきます。なおpython3を使っていることを前提とします。</p>
</div>
<div class="section">
<h3>クラスをインスタンス化していない</h3>
<p> このエラーは、なんとなくエラーの文面だけ見ると、引数を渡してあげれば良いのかな? というような気がします。実際、引数を要求する関数を引数無しで呼び出すとほぼ同じエラーが出ます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>(a):
... <span class="synStatement">pass</span>
...
>>> f()
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: f() missing <span class="synConstant">1</span> required positional argument: <span class="synConstant">'a'</span>
</pre><p> だけど、ライブラリやモジュールのドキュメントをのぞいてもselfという引数に関する記載はなかったりします</p><p> 実は、このエラーにはpythonのクラスの言語仕様が関係しています。</p><p> pythonでは、通常のメソッドでは第一引数にオブジェクトのインスタンスそのもの(Javaでいうthis)が渡されてやってくる、という仕様になっています。</p><p> たとえば次のようなコードを試しに実行してみます。</p><p><b>test_hoge.py</b></p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>():
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>)
h = Hoge()
h.print_hoge()
</pre><p><b>実行結果</b></p>
<pre class="code" data-lang="" data-unlink>Traceback (most recent call last):
File "test_hoge.py", line 6, in <module>
h.print_hoge()
TypeError: print_hoge() takes 0 positional arguments but 1 was given</pre><p> print_hoge()は1つも引数を取らない関数として定義されているのに、1つ渡されています、というエラーが出ます。ここで渡されているものがインスタンス自身です。</p><p> インスタンス自身を受け取る名前は、実はどんな名前でも構わないのですが、慣習的にpythonでは「self」を使います。さっきのコードをselfを受け取るように書き換えましょう。</p><p><b>test_hoge.py</b></p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>(self):
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>)
h = Hoge()
h.print_hoge()
</pre><p><b>実行結果</b></p>
<pre class="code" data-lang="" data-unlink>hoge</pre><p> 無事実行できるようになりました。よかったね、という話なのですが、これを今度はインスタンス化しないで呼んでみましょう。</p><p><b>test_hoge.py</b></p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>(self):
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>)
Hoge.print_hoge()
</pre><p><b>実行結果</b></p>
<pre class="code" data-lang="" data-unlink>Traceback (most recent call last):
File "test_hoge.py", line 5, in <module>
Hoge.print_hoge()
TypeError: print_hoge() missing 1 required positional argument: 'self'</pre><p> はい、エラーが再現しました。このような状況になっていた訳ですね。</p><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p></p>
</div>
<div class="section">
<h3>対策</h3>
<p> このエラーに遭遇した場合、大抵はインスタンス化して使うべきクラスを不適切にインスタンス化せずに使っていたというケースだと思います。インスタンス化してあげましょう。上の例の、ちゃんと実行できるコードを再掲します。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>(self):
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>)
h = Hoge() <span class="synComment"># この行でインスタンス化</span>
h.print_hoge()
</pre><p> ただし、自作クラスで「インスタンス自身なんか処理に使わないから、クラスのまま呼べるようにしたい」という場合もあると思います。その場合は、@staticmethodとメソッド宣言の前に付けてあげるとスタティックメソッドを定義できます。<br />
(「@staticmethod」そのものは特別な記述子とかではなく、pythonでは一般的に使われるデコレータという機能で実装されています。詳細はドキュメントやヘルプを参照してください)</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synPreProc">@</span><span class="synIdentifier">staticmethod</span> <span class="synComment"># これによってスタティックメソッドになる</span>
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>():
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>)
Hoge.print_hoge()
</pre><p> ただし、これはつまるところただの関数と何も違いません。スタティックメソッドを使うメリットはかなり限られた場面にしかありません。だいたい、pythonではクラスを入れ物的に使うということをあまりしません(通常はトップレベル関数として定義し、モジュールで管理する)。本当にそのスタティックメソッド必要? と考え直す視点は常に持っておいた方が良いです。</p><p> なお、似たようなデコレータに@classmethodというというものもありますが、これは第一引数に「クラス自身」が渡されるというもので、スタティックメソッドとはまた別物です。間違えないようにしてください。</p>
</div>
<div class="section">
<h3>色々なパターン</h3>
<p> これに似ているパターンが幾つかあると思うので、カバーしておきます。</p>
<div class="section">
<h4>引数を受け取るメソッド</h4>
<p> このようなケースです。</p><p><b>test_hoge.py</b></p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>(s):
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>, s)
h = Hoge()
h.print_hoge(<span class="synConstant">"fuga"</span>)
</pre><p><b>実行結果</b></p>
<pre class="code" data-lang="" data-unlink>Traceback (most recent call last):
File "test_hoge.py", line 6, in <module>
h.print_hoge("fuga")
TypeError: print_hoge() takes 1 positional argument but 2 were given</pre><p> この記事をここまで読んできた皆さんは、もうどうすれば良いかおわかりだと思います。</p><p><b>正しいコード</b></p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">class</span> <span class="synIdentifier">Hoge</span>:
<span class="synStatement">def</span> <span class="synIdentifier">print_hoge</span>(self, s):
<span class="synIdentifier">print</span>(<span class="synConstant">"hoge"</span>, s)
h = Hoge()
h.print_hoge(<span class="synConstant">"fuga"</span>)
</pre>
</div>
</div>
<div class="section">
<h3>まとめ</h3>
<p> pythonのクラス周りは他の言語と比べてちょっと独特ですが、「通常のメソッドではインスタンス自身が暗黙的に第一引数に渡される」というルールさえ理解してしまえば、むしろわかりやすいと言えます。「thisが自動的にインスタンス自身を表すキーワードとして機能する」という魔法がない分、一貫性があってすっきりしているからです。</p><br />
<p> ただ、理解するまではタイトルのようなエラーにはよく遭遇すると思います。早く覚えてこんなエラーは出さないようにしましょう。</p>
</div>
hayataka2049
python環境構築まとめ
hatenablog://entry/17391345971651150779
2018-06-05T03:46:39+09:00
2019-09-04T06:07:15+09:00 pythonの環境構築に悩む人たちのために、環境構築についてまとめておきます。
<div class="section">
<h3 id="概要">概要</h3>
<p> pythonの環境構築に悩む人たちのために、環境構築についてまとめておきます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#概要">概要</a></li>
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#覚えておいてほしい大切なこと">覚えておいてほしい大切なこと</a></li>
<li><a href="#pythonをやるのに向いたOS">pythonをやるのに向いたOS</a><ul>
<li><a href="#windows">windows</a></li>
<li><a href="#Mac-OS">Mac OS</a></li>
<li><a href="#linux系">linux系</a></li>
<li><a href="#その他のOS">その他のOS</a></li>
<li><a href="#Web上実行環境">Web上実行環境</a></li>
<li><a href="#結論">結論</a></li>
</ul>
</li>
<li><a href="#生のシステムのpythonを使うシステムに直接インストールしてそのまま使う">生のシステムのpythonを使う(システムに直接インストールしてそのまま使う)</a></li>
<li><a href="#パッケージマネージャについて">パッケージマネージャについて</a></li>
<li><a href="#仮想環境編">仮想環境編</a><ul>
<li><a href="#定石">定石</a></li>
<li><a href="#venv">venv</a></li>
<li><a href="#virtualenv">virtualenv</a></li>
<li><a href="#pyenv">pyenv</a></li>
<li><a href="#anaconda">anaconda</a></li>
<li><a href="#その他の仮想環境">その他の仮想環境</a><ul>
<li><a href="#virtualenvwrapper">virtualenvwrapper</a></li>
<li><a href="#pyenv-virtualenv">pyenv-virtualenv</a></li>
<li><a href="#pyvenv">pyvenv</a></li>
<li><a href="#conda">conda</a></li>
<li><a href="#pipenv">pipenv</a></li>
</ul>
</li>
<li><a href="#結論-1">結論</a></li>
</ul>
</li>
<li><a href="#まとめ">まとめ</a></li>
</ul><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p></p>
</div>
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> pythonは最近よく流行っているスクリプト言語ですが、残念ながら環境構築のとっつきづらさは他の言語の比ではないと思います<a href="#f-4cb90974" name="fn-4cb90974" title="もちろん、探せばもっとひどい言語はあるだろうけど。スクリプト言語の平均よりは明らかに悪いという程度の意味">*1</a>。初心者が変な環境を作ってトラブルの元になる・・・というのもよくあることなので、この際まとめておこうと思いました。</p><p> さて、まず大前提として、メインで使うpythonはpython3系にします。今からpython2系を学習する意味はほとんどないからです。</p><p> また、この記事では環境構築に際して使う各ツールの操作手順については述べません。それぞれの構築方法についてご自身で検索していただければ良いと思います。日本語Web圏におおむね十分な情報があります<a href="#f-f1b3edba" name="fn-f1b3edba" title="信用に足る記事があるかはまた別ですが・・・新し目でまともそうなものを選ぼう、としか言えません">*2</a>。</p>
</div>
<div class="section">
<h3 id="覚えておいてほしい大切なこと">覚えておいてほしい大切なこと</h3>
<p> <span style="font-size: 150%">「自分でよくわからない/把握できない環境は作らない」</span></p><p> これが基本です。</p><p> ネットには無責任に「○○が良いですよ~」と書いてしまう人はたくさんいます。それを真に受けて、使い方もよくわからないツールを落としてきて入れ、記事に書いてある操作手順通りにインストールし、インストールはできたけど使用開始とほぼ同時に早速ハマる……というどうしようもないことをする初心者の方も一定数います。</p><p> むやみにツールを入れないでください。入れるなら、入れる前に目的と使い方くらいは理解しておきましょう。そうしないと扱いきれません。</p><p> 実際、何も知らない初心者が、ネットの記事に書いてあるコマンドをコピペしてpyenvやanacondaを導入し、扱いきれなくて挫折する……という悲劇がたくさん起きています。</p><p><a href="https://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7">pyenvが必要かどうかフローチャート - Qiita</a><br />
<a href="http://www.zopfco.de/entry/2017/04/03/233811">Pythonの環境管理ツール良し悪し - Zopfcode</a></p><p><a href="https://teratail.com/search?q=python+import+error">python import errorに関連する質問・回答の検索結果(1ページ目)|teratail</a></p><p> できるだけそういう事態になりそうな展開は回避し、単純な環境で構築してから他のツールに手を出した方が、失敗しづらいはずです。</p>
</div>
<div class="section">
<h3 id="pythonをやるのに向いたOS">pythonをやるのに向いたOS</h3>
<p> ご存知の通り、pythonはマルチプラットフォームなスクリプト言語です。しかしどうしても、OSによって向き不向きがあるようです。</p>
<div class="section">
<h4 id="windows">windows</h4>
<p><b> おすすめ度:☆3</b><br />
率直に言って、おすすめできません。windowsだと余計な苦労が増えます。上級者は普通に使いこなせると思いますが、初心者向けではありません。</p><p> それでも一時期に比べれば、wheelで入るライブラリも増えたし、UNIXに依存するライブラリというのもないので、簡単になった方です。エラーメッセージが出たときに、根気よく検索して対処できる人向けです。</p><p> Bash on Ubuntu on Windowsは使ったことがないのでわかりません。ごめんなさい。</p>
</div>
<div class="section">
<h4 id="Mac-OS">Mac OS</h4>
<p><b> おすすめ度:☆2</b><br />
これも、あまりおすすめしません。使い勝手自体はwindowsよりはマシですが、Web情報はwindowsより少なかったりします。Mac特有のハマり方があるので<a href="#f-0bfd3fd5" name="fn-0bfd3fd5" title="というかライブラリとかがMacまでしっかり考えて作られていない・・・Macのパッケージマネージャもいまいちpythonに優しくない・・・">*3</a>、少ない英語情報を必死に探って自己解決できる人でないとしんどいと思います。</p><p> 初心者は避けた方が無難です。「pythonでプログラミングを勉強したい!」と思ったとき、いきなりMacを買う理由はないということです。</p>
</div>
<div class="section">
<h4 id="linux系">linux系</h4>
<p><b> おすすめ度:☆4</b><br />
windows, macよりはおすすめです。初心者はlinux系を使えば良いと思います(pythonをやるついでにlinuxの勉強も出来て一石二鳥です)。ただ、まったく経験がないと敷居が高いのも事実です。</p><p> windowsマシンの上に仮想マシン(後で述べるpython仮想環境とは別物です)で入れれば、環境ぶっ壊しちゃっても作り直せば良いだけで、とても気楽です。</p><p> linux系にはディストリビューションがいろいろありますが、デファクトスタンダードはubuntuです。このことは、「ubuntu python 環境構築」とか検索すれば幾らでも記事が出てくる、ということを意味します。他のディストリビューションはそこまで強くないので、手を出すのは中級者以上になってからで良いと思います。</p>
</div>
<div class="section">
<h4 id="その他のOS">その他のOS</h4>
<p> そんなの使いたがる人はこの記事を読んでいないと思いますが・・・。</p><p> FreeBSD使いの人はいるかもしれませんね。頑張ってください。応援しています。</p><p> Android、iPhoneなどのスマホ・タブレットに入れたがる人も時々います。対応した実装もあるといえばあるのですが、あまり使いやすいものではありませんから、素直にノートパソコンを買った方が有利です。</p>
</div>
<div class="section">
<h4 id="Web上実行環境">Web上実行環境</h4>
<p> OSではありませんが、実はWeb上でpython(に限らずいろいろな言語)を実行できるサービスがあります。たとえばWandboxなんてどうでしょう。</p><p><a href="https://wandbox.org/">[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ</a></p><p> こういった環境は、勉強とか、ちょっとした動作チェックには重宝します。それ以上でもそれ以下でもないのですが、とりあえず取っ掛かりとしてはありです。簡単に試してみたい、というときはここに入門書の内容などを打ち込んでいくと良いと思います。</p>
</div>
<div class="section">
<h4 id="結論">結論</h4>
<p> 今使ってるwindowsマシンにVirtualBoxかVMWare Playerを落としてきて、ubuntuを入れましょう。</p>
</div>
</div>
<div class="section">
<h3 id="生のシステムのpythonを使うシステムに直接インストールしてそのまま使う">生のシステムのpythonを使う(システムに直接インストールしてそのまま使う)</h3>
<p> さて、ubuntuを入れた方はターミナルで「python」と打つといきなりpythonが立ち上がると思います。今どきのUNIX系OS(事実上linux+Mac)であれば最初からpythonが入っているので、それが使える訳です。</p><p> これをそのまま使う、というのは選択肢の一つです。ただ、2018年6月現在では、まだシステムデフォルトのpythonがpython2系のシステムがほとんどだと思います。できればpython3系を使いたいので、これはボツです。もしデフォルトがpython3系のシステムにあたったら、しばらくはそれを使って基本的な構文や機能の勉強をやれば良いと思います。</p><p> システムのpythonがpython2系だけどpython3系を使いたい、という場合、システムにpython3をインストールすることができます。この場合、python2を消したり、置き換えたりはせず、python2とpython3を共存させるようにするのが無難です。python2はシステムの中で使っているプログラムがいろいろあるので、消してしまうとOSがまともに動かなくなります。</p><p> また、python2系がデフォルトだけど、python3系も一緒に入っている、というシステムもあります(最近のubuntuはそうだったはずです)。これはしめたもので、そのまま使えばインストールの手間が省けますし、インストールで事故る確率も減らせます。ただし、pipなどは自分で入れてやる必要があったりするようです<a href="#f-29db416a" name="fn-29db416a" title="参考:[https://www.python.jp/install/ubuntu/index.html:title]">*4</a>。</p><p> おそらく、python2とpython3が共存する環境では、「python」とターミナルに打ち込むと平然とpython2が立ち上がってくるはずです。そういうときは、慌てずに「python3」と打ち込みます。そうすると(ちゃんとインストールされていれば)python3が立ち上がるので、使うことができます。</p><p> また、パッケージマネージャのpipも、(インストールされていれば)「pip」と打つとpython2に対応するpipが立ち上がってくるはずです。同様にpip3と打てばpip3が立ち上がるので、こちらを使います。パッケージマネージャについては次章で詳しく述べます。</p>
</div>
<div class="section">
<h3 id="パッケージマネージャについて">パッケージマネージャについて</h3>
<p> パッケージマネージャは、主に外部ライブラリなどを管理するためのツールです。</p><p> 2018年6月現在では、間違いなくpipがスタンダードです。大抵のものがpipで入ります。というか、pipで入らないものは他のパッケージマネージャでも扱えないので、pip以外を使う意味がまったくありません(というか、そもそも存在しているの? レベル)。</p><p> 例外として、anaconda(あとで述べます)を使う人はcondaというanaconda独自のツールを使う必要があります。</p><p> また、pipで扱えない、ソースコードで配布されているだけのパッケージも存在します。そういうものはsetup.pyなど<a href="#f-2e70dd36" name="fn-2e70dd36" title="distutilsなどという。参考:[https://docs.python.jp/3/library/distutils.html:title]">*5</a>を使って環境に入れます。大抵はパッケージのreadmeとかで親切に説明してくれているので、その通りにやれば良いです。</p><p> さて、pipと一口に言っても、実はコマンドの打ち方はいろいろあります。</p><p> もしインストール手順などで「pip install ○○」と指示されていたら、それは「自分の環境に合った方法でpipを使って入れろ」ってことです。この通りコマンドを打っても、ほぼ入りません。</p><p> 以下に大まかな傾向を書いておきますが、あくまでも参考情報です。極論すれば、pip自体のありかがわかって、権限の問題が解決できれば、コマンドの細かい違いはどうでも良いことです。でも、使い分ける上ではこれらは重要です。</p>
<ul>
<li>sudo pip</li>
</ul><p> これは普通はシステムのpythonにインストールする場合です(そういう認識で構いません。普通にaptとかでインストールすると権限が必要な場所に入ると思います)。</p><p> sudoはunix系のコマンドであり、windowsだとsudoはないので、なにか違う方法で同様のことを実現する必要があります<a href="#f-f41a9ffb" name="fn-f41a9ffb" title="もしかしたらただのpipかもしれないし、管理者権限でやる必要があるかもしれない。インストール先等で変わってきます">*6</a>。また、python2とpython3を使い分けていれば「sudo pip3」というのもありえます。</p>
<ul>
<li>pip</li>
</ul><p> ただのpip。仮想環境を使うと、これで済むと思います。逆に、仮想環境を使っていないとただのpipで済む場面はあまりないとも言えます。</p>
<ul>
<li>pip2、pip3</li>
</ul><p> システムに異なるバリエーションのpythonを複数インストールして、仮想環境等を使わずに使い分ける場合、区別のために数字付きのpipコマンドを使うことになります。インストール先にもよりますが、sudoを付ける必要があるかもしれません。また、python3.5とpython3.6を使い分けたい、という場合、pip3.5とpip3.6を使い分けます。面倒くさいですね。</p><p> 自分が使っているpythonに入れるにはどれを使えば良いのか、把握しておきましょう。</p><p>「pipでインストールしたのに使えません!」<br />
「違うpythonに入れてるみたいですね!」</p><p> というやり取りは、割と頻繁に目にします。</p>
</div>
<div class="section">
<h3 id="仮想環境編">仮想環境編</h3>
<p> この章はあんまり書きたくはないのですが・・・。</p><p> システムのpython(インストールしたままのpython)を使うと、ミスって環境をぶっ壊してしまうリスクがあります。管理もいろいろ面倒です。そこで、仮想環境を使うと良いですよ、ということがいろいろなところで言われています<a href="#f-3bf5c395" name="fn-3bf5c395" title="仮想環境とは何ぞや、という基本的なことについてはこちらを参照:[https://www.python.jp/install/windows/virtualenv.html:title]">*7</a>。</p><p> ぶっちゃけた話、仮想環境を作るのは初心者にはコストが高いです。ネットで調べてその通り打ち込むだけといえば、その通りなのですが、それでもけっこうハマりどころがあります。なので、入門書程度の内容をやっている間は、仮想環境は要らないと思います。pipでライブラリをがつがつ入れたくなったときに、検討してみてください。</p><p> また、げんなりすることに、仮想環境は何種類もあります。互換性もないし、使い方も違うしで、どれを選べば良いのかよくわかりませんよね。安心してください。ある程度定石があります。</p>
<div class="section">
<h4 id="定石">定石</h4>
<p> <b>venvかvirtualenvのどちらかを使う。</b></p><p> これで良いと思います。それぞれについては追って説明します。</p>
</div>
<div class="section">
<h4 id="venv">venv</h4>
<p><b> おすすめ度:☆5</b> <br />
最近のスタンダードです。が、実は次節のvirtualenvがpython3.3で標準モジュールとして取り入れられたものと解釈して、ほとんど間違いありません。</p><p> venvはシステムにインストールされているpython3.3以上に依存します。というか、python3.3以上のpythonが環境に入っていれば、自動的に使えます(よほど変な環境構築をしていない限り)。なので、最近のubuntuならこれを使えば良いですし、自分でpython3を入れてvenv、というのもありです。</p><p> 特に使いづらいとかもなく、普通に使えます。</p>
</div>
<div class="section">
<h4 id="virtualenv">virtualenv</h4>
<p><b> おすすめ度:☆4</b> <br />
一昔前のスタンダードでした。venvがpython3.3に入って以降は存在意義が薄くなっていますが、システムにpython2系しかなく、というかそもそも使うのがpython2系だけです、みたいな状況で使うのは今でもありです。</p><p> これは外部ライブラリなので、pipでインストールする必要があります。</p><p> また、venvでできなくてvirtualenvでできることとして、pythonインタプリタ本体のバージョンを切り替える操作があります。複数のバージョンを共存させたい場合は、システムのpythonにvirtualenvを入れ、あとは好きなところに複数バージョンのpythonを入れ、仮想環境を作るといった使い方ができます。</p>
</div>
<div class="section">
<h4 id="pyenv">pyenv</h4>
<p><b> おすすめ度:☆3</b> <br />
一昔前にちょっと流行っていました。未だに記事をたくさん見かけますが、今から使いたいかと言われると、正直イヤです。venvでいいと思います。</p><p> 長所はpythonに依存しないことです。そのかわり、シェルスクリプトに依存します。当然windowsでは動きません。これを欠点と呼ぶかは悩みますが(記事の最初でwindowsは斬って捨ててる訳だし)、とにかくそういう特徴があります。</p>
</div>
<div class="section">
<h4 id="anaconda">anaconda</h4>
<p><b> おすすめ度:☆3</b><br />
anacondaは有名ですね。環境構築の手間が省けて、統計や機械学習用のライブラリまで丸ごと入れられる、という奴です。しかし、個人的には☆3を付けます。</p><p> anacondaの最大の利点は、condaという独自のパッケージ管理システムを持つことで、オリジナルのpipと比べてもパッケージのインストールや仮想環境の操作が容易であることです。</p><p> 一方、欠点は、パッケージ管理周りがpipとはまったく別物なので、anaconda独自のハマりどころがたくさんある、ということです。ハマると面倒ですし、ちょっとマイナーな話題だとWebに情報があるかも怪しい、githubにissue上がっててもcloseしないまま何ヶ月も放置されてる、といった具合です。</p><p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Fonoz000.hatenablog.com%2Fentry%2F2018%2F02%2F11%2F142347" title="condaとpip:混ぜるな危険 - onoz000’s blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="http://onoz000.hatenablog.com/entry/2018/02/11/142347">onoz000.hatenablog.com</a></cite></p><br />
<p> 端的にいうと、確かにanacondaの開発は頑張ってはいるけど、パーフェクトというほどの完成度ではないので、anacondaを使うと問題がややこしくなるケースというのが一定数存在します。どう判断するかは人によりますが、私は最初からpipを使った方がマシだと思います。</p><p> それでも、環境構築のことは何も知らない人が、手軽に統計とか機械学習を試すためにあると思えは、anacondaは弁護できます。実際、numpyとかscipyとかcythonとかmatplotlibとかsklearnとかを自分でインストールしようとすると、それはそれで一筋縄ではいかないので、「その辺のライブラリをさっさと使いたいんです、授業が/研究が/研修が済んだらもうpythonなんか触らないんです」という状況であれば、anacondaはありです。</p><p> 逆に、長くpythonを使い続ける、いろいろなライブラリを入れたりして愛用していく、のであれば、やめた方が良いと個人的には思います。多少手間がかかっても、自分で普通に環境構築して、pipを使ったインストールに慣れた方が良いです。</p><p> 申し訳ありませんが、そういう認識です。</p>
</div>
<div class="section">
<h4 id="その他の仮想環境">その他の仮想環境</h4>
<p> 採点はしません。</p>
<div class="section">
<h5 id="virtualenvwrapper">virtualenvwrapper</h5>
<p> 名前の通り、virtualenvのラッパーです。使い勝手が改善されているらしいですが、使ったことがないのでわかりません。ごめんなさい。</p><p> 生virtualenvを使いづらいと感じたことは特にないので、これを使うならvirtualenvで良いと思います。まあ、最終的には好みの問題ですが、多少コマンドが打ちやすくなるとかのために不安要素を増やすかというと、Noです。</p>
</div>
<div class="section">
<h5 id="pyenv-virtualenv">pyenv-virtualenv</h5>
<p> pyenvでvirtualenvwrapperに相当するものです。これも恐らく要らないと思います。</p>
</div>
<div class="section">
<h5 id="pyvenv">pyvenv</h5>
<p> venvの別名。あまりにpyenvと紛らわしいため(だと思います)、非推奨にされたそうです。</p><p><a href="https://docs.python.jp/3/library/venv.html">venv --- 仮想環境の作成 — Python 3.7.4 ドキュメント</a><br />
</p>
</div>
<div class="section">
<h5 id="conda">conda</h5>
<p> これはanacondaの管理ツールです。「conad install ○○」とかやって使うそうです。見た目はpipっぽいですが、中身はまったくの別物。</p>
</div>
<div class="section">
<h5 id="pipenv">pipenv</h5>
<p> これは比較的新し目のツールです。pipとvirtualenvを統合したという、ちょっと触れ込みだけでは想像がつかないもの。まだ試していませんが、そのうち試してみます。</p>
</div>
</div>
<div class="section">
<h4 id="結論-1">結論</h4>
<p> <b>venvかvirtualenvのどちらかを使う。</b></p><p> 最初に言いたいことはまとめたので、特に追加で言うことはないです。</p>
</div>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> この記事に書いてあることをどこまで信頼するかは、あなた自身で決めてください。私は何も保証しません。それはあなたの責任です。</p><p> この記事の内容自体はそんなに外していないとは思います。しかし、人によって考え方の違いもありますし、環境構築に正解なんてありません。究極的には動けば良いのです。せいぜい一つの指針にしてください。</p><p> あと、間違いにお気づきになられた識者の方は、ご遠慮無くご指摘いただけると大変助かります。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-4cb90974" name="f-4cb90974" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">もちろん、探せばもっとひどい言語はあるだろうけど。スクリプト言語の平均よりは明らかに悪いという程度の意味</span></p>
<p class="footnote"><a href="#fn-f1b3edba" name="f-f1b3edba" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">信用に足る記事があるかはまた別ですが・・・新し目でまともそうなものを選ぼう、としか言えません</span></p>
<p class="footnote"><a href="#fn-0bfd3fd5" name="f-0bfd3fd5" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">というかライブラリとかがMacまでしっかり考えて作られていない・・・Macのパッケージマネージャもいまいちpythonに優しくない・・・</span></p>
<p class="footnote"><a href="#fn-29db416a" name="f-29db416a" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">参考:<a href="https://www.python.jp/install/ubuntu/index.html">Ubuntu環境のPython - python.jp</a></span></p>
<p class="footnote"><a href="#fn-2e70dd36" name="f-2e70dd36" class="footnote-number">*5</a><span class="footnote-delimiter">:</span><span class="footnote-text">distutilsなどという。参考:<a href="https://docs.python.jp/3/library/distutils.html">distutils --- Python モジュールの構築とインストール — Python 3.7.4 ドキュメント</a></span></p>
<p class="footnote"><a href="#fn-f41a9ffb" name="f-f41a9ffb" class="footnote-number">*6</a><span class="footnote-delimiter">:</span><span class="footnote-text">もしかしたらただのpipかもしれないし、管理者権限でやる必要があるかもしれない。インストール先等で変わってきます</span></p>
<p class="footnote"><a href="#fn-3bf5c395" name="f-3bf5c395" class="footnote-number">*7</a><span class="footnote-delimiter">:</span><span class="footnote-text">仮想環境とは何ぞや、という基本的なことについてはこちらを参照:<a href="https://www.python.jp/install/windows/virtualenv.html">仮想環境 - python.jp</a></span></p>
</div>
hayataka2049
【python】listをforループで回してremoveしたら思い通りにならない
hatenablog://entry/17391345971650354668
2018-06-02T16:34:15+09:00
2019-06-01T20:37:52+09:00 forループでループ対象のリストから要素を除去してしまったりすると、まったく想定と違った結果になってしまうことがあります。pythonプログラミングを始めたばかりの人がよくハマるネタです。
<p> <br />
forループでループ対象のリストから要素を削除してしまったりすると、まったく想定と違った結果になってしまうことがあります。</p><p> pythonプログラミングを始めたばかりの人がよくハマるトラブルです。日本語Web圏にはイマイチよくまとまった記事がないようなので、まとめておきます。</p><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><br />
<p></p>
<div class="section">
<h3>問題の概要</h3>
<p> たとえば、0から9のリストから偶数だけ取り出そうとして、こんなコードを書いてみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... <span class="synStatement">if</span> x%<span class="synConstant">2</span> != <span class="synConstant">0</span>:
... lst.remove(x)
...
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">2</span>, <span class="synConstant">4</span>, <span class="synConstant">6</span>, <span class="synConstant">8</span>]
</pre><p> 一見すると上手く動いているようです。調子に乗って、今度は3の倍数を取り出そうとしてみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... <span class="synStatement">if</span> x%<span class="synConstant">3</span> != <span class="synConstant">0</span>:
... lst.remove(x)
...
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>, <span class="synConstant">8</span>, <span class="synConstant">9</span>]
</pre><p> おかしくなった。なぜでしょう? forがちゃんと動いていない? という感じで、ハマります。</p>
</div>
<div class="section">
<h3>原因</h3>
<p> こういうときはforのループごとにxに代入されている値をprintしてみると、どんなことになっているのかよくわかります。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... <span class="synIdentifier">print</span>(x)
... <span class="synStatement">if</span> x%<span class="synConstant">2</span> != <span class="synConstant">0</span>:
... lst.remove(x)
...
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">3</span>
<span class="synConstant">5</span>
<span class="synConstant">7</span>
<span class="synConstant">9</span>
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">2</span>, <span class="synConstant">4</span>, <span class="synConstant">6</span>, <span class="synConstant">8</span>]
>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... <span class="synIdentifier">print</span>(x)
... <span class="synStatement">if</span> x%<span class="synConstant">3</span> != <span class="synConstant">0</span>:
... lst.remove(x)
...
<span class="synConstant">0</span>
<span class="synConstant">1</span>
<span class="synConstant">3</span>
<span class="synConstant">4</span>
<span class="synConstant">6</span>
<span class="synConstant">7</span>
<span class="synConstant">9</span>
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>, <span class="synConstant">8</span>, <span class="synConstant">9</span>]
</pre><p> なんてことでしょう、ちゃんと動いていない!</p><p> ・・・これはドキュメントにも書いてある、pythonのれっきとした仕様です。</p>
<blockquote>
<p>注釈 ループ中でのシーケンスの変更には微妙な問題があります (これはミュータブルなシーケンス、すなわちリストなどでのみ起こります)。どの要素が次に使われるかを追跡するために、内部的なカウンタが使われており、このカウンタは反復のたびに加算されます。このカウンタがシーケンスの長さに達すると、ループは終了します。<b><u>このことから、スイート中でシーケンスから現在の (または以前の) 要素を除去すると、(次の要素のインデクスは、すでに取り扱った現在の要素のインデクスになるために) 次の要素が飛ばされることになります。</u></b>(※筆者強調) 同様に、スイート中でシーケンス中の現在の要素以前に要素を挿入すると、現在の要素がループの次の週で再度扱われることになります。こうした仕様は、厄介なバグにつながります。</p>
</blockquote>
<p><a href="https://docs.python.jp/3/reference/compound_stmts.html#the-for-statement">8. 複合文 (compound statement) — Python 3.7.3 ドキュメント</a></p><p> インタプリタの内部では、カウンタで管理しているんですね。削除しようとして失敗するのは、それが原因です。</p>
</div>
<div class="section">
<h3>回避策</h3>
<p> とりあえず、公式ドキュメントにはこのような方法が記載されています。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">for</span> x <span class="synStatement">in</span> a[:]:
<span class="synStatement">if</span> x < <span class="synConstant">0</span>: a.remove(x)
</pre><p> ここで[:]というのは範囲指定なしのスライスです。これはこのように機能します。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> lst[:]
[<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>, <span class="synConstant">7</span>, <span class="synConstant">8</span>, <span class="synConstant">9</span>]
</pre><p> まったく無意味な気がしますが、実は両者は別のオブジェクトになっています。</p><p> <a href="https://docs.python.jp/3/library/functions.html#id">id()関数</a>で確認してみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">id</span>(lst)
<span class="synConstant">140603063055816</span>
>>> <span class="synIdentifier">id</span>(lst[:])
<span class="synConstant">140603063055048</span>
</pre><p> つまり、[:]は中身の同じコピーを作ることができます。こうすればループの対象のリストは変更されないので、問題なくループを回せるという訳ですね。</p><p> でもこういうコードはちょっとかっこ悪いので、内包表記を使った方がベターです。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> [x <span class="synStatement">for</span> x <span class="synStatement">in</span> lst <span class="synStatement">if</span> x%<span class="synConstant">3</span> == <span class="synConstant">0</span>] <span class="synComment"># 条件の反転に注意(残すものの条件を指定する)</span>
[<span class="synConstant">0</span>, <span class="synConstant">3</span>, <span class="synConstant">6</span>, <span class="synConstant">9</span>]
>>> lst <span class="synComment"># 上のコードは新しいリストを作る。元のリストは変わらない</span>
[<span class="synConstant">0</span>, <span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>, <span class="synConstant">4</span>, <span class="synConstant">5</span>, <span class="synConstant">6</span>, <span class="synConstant">7</span>, <span class="synConstant">8</span>, <span class="synConstant">9</span>]
>>> lst = [x <span class="synStatement">for</span> x <span class="synStatement">in</span> lst <span class="synStatement">if</span> x%<span class="synConstant">3</span> == <span class="synConstant">0</span>] <span class="synComment"># 再代入するとlstの値が変わる(ただし別のオブジェクトになる)</span>
>>> lst
[<span class="synConstant">0</span>, <span class="synConstant">3</span>, <span class="synConstant">6</span>, <span class="synConstant">9</span>]
</pre><p> どうしても同じオブジェクトをいじらないといけない、というシチュエーションも稀にありますが、そうでなければ内包表記などを使って新しくリストを作る、という発想で書いた方が簡単ですし、へんなバグも生みません。</p><p> 余談ですが、pythonではlist.remove()はあまり使わないメソッドです。他にもlist.pop()やlist.insert()などリストを操作するメソッドはたくさんありますが、これらをforループと組み合わせて書くような操作は、大抵の場合は内包表記などで代用できます。そして、その方が元のリストを壊さないので、バグが発生する余地が減ります<a href="#f-737eb989" name="fn-737eb989" title="この考え方はけっこう重要です。こういうオブジェクトの状態を変更する操作を破壊的操作といいますが、これはよく把握していないとわかりづらいバグを生みやすいです">*1</a><a href="#f-f97d29da" name="fn-f97d29da" title="他にも、特にlist.remove()はけっこうコストが高い(該当する要素が見つかるまで線形探索する)という理由があり、嫌われがちなメソッドです">*2</a>。</p><p> なので、初心者の方はあまりこういったものに頼らず、まずは内包表記から覚えるか、内包表記がとっつきづらければ空listにappendしていく方法を使うのが良いと思います。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>,<span class="synConstant">4</span>,<span class="synConstant">5</span>,<span class="synConstant">6</span>,<span class="synConstant">7</span>,<span class="synConstant">8</span>,<span class="synConstant">9</span>]
>>> result = []
>>> <span class="synStatement">for</span> x <span class="synStatement">in</span> lst:
... <span class="synStatement">if</span> x%<span class="synConstant">3</span> == <span class="synConstant">0</span>:
... result.append(x)
...
>>> result
[<span class="synConstant">0</span>, <span class="synConstant">3</span>, <span class="synConstant">6</span>, <span class="synConstant">9</span>]
</pre><p> これはappendで書く場合の例です。実はリスト内包表記とほとんど同じようなことをやっているのですが、最初はこちらの方が読みやすいかもしれません。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> pythonってけっこう直感的じゃない仕様があるので、「なんで!?」と思うこともままありますね。でも、どうせ慣れれば、そういう仕様は使わないで済ませられるようになってくるので、大丈夫です。</p><p> 基本的には「listをforループで回すときは、回しているlist自体はいじらないで処理する」ことを心がけるようにしましょう。この考え方が大切です。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-737eb989" name="f-737eb989" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">この考え方はけっこう重要です。こういうオブジェクトの状態を変更する操作を破壊的操作といいますが、これはよく把握していないとわかりづらいバグを生みやすいです</span></p>
<p class="footnote"><a href="#fn-f97d29da" name="f-f97d29da" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">他にも、特にlist.remove()はけっこうコストが高い(該当する要素が見つかるまで線形探索する)という理由があり、嫌われがちなメソッドです</span></p>
</div>
hayataka2049
【python】辞書で同じキーに複数の値を登録する
hatenablog://entry/17391345971637818602
2018-04-24T00:25:24+09:00
2018-11-27T23:38:58+09:00 ちょっとしたTips。 辞書(dict)は通常、一つのキーには一つの値しか登録できない。代入しても上書きされる。 >>> d = {} >>> d["hoge"] = 1 >>> d {'hoge': 1} >>> d["hoge"] = 2 >>> d {'hoge': 2} こういうときどうすれば良いのかというと、値をリスト等にしておいて、そのリストにappendしていけば良い。どのように使いたいかにもよるのだが、大抵はこれで用が済む。スポンサーリンク (adsbygoogle = window.adsbygoogle || []).push({}); defaultdictを使うと面倒な…
<p> ちょっとしたTips。</p><p> 辞書(dict)は通常、一つのキーには一つの値しか登録できない。代入しても上書きされる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {}
>>> d[<span class="synConstant">"hoge"</span>] = <span class="synConstant">1</span>
>>> d
{<span class="synConstant">'hoge'</span>: <span class="synConstant">1</span>}
>>> d[<span class="synConstant">"hoge"</span>] = <span class="synConstant">2</span>
>>> d
{<span class="synConstant">'hoge'</span>: <span class="synConstant">2</span>}
</pre><p> こういうときどうすれば良いのかというと、値をリスト等にしておいて、そのリストにappendしていけば良い。どのように使いたいかにもよるのだが、大抵はこれで用が済む。</p><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p> defaultdictを使うと面倒な初期化処理が省けて便利。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synPreProc">from</span> collections <span class="synPreProc">import</span> defaultdict
>>> d = defaultdict(<span class="synIdentifier">list</span>)
>>> d[<span class="synConstant">"hoge"</span>].append(<span class="synConstant">1</span>)
>>> d[<span class="synConstant">"hoge"</span>].append(<span class="synConstant">2</span>)
>>> d
defaultdict(<<span class="synStatement">class</span> <span class="synConstant">'list'</span>>, {<span class="synConstant">'hoge'</span>: [<span class="synConstant">1</span>, <span class="synConstant">2</span>]})
>>> d[<span class="synConstant">"hoge"</span>]
[<span class="synConstant">1</span>, <span class="synConstant">2</span>]
</pre><p> 別にlistじゃなくても、setだろうがdictだろうが何でも指定できる。tupleも指定はできるが、変更できないと何の役にも立たない。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = defaultdict(<span class="synIdentifier">set</span>) <span class="synComment"># setの場合</span>
>>> d[<span class="synConstant">"hoge"</span>].add(<span class="synConstant">1</span>) <span class="synComment"># setの場合はaddを使う</span>
>>> d[<span class="synConstant">"hoge"</span>].add(<span class="synConstant">1</span>)
>>> d[<span class="synConstant">"hoge"</span>].add(<span class="synConstant">2</span>)
>>> d[<span class="synConstant">"hoge"</span>]
{<span class="synConstant">1</span>, <span class="synConstant">2</span>} <span class="synComment"># 重複しないことに注目</span>
>>> d = defaultdict(<span class="synIdentifier">dict</span>) <span class="synComment"># dictの場合</span>
>>> d[<span class="synConstant">"hoge"</span>][<span class="synConstant">1</span>] = <span class="synConstant">1</span>
>>> d[<span class="synConstant">"hoge"</span>][<span class="synConstant">2</span>] = <span class="synConstant">2</span>
>>> d[<span class="synConstant">"fuga"</span>][-<span class="synConstant">1</span>] = -<span class="synConstant">1</span>
>>> d[<span class="synConstant">"fuga"</span>][-<span class="synConstant">2</span>] = -<span class="synConstant">2</span>
>>> d
defaultdict(<<span class="synStatement">class</span> <span class="synConstant">'dict'</span>>, {<span class="synConstant">'hoge'</span>: {<span class="synConstant">1</span>: <span class="synConstant">1</span>, <span class="synConstant">2</span>: <span class="synConstant">2</span>}, <span class="synConstant">'fuga'</span>: {-<span class="synConstant">2</span>: -<span class="synConstant">2</span>, -<span class="synConstant">1</span>: -<span class="synConstant">1</span>}}) <span class="synComment"># よくわからないけど何でもできそう</span>
</pre><p> 参考:<br />
<a href="https://docs.python.jp/3/library/collections.html#collections.defaultdict">8.3. collections — コンテナデータ型 — Python 3.6.5 ドキュメント</a></p><p> mutableなコレクション型を辞書の値にしておく、という発想があればそれほど難しい話ではない。</p>
hayataka2049
【python】pythonでscanf的なことをする
hatenablog://entry/17391345971633924598
2018-04-10T15:59:57+09:00
2019-08-22T18:15:54+09:00 一年以上前にこんな記事を書きました。 これはこれで今読み返すと面白い(香ばしい)記事ですが、真剣にpythonでscanfと同じことをしたくてアクセスしてきた人には役に立たないという問題点がありました。 そこで、pythonでscanfと同じことをする方法について真面目な記事を書いておきます。 目次 何はともあれ入力を受け取る 文字列操作 正規表現を使う parseライブラリを使う まとめ printf編 なお、本記事では次のコマンドで実行できる対話的インタプリタの出力を掲載します。返り値の文字列をそのまま出していますが、標準出力から出力したいときはprintを使ってください。 $ pytho…
<p> 一年以上前に<a href="https://www.haya-programming.com/entry/2017/01/18/221336">こんな記事</a>を書きました。</p><p> これはこれで今読み返すと面白い(香ばしい)記事ですが、真剣にpythonでscanfと同じことをしたくてアクセスしてきた人には役に立たないという問題点がありました。</p><p> そこで、pythonでscanfと同じことをする方法について真面目な記事を書いておきます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#何はともあれ入力を受け取る">何はともあれ入力を受け取る</a></li>
<li><a href="#文字列操作">文字列操作</a></li>
<li><a href="#正規表現を使う">正規表現を使う</a></li>
<li><a href="#parseライブラリを使う">parseライブラリを使う</a></li>
<li><a href="#まとめ">まとめ</a></li>
<li><a href="#printf編">printf編</a></li>
</ul><p> なお、本記事では次のコマンドで実行できる対話的インタプリタの出力を掲載します。返り値の文字列をそのまま出していますが、標準出力から出力したいときはprintを使ってください。</p>
<pre class="code" data-lang="" data-unlink>$ python</pre><p><br />
<span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p></p>
<div class="section">
<h3 id="何はともあれ入力を受け取る">何はともあれ入力を受け取る</h3>
<p> python2ではraw_input、python3ではinputという関数があり、標準入力からのキー入力を受け取ることができます。</p><p> python2の場合</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synIdentifier">raw_input</span>()
hoge
>>> s
<span class="synConstant">'hoge'</span>
</pre><p> python3の場合</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synIdentifier">input</span>()
hoge
>>> s
<span class="synConstant">'hoge'</span>
</pre><p> この受け取った文字列を加工することで、なんとか所要を達するのが基本的なアプローチ方法になります。</p>
</div>
<div class="section">
<h3 id="文字列操作">文字列操作</h3>
<p> pythonには文字列の操作方法がいろいろあり、また文字列操作関数(メソッド)もいろいろあります。多すぎて網羅しきれないので、よく使うものだけまとめておきます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synConstant">"hoge fuga"</span> <span class="synComment"># 文字列の定義</span>
>>> s[<span class="synConstant">0</span>] <span class="synComment"># 0文字目を取り出す</span>
<span class="synConstant">'h'</span>
>>> s[-<span class="synConstant">1</span>] <span class="synComment"># 一番最後の文字を取り出す</span>
<span class="synConstant">'a'</span>
>>> s[:<span class="synConstant">4</span>] <span class="synComment"># 0から3文字目を取り出す</span>
<span class="synConstant">'hoge'</span>
>>> s[<span class="synConstant">2</span>:<span class="synConstant">7</span>] <span class="synComment"># 0から6文字目を取り出す</span>
<span class="synConstant">'ge fu'</span>
>>> s.split(<span class="synConstant">" "</span>) <span class="synComment"># 半角スペースでsplitする</span>
[<span class="synConstant">'hoge'</span>, <span class="synConstant">'fuga'</span>]
>>> s.replace(<span class="synConstant">"g"</span>, <span class="synConstant">"G"</span>) <span class="synComment"># 文字列を置換する</span>
<span class="synConstant">'hoGe fuGa'</span>
>>> s.isnumeric() <span class="synComment"># 数字の文字列かどうかを判定する</span>
<span class="synIdentifier">False</span>
</pre><p> なお、pythonはC言語と違って、「char型」というものはありません。1文字でもすべて「1文字の文字列」という扱いになります。</p><p> このような文字列操作を型変換と組み合わせて使うことで、かなり色々なことができます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synConstant">"1 1.5 1,5"</span> <span class="synComment"># 文字列の定義</span>
>>> splitted_s = s.split(<span class="synConstant">" "</span>) <span class="synComment"># とりあえずsplit</span>
>>> splitted_s <span class="synComment"># splitした結果を表示</span>
[<span class="synConstant">'1'</span>, <span class="synConstant">'1.5'</span>, <span class="synConstant">'1,5'</span>]
>>> d1 = <span class="synIdentifier">int</span>(splitted_s[<span class="synConstant">0</span>]) <span class="synComment"># splitした結果の0番目をint型にする </span>
>>> d1
<span class="synConstant">1</span>
>>> f1 = <span class="synIdentifier">float</span>(splitted_s[<span class="synConstant">1</span>]) <span class="synComment"># splitした結果の1番目をfloat型にする</span>
>>> f1
<span class="synConstant">1.5</span>
>>> f2 = <span class="synIdentifier">float</span>(splitted_s[<span class="synConstant">2</span>].replace(<span class="synConstant">","</span>, <span class="synConstant">"."</span>)) <span class="synComment"># splitした結果の2番目をfloat型にする</span>
>>> f2
<span class="synConstant">1.5</span>
</pre><p> こういった処理をループなどと組み合わせて頑張れば、大抵のことは実現可能です。でも実際にやってみると頑張るのはなかなか辛いので、scanfのようなものがほしくなるのかもしれません。</p>
</div>
<div class="section">
<h3 id="正規表現を使う">正規表現を使う</h3>
<p> たとえば、こんな入力をした場合どうでしょう?</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synConstant">"1, 1.5, 2, 2.5:hoge"</span>
</pre><p> この場合、一回のsplitで綺麗にsplitすることはできません。何回かに分けて繰り返しsplitするというのも一つの考え方ですが、こういう場合は正規表現を使うと簡単です。正規表現は標準ライブラリのreモジュールで使えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> s = <span class="synConstant">"1, 1.5, 2, 2.5:hoge"</span>
>>> <span class="synPreProc">import</span> re
>>> re.split(<span class="synConstant">r",\s+|:"</span>, s)
[<span class="synConstant">'1'</span>, <span class="synConstant">'1.5'</span>, <span class="synConstant">'2'</span>, <span class="synConstant">'2.5'</span>, <span class="synConstant">'hoge'</span>]
</pre><p> 一発で綺麗にsplitできましたね。re.splitは区切り文字列の正規表現パターンと文字列を渡すと、それを探してそこで切ってくれます。</p><p> ",\s+|:"というパターンの意味を簡単に説明すると、「カンマの後にスペースが続く OR コロン1つ」を区切り文字として使うという意味です。見た目よりは簡単な内容を表しているのがおわかり頂けるでしょう。それでいて、けっこう色々な表現ができます。</p><p> 正規表現はプログラミングをやるなら覚えておいて損はしないので、まだ使ったことがない人も使えそうな機会がある度に積極的に使って、少しずつでも覚えていくことをおすすめします。</p>
</div>
<div class="section">
<h3 id="parseライブラリを使う">parseライブラリを使う</h3>
<p> 正規表現で複雑なsplitなどが簡単にできると言っても、けっきょく型変換は自分でやるしかないのが実情でした。これではscanfには及びません。</p><p> そこで、parseというライブラリを使うことができます。これは外部ライブラリなので、pipで入れる必要があります。</p>
<pre class="code" data-lang="" data-unlink>$ pip install parse</pre><p> ※具体的なインストール方法は環境によって異なります。自分の環境でライブラリを入れる方法を確認した上で、正しい方法でインストールしてください。</p><p> さっそく使ってみましょう。次のように使うことができます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> parse.parse(<span class="synConstant">"{:d} hoge {:f}"</span>, <span class="synConstant">"1024 hoge 11.19"</span>)[<span class="synConstant">0</span>]
>>> <span class="synPreProc">import</span> parse
>>> s = <span class="synIdentifier">input</span>()
hoge <span class="synConstant">1024.20</span>.<span class="synConstant">48</span>, <span class="synConstant">56</span>
>>> parse.parse(<span class="synConstant">"hoge {:d}.{:f}, {:d}"</span>, s)
<Result (<span class="synConstant">1024</span>, <span class="synConstant">20.48</span>, <span class="synConstant">56</span>) {}>
</pre><p> {:d}や{:f}がC言語でいうところのフォーマット文字列であり、scanfというかsscanfのように使うことができます。当然結果は型変換済みです。</p><p> resultというオブジェクトが返っていますが、このオブジェクトはリストのようにインデックスでアクセスすることが可能です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> result = parse.parse(<span class="synConstant">"hoge {:d}.{:f}, {:d}"</span>, s)
>>> result[<span class="synConstant">0</span>]
<span class="synConstant">1024</span>
>>> result[<span class="synConstant">1</span>]
<span class="synConstant">20.48</span>
>>> result[<span class="synConstant">2</span>]
<span class="synConstant">56</span>
</pre><p> あるいは、結果を辞書のような形で格納することもできます。次のようにフォーマットを指定します。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> result = parse.parse(<span class="synConstant">"hoge {var1:d}.{var2:f}, {var3:d}"</span>, s)
>>> result[<span class="synConstant">"var1"</span>]
<span class="synConstant">1024</span>
>>> result[<span class="synConstant">"var2"</span>]
<span class="synConstant">20.48</span>
>>> result[<span class="synConstant">"var3"</span>]
<span class="synConstant">56</span>
</pre><p> なお、これらのリスト(厳密にはtuple)と辞書には、result.fixed, result.namedでアクセス可能です。</p><p> parseライブラリはとても色々なことができます。より詳しく知りたい方は、parseライブラリの公式ページを読んでみてください。</p><p><a href="https://github.com/r1chardj0n3s/parse">GitHub - r1chardj0n3s/parse: Parse strings using a specification based on the Python format() syntax.</a><br />
</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> pythonにはそのままのscanfはありませんが、色々な手段で同じ目的を達することができます。最初は覚えるのが大変ですが、慣れてくると色々なことが簡単にできるのに気づいてくるはずです。Let's enjoy Python!<br />
<br />
</p>
</div>
<div class="section">
<h3 id="printf編">printf編</h3>
<p> 兄弟記事です。よろしければこちらも御覧ください。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2018%2F04%2F10%2F155811" title="【python】pythonでprintf的なことをする - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.haya-programming.com/entry/2018/04/10/155811">www.haya-programming.com</a></cite></p>
</div>
hayataka2049
【python】pythonでprintf的なことをする
hatenablog://entry/17391345971633924218
2018-04-10T15:58:11+09:00
2019-08-22T18:22:09+09:00 一年以上前にこんな記事を書きました。 これはこれで今読み返すと面白い(香ばしい)記事ですが、真剣にpythonでprintfと同じことをしたくてアクセスしてきた人には役に立たないという問題点がありました。 そこで、pythonでprintf的なことをする方法をまとめておきます。 目次 概要 %演算子を使った記法 str.format()メソッド f文字列 まとめ scanf編 なお、本記事では次のコマンドで実行できる対話的インタプリタの出力を掲載します。返り値の文字列をそのまま出していますが、標準出力から出力したいときはprintを使ってください。 $ python スポンサーリンク (ads…
<p> 一年以上前に<a href="https://www.haya-programming.com/entry/2017/01/18/221336">こんな記事</a>を書きました。</p><p> これはこれで今読み返すと面白い(香ばしい)記事ですが、真剣にpythonでprintfと同じことをしたくてアクセスしてきた人には役に立たないという問題点がありました。</p><p> そこで、pythonでprintf的なことをする方法をまとめておきます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#概要">概要</a></li>
<li><a href="#演算子を使った記法">%演算子を使った記法</a></li>
<li><a href="#strformatメソッド">str.format()メソッド</a></li>
<li><a href="#f文字列">f文字列</a></li>
<li><a href="#まとめ">まとめ</a></li>
<li><a href="#scanf編">scanf編</a></li>
</ul><p></p><p> なお、本記事では次のコマンドで実行できる対話的インタプリタの出力を掲載します。返り値の文字列をそのまま出していますが、標準出力から出力したいときはprintを使ってください。</p>
<pre class="code" data-lang="" data-unlink>$ python</pre><p><br />
<span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p></p>
<div class="section">
<h3 id="概要">概要</h3>
<p> pythonでprintfのようなことをする方法は、3つあります。</p>
<ul>
<li>%演算子を使った記法</li>
<li>str.format()メソッド</li>
<li>f文字列</li>
</ul><p> なんで3つもあるんでしょうねぇ・・・。困ったものです。</p><p> とりあえず1つずつ説明していきます。</p>
</div>
<div class="section">
<h3 id="演算子を使った記法">%演算子を使った記法</h3>
<p> 一番昔からあり、最新のpythonでも使える方法です。なのでpythonのバージョンに依存せず使えるというメリットがあります。デメリットとしては、ちょっとわかりづらくトラブルの原因にもなること、柔軟性に劣ることが挙げられます。</p><p> これは次のように使います。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synConstant">"hoge %s"</span> % <span class="synConstant">"fuga"</span>
<span class="synConstant">'hoge fuga'</span>
</pre><p> いかにもprintf的です。色々な例を示してみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synConstant">"hoge %s %s"</span> % (<span class="synConstant">"fuga"</span>, <span class="synConstant">"piyo"</span>) <span class="synComment"># 複数渡すことができる</span>
<span class="synConstant">'hoge fuga piyo'</span>
>>> <span class="synConstant">"hoge %(fuga)s %(piyo)s"</span> % {<span class="synConstant">"fuga"</span>:<span class="synConstant">"piyo"</span>, <span class="synConstant">"piyo"</span>:<span class="synConstant">"fuga"</span>} <span class="synComment"># 辞書を使うと名前を指定して渡せる</span>
<span class="synConstant">'hoge piyo fuga'</span>
>>> <span class="synConstant">"hoge %d %03d"</span> % (<span class="synConstant">10</span>, <span class="synConstant">20</span>) <span class="synComment"># intもばっちり</span>
<span class="synConstant">'hoge 10 020'</span>
>>> <span class="synConstant">"hoge %.3f"</span> % <span class="synIdentifier">float</span>(<span class="synConstant">1</span>/<span class="synConstant">3</span>) <span class="synComment"># floatも同様</span>
<span class="synConstant">'hoge 0.333'</span>
</pre><p> この%はあくまでも文字列オブジェクトに対する演算子操作であることに注意してください。</p><p> こうして見るとよさそうですが、複雑なことをしようとすると色々なトラブルが起こるらしいので、近年は次に説明するformatメソッドなどを使うことが公式ドキュメントなどでも推奨されています。</p><p> もっと詳しく知りたい方は、公式ドキュメントを参照してください。</p><p><a href="https://docs.python.jp/3.6/library/stdtypes.html#printf-style-string-formatting">4. 組み込み型 — Python 3.6.9 ドキュメント</a><br />
</p>
</div>
<div class="section">
<h3 id="strformatメソッド">str.format()メソッド</h3>
<p> これはpythonの文字列オブジェクトに標準で実装されているメソッドです。python2.6以上で使えます。</p><p> 使い方は簡単です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synConstant">"hoge {}"</span>.format(<span class="synConstant">"fuga"</span>)
<span class="synConstant">'hoge fuga'</span>
</pre><p> 最初はprintfや上の%演算子とはフォーマットが異なるのに戸惑うでしょう。formatメソッドでは"{}"でくくられた範囲をフォーマットとして解釈します。</p><p> formatメソッドでも上と同様のことができます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synConstant">"hoge {} {}"</span>.format(<span class="synConstant">"fuga"</span>, <span class="synConstant">"piyo"</span>) <span class="synComment"># 複数渡す</span>
<span class="synConstant">'hoge fuga piyo'</span>
>>> <span class="synConstant">"hoge {fuga} {piyo}"</span>.format(fuga=<span class="synConstant">"piyo"</span>, piyo=<span class="synConstant">"fuga"</span>) <span class="synComment"># 名前を指定</span>
<span class="synConstant">'hoge piyo fuga'</span>
>>> <span class="synConstant">"hoge {0} {0} {1}"</span>.format(<span class="synConstant">"fuga"</span>, <span class="synConstant">"piyo"</span>) <span class="synComment"># こういうこともできる。indexを指定すると便利</span>
<span class="synConstant">'hoge fuga fuga piyo'</span>
>>> <span class="synConstant">"hoge {0:10.3f}"</span>.format(<span class="synConstant">1.4</span>) <span class="synComment"># 文字列幅と精度を指定している</span>
<span class="synConstant">'hoge 1.400'</span>
</pre><p> こちらの方が柔軟性が高いのと、メソッドなので通常のオブジェクト指向の延長上で捉えることができ、%演算子ほど場当たり的な側面がありません。なので、この方法を積極的に覚えていくことをおすすめします。</p><p> なお、公式ドキュメントはこちらです。<br />
<a href="https://docs.python.jp/3/library/stdtypes.html#str.format">組み込み型 — Python 3.7.4 ドキュメント</a><br />
</p>
</div>
<div class="section">
<h3 id="f文字列">f文字列</h3>
<p> f文字列は一番新しい方法です。python3.6から導入されました。</p><p> %演算子にしろstr.format()メソッドにしろ、ちょっと記述が冗長という欠点がありました。それを補ったのがf文字列です。これは文字列の中で直接式の値を評価し、それを文字列に変換して出力することができます。</p><p> これを使うためには、文字列リテラルの先頭にfを付けます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> f<span class="synConstant">"{1+1}"</span>
<span class="synConstant">'2'</span>
</pre><p> 簡潔な感じです。こういう使い方もできます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> a = <span class="synConstant">"hoge"</span>
>>> f<span class="synConstant">"{a}"</span>
<span class="synConstant">'hoge'</span>
</pre><p> 関数だって呼び出せます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">pow2</span>(x):
... <span class="synStatement">return</span> x*x
...
>>> b = <span class="synConstant">10</span>
>>> f<span class="synConstant">"{pow2(b)}"</span>
<span class="synConstant">'100'</span>
</pre><p> 表示フォーマットも指定できます。formatのときと同じような書き方です。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> f<span class="synConstant">"{1/3:.3f}"</span>
<span class="synConstant">'0.333'</span>
</pre><p> なかなか凄いですね。でも、個人的にはちょっとトリッキーすぎて使いづらい気が・・・。</p><p> 公式ドキュメントはここです。</p><p><a href="https://docs.python.jp/3.6/reference/lexical_analysis.html#f-strings">2. 字句解析 — Python 3.6.9 ドキュメント</a></p><p><b>2019/08/22追記</b><br />
この記事を書いてから月日が過ぎ、近年は少し事情が変わってきたのかなと思うようになりました。</p><p> なんだかんだで簡潔に書けるのがf文字列の良いところです。また、最近のPython環境は3.6以降が標準になってきたので(何かと美味しい機能が3.6以降で増えたので)、f文字列の互換性の問題もあまり気にならなくなってきました。</p><p> 今後はf文字列でいいかなという感じもします。</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> printf的なことをする3種類の方法を紹介しました。</p><p> どの方法が良いのか? については、</p>
<ul>
<li>歴史的使命を終えつつある%演算子を使った記法</li>
<li>現役バリバリなのでおすすめのsrt.format()メソッド</li>
<li>まだよくわからないf文字列</li>
</ul><p> という感じで、まずはsrt.format()メソッドを使いこなせるようになることを推奨します。もちろん他の方法を使ってはいけないということではないので、少しずつ覚えていくのがおすすめです。</p><p><b>2019/08/22追記</b><br />
新し目のPythonしか触らないという前提であれば、f文字列から覚えてもいいと思います。記述量が減らせて楽です。</p>
</div>
<div class="section">
<h3 id="scanf編">scanf編</h3>
<p> 兄弟記事です。よろしければこちらも御覧ください。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2018%2F04%2F10%2F155957" title="【python】pythonでscanf的なことをする - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.haya-programming.com/entry/2018/04/10/155957">www.haya-programming.com</a></cite></p>
</div>
hayataka2049
【python】dictのkeyとvalueを入れ替える話色々
hatenablog://entry/8599973812341910890
2018-01-29T18:30:48+09:00
2018-11-27T15:55:26+09:00 dictのkeyとvalueを入れ替えたい、誰でも一度はそう思うのではないだろうか。 方法は何種類かある。それらについて説明する。 あと、この話は簡単なようで実は罠の宝庫。その辺もちょっと説明しておく。 目次 for文で書く リスト内包表記で書く 辞書内包表記 罠の説明 罠1:valueがmutableだとできない(TypeError: unhashable type: ~) 罠2:複数のkeyが同じvalueに刺さってるとき(エラーは出ないが悲しい結果になる) まとめ スポンサーリンク (adsbygoogle = window.adsbygoogle || []).push({}); fo…
<p> dictのkeyとvalueを入れ替えたい、誰でも一度はそう思うのではないだろうか。</p><p> 方法は何種類かある。それらについて説明する。</p><p> あと、この話は簡単なようで実は罠の宝庫。その辺もちょっと説明しておく。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#for文で書く">for文で書く</a></li>
<li><a href="#リスト内包表記で書く">リスト内包表記で書く</a></li>
<li><a href="#辞書内包表記">辞書内包表記</a></li>
<li><a href="#罠の説明">罠の説明</a><ul>
<li><a href="#罠1valueがmutableだとできないTypeError-unhashable-type-">罠1:valueがmutableだとできない(TypeError: unhashable type: ~)</a></li>
<li><a href="#罠2複数のkeyが同じvalueに刺さってるときエラーは出ないが悲しい結果になる">罠2:複数のkeyが同じvalueに刺さってるとき(エラーは出ないが悲しい結果になる)</a></li>
</ul>
</li>
<li><a href="#まとめ">まとめ</a></li>
</ul><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><p></p>
<div class="section">
<h3 id="for文で書く">for文で書く</h3>
<p> 誰でも思いつく方法。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {<span class="synConstant">"a"</span>:<span class="synConstant">"あ"</span>,<span class="synConstant">"i"</span>:<span class="synConstant">"い"</span>}
>>> result = {}
>>> <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items():
... result[v] = k
...
>>> result
{<span class="synConstant">'あ'</span>: <span class="synConstant">'a'</span>, <span class="synConstant">'い'</span>: <span class="synConstant">'i'</span>}
</pre><p> d.items()は次のようなものを返す。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d.items()
dict_items([(<span class="synConstant">'a'</span>, <span class="synConstant">'あ'</span>), (<span class="synConstant">'i'</span>, <span class="synConstant">'い'</span>)])
</pre><p> dict_itemsは辞書ビューオブジェクト。詳細については<a href="https://docs.python.jp/3/library/stdtypes.html#dictionary-view-objects">公式ドキュメント</a>を確認してほしい。形としては、中のtupleのlist通りのものが返るので、forで素直に処理すれば良い。これが基本中の基本。</p>
</div>
<div class="section">
<h3 id="リスト内包表記で書く">リスト内包表記で書く</h3>
<p> 上でも触れたように、d.items()で辞書ビューオブジェクトが返る。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {<span class="synConstant">"a"</span>:<span class="synConstant">"あ"</span>,<span class="synConstant">"i"</span>:<span class="synConstant">"い"</span>}
>>> d.items()
dict_items([(<span class="synConstant">'a'</span>, <span class="synConstant">'あ'</span>), (<span class="synConstant">'i'</span>, <span class="synConstant">'い'</span>)])
<span class="synComment"># こんな形 -> [('a', 'あ'), ('i', 'い')]</span>
</pre><p> 実は、この形のiterableをdictのインスタンス生成時に渡してやると、ちゃんと元の辞書になる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">dict</span>(<span class="synIdentifier">list</span>(d.items())) <span class="synComment"># 1回リストにしてみても大丈夫!</span>
{<span class="synConstant">'a'</span>: <span class="synConstant">'あ'</span>, <span class="synConstant">'i'</span>: <span class="synConstant">'い'</span>}
</pre><p> これを応用して、次のように書くことができる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synIdentifier">dict</span>([(v,k) <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items()])
{<span class="synConstant">'a'</span>: <span class="synConstant">'あ'</span>, <span class="synConstant">'i'</span>: <span class="synConstant">'い'</span>}
</pre><p> まあ、単にkeyとvalueを入れ替えたいだけなら次の辞書内包表記の方が気軽だけど。この方法は2つのリストがあって、合体させて辞書にしたいみたいなとき、zipと組み合わせて使うと威力を発揮したりする。<br />
<br />
</p>
</div>
<div class="section">
<h3 id="辞書内包表記">辞書内包表記</h3>
<p> なんとこんな簡単に書ける。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> {v:k <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items()}
{<span class="synConstant">'a'</span>: <span class="synConstant">'あ'</span>, <span class="synConstant">'i'</span>: <span class="synConstant">'い'</span>}
</pre><p> 辞書内包表記という。なんだか不思議だけど、こうやって書くことができる。</p>
</div>
<div class="section">
<h3 id="罠の説明">罠の説明</h3>
<p> 基本的な方法は上で説明した通りなのだけど、この話にはたくさん罠があるので、それについて説明する。</p>
<div class="section">
<h4 id="罠1valueがmutableだとできないTypeError-unhashable-type-">罠1:valueがmutableだとできない(TypeError: unhashable type: ~)</h4>
<p> mutableとは値(内部状態)を変更できるオブジェクトのこと。</p><p> 普段はあまり意識しない概念だが、たとえばpython世界では数字の1はmutableではなくimmutableで、数字の1のオブジェクトを上書きしようとしても2になったり3になったりは絶対にしない。1+1という演算を行うと、新しく数字の2のオブジェクトが生成されて返される<a href="#f-2f284092" name="fn-2f284092" title="実際には高速化のためにオブジェクトをキャッシュしたり、色々忙しいことをしているらしいが">*1</a>。</p><p> 一方、たとえばlistでは要素をappendしても同じオブジェクトのまま内部状態が上書きされて、結果的に要素が1つ増える。こういうのがmutable<a href="#f-5baaa549" name="fn-5baaa549" title="厳密な説明じゃないと思うが、ご了承いただきたい">*2</a>。</p><p> immutableなオブジェクトの例を挙げると、</p>
<ul>
<li>int</li>
<li>float</li>
<li>str</li>
<li>tuple</li>
</ul><p> こんな連中がそう。</p><p> mutableなオブジェクトの例は、</p>
<ul>
<li>list</li>
<li>set</li>
<li>dict</li>
</ul><p> 大体イメージが掴めただろうか?</p><p> さて、辞書のkeyとvalueを入れ替える話に戻る。</p><p> 結論から言うと、mutableなオブジェクトは辞書のkeyにはできない。たとえば、listをkeyに使おうとするとこんなエラーが返ってくる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> {[<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>]:<span class="synConstant">1</span>}
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
<span class="synType">TypeError</span>: unhashable <span class="synIdentifier">type</span>: <span class="synConstant">'list'</span>
</pre><p> そりゃ、辞書のキーがほいほい書き換わったら困るもんな。だけど、valueにはmutableは普通に使えるので、</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {<span class="synConstant">123</span>:[<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>]}
>>> {v:k <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items()}
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <dictcomp>
<span class="synType">TypeError</span>: unhashable <span class="synIdentifier">type</span>: <span class="synConstant">'list'</span>
</pre><p> こんな悲しい目に遭う。対策は適当なimmutableに変換してやること。リストならtupleにするのが良いだろう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {<span class="synConstant">123</span>:[<span class="synConstant">1</span>,<span class="synConstant">2</span>,<span class="synConstant">3</span>]}
>>> {<span class="synIdentifier">tuple</span>(v):k <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items()}
{(<span class="synConstant">1</span>, <span class="synConstant">2</span>, <span class="synConstant">3</span>): <span class="synConstant">123</span>}
</pre><p> じゃあvalueもdictだったらどうしよう? リストとstrが入り混じってたりしたら? そんなややこしいdictのkeyとvalueを入れ替えようとするくらいなら、処理フローを抜本的に見直した方が良いだろう。絶対もっとマシな書き方がある。<br />
<br />
</p>
</div>
<div class="section">
<h4 id="罠2複数のkeyが同じvalueに刺さってるときエラーは出ないが悲しい結果になる">罠2:複数のkeyが同じvalueに刺さってるとき(エラーは出ないが悲しい結果になる)</h4>
<p> さて、ここまで説明してきたような方法は、実はkeyとvalueが1対1で対応しているときしか使えない。数学用語でいう単射。</p><p> 複数のvalueが同じkeyに刺さってる場合・・・は、まあ、dictの性質上あり得ないが、複数のkeyが同じ値に刺さる場合はままある。これのkeyとvalueを入れ替えてひっくり返したからといって、dictの性質上、複数のvalueが同じkeyに刺さることはあり得ない。どうなるのか?</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> d = {<span class="synConstant">"あ"</span>:<span class="synConstant">"a"</span>, <span class="synConstant">"い"</span>:<span class="synConstant">"i"</span>, <span class="synConstant">"ア"</span>:<span class="synConstant">"a"</span>, <span class="synConstant">"イ"</span>:<span class="synConstant">"i"</span>}
>>> {v:k <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items()}
{<span class="synConstant">'a'</span>: <span class="synConstant">'あ'</span>, <span class="synConstant">'i'</span>: <span class="synConstant">'イ'</span>}
</pre><p> いずれかの値1つに決まる。こういうのはロジックエラーの温床になって怖いけど、辞書の仕様上仕方ない。</p><p> ちなみにどれに決まるかは、ドキュメントでも定義されておらずランダムだと思う<a href="#f-71223e31" name="fn-71223e31" title="でも何回回しても同じ結果になるので、内部的には「順番」はあるんだと思う。たぶん最後に入ることになる値">*3</a>。</p><p> これの解決方法は、どんな形で結果を得たいかによって変わってくる。普通は何らかのcollectionにvalues(入れ替える前のkeys)を格納してあげたいことが多いと思う。その場合は、こんな風に書ける。簡潔に書くためにdefaultdictを使い、default_factory(要するにデフォルト値を生成するもん)にはsetを使ってみた。一応defaultdictのドキュメントを貼っておく。</p><p><a href="https://docs.python.jp/3.3/library/collections.html#collections.defaultdict">8.3. collections — コンテナデータ型 — Python 3.3.6 ドキュメント</a><br />
</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synPreProc">from</span> collections <span class="synPreProc">import</span> defaultdict
>>> d = {<span class="synConstant">"あ"</span>:<span class="synConstant">"a"</span>, <span class="synConstant">"い"</span>:<span class="synConstant">"i"</span>, <span class="synConstant">"ア"</span>:<span class="synConstant">"a"</span>, <span class="synConstant">"イ"</span>:<span class="synConstant">"i"</span>}
>>> result = defaultdict(<span class="synIdentifier">set</span>)
>>> <span class="synStatement">for</span> k,v <span class="synStatement">in</span> d.items():
... result[v].add(k)
...
>>> result
defaultdict(<<span class="synStatement">class</span> <span class="synConstant">'set'</span>>, {<span class="synConstant">'a'</span>: {<span class="synConstant">'ア'</span>, <span class="synConstant">'あ'</span>}, <span class="synConstant">'i'</span>: {<span class="synConstant">'い'</span>, <span class="synConstant">'イ'</span>}})
</pre><p> こればっかりは内包表記で書こうとしても上手く行かない。for文を回して愚直に付け加えていく必要がある(と思う)。<br />
<br />
</p>
</div>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 意外と考えることが多くて面倒くさい。安直に入れ替えようとする前に、keyとvalueを入れ替えて本当に大丈夫かどうかは良く検討する必要はある。自分で構造をよく理解していないような辞書に対してやってはいけない。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-2f284092" name="f-2f284092" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">実際には高速化のためにオブジェクトをキャッシュしたり、色々忙しいことをしているらしいが</span></p>
<p class="footnote"><a href="#fn-5baaa549" name="f-5baaa549" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">厳密な説明じゃないと思うが、ご了承いただきたい</span></p>
<p class="footnote"><a href="#fn-71223e31" name="f-71223e31" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">でも何回回しても同じ結果になるので、内部的には「順番」はあるんだと思う。たぶん最後に入ることになる値</span></p>
</div>
hayataka2049