IntelliJ で Python の virtualenv を効かせる設定

IntelliJ の使い方が分からな過ぎて生産性が低い… つらい。

Python の virtualenv を使っている環境で、virtualenv 内のライブラリ群と Python 本体の組み込みライブラリの両方で補完やジャンプを効かせるのに苦労をした。うう…たかだかこれだけのことに、なんでこんなに時間を…。同じことで時間を無駄にしないよう、ここにメモを残す。

端的に言えば、「SDK」と「Modules」の両方に設定を入れる必要がある、ということを理解すればよい。

start

この何とも言えないアイコンから「Project Settings」に飛ぶ。

modules-dependencies.png

その後、「Modules => Dependencies」から「Python 3.6 interpreter Library」にチェックを入れる。

site-packages.png

最後に virtualenv の中の site-packages を Classpath に含めてやればよい。うまく反映されないようであれば、「File => Invalidate Caches / Restart…」を実行する。

広告

CheckiO で Python を学ぶ

この記事は Python Advent Calendar の15日目の記事として書かれています。

CheckiO とは何か?

CheckiO は Python を書くことでステージを攻略していく、ゲームサービスでした。今は Python と JavaScript のどちらか好きな方でプログラムを書くことができます。

姉妹サービスとして、Empire of Code というものもあります。こちらの方では、日本のソシャゲーのように、現実世界で一定時間が経過すると回復アイテムがもらえる仕組みがあり、定期的にログインさせるインセンティブを持たせたゲームデザインになっています。

この記事では CheckiO に絞って話を進めていきます。

CheckiO のよいところは何か?

ゲームを通じてプログラミングを学ぶというコンセプトはそれほど目新しいものではありません。例えば CodinGameCodeCombat など、様々なプログラミングゲームが存在します。“Programming Games” というクエリで Google 検索する と、このジャンルで一旗揚げようとしているサービスがとても多いことが分かると思います。

このように多数のプログラミングゲームが存在する中で、僕が CheckiO を特に気に入っている理由がいくつかあります。

問題が段階的に難しくなる

このゲームでは、いきなり高難度の問題に取り組むことができないようになっています。

ゲームを攻略していくことでスコアを獲得し、ある一定値を超えた段階で、より難しい問題に挑戦できるようになります。初学者が「どこから初めていいか分からない…」と途方に暮れることのないような設計になっています。

「とりあえず要件を満たすコード」を提出できれば他人のコードを読める

簡単な問題であっても、エキスパートのコードと初心者のコードではアプローチが大きく異なります。

「とりあえず動く」コードさえ提出できれば、エキスパートのコードを読み、どこに改善の余地があるのか学べます。

逆に言うと、「とりあえず動く」ところまでは自分で考え抜かなければなりません。そこまで自力で行ければ、基本的なロジックは理解できているということなので、他人のコードを消化する準備ができたと言えるわけです。よくできています。

時間制限がない

コーディング時間の制約が一切ないので、とことん考え抜くことができます。

仕事では往々にして決められたデッドラインに向けて、妥協をしつつプログラムを作成します。CheckiO では、時間的なプレッシャーがない中、閃きがあるまでずっと問題に取り組むことができます。

再提出回数の制限も存在しないので、「これで万全!」と思ったものであっても、さらに後で改良することができます。

出題に貢献できる

企業がホストしているゲームにも関わらず、問題文に “How to improve this question?” のリンクが存在し、プルリクエストベースで問題文の編集をリクエストすることができます。コミュニティベースでサービスをよくしていきたいという姿勢には好感が持てます。

(必要があれば) ヒントが与えられる

もし全く問題を解く糸口が見つからない場合、”I have no idea how to start solving this mission (どこから手をつけていいか分かりません)” というリンクをクリックすると、出題者からのヒントが読めます。

最初の一歩を踏み出す

CheckiO でアカウントを作ると、まずは「HOME」と「ELEMENTARY」というステージに行けるようになります。例として「ELEMENTARY」にある FizzBuzz の問題を取り上げましょう。

“Fizz buzz” is a word game we will use to teach the robots about division. Let’s learn computers.

You should write a function that will receive a positive integer and return:
“Fizz Buzz” if the number is divisible by 3 and by 5;
“Fizz” if the number is divisible by 3;
“Buzz” if the number is divisible by 5;
The number as a string for other cases.

典型的な FizzBuzz の要件です。”Solve It” ボタンをクリックして、解いてみましょう。

ひな形のコードが次のように与えられています。

def checkio(number):
    #Your code here  (コードはここに書いてください)
    #It's main function. Don't remove this function  (この関数が評価対象なので、削除しないでください)
    #It's using for auto-testing and must return a result for check.  (返り値を自動テストが確認するので、値を返してください)

    #replace this for solution  (ここを書き換えて解答を作成してください)
    return str(number)

ベタに書くと、こんな感じになるでしょうか。

def checkio(number):
    if number % 15 == 0:
        return "Fizz Buzz"
    if number % 5 == 0:
        return "Buzz"
    if number % 3 == 0:
        return "Fizz"

    return str(number)

コードを書き換えたら、画面左上の “Check” をクリックしてみましょう。

正解の場合は添付画像のように “View other solutions (他人の解答を見る)” というリンクが表示されます。

CheckiO の猛者について

“View other solutions (他人の解答を見る)” を実際にクリックしてみましょう。

各人の答えは「Speedy」や「Creative」などのように、カテゴリ分けされます。

本記事の執筆時点で最も Creative なスコアが高い解答は veky による次のコードです。

checkio=lambda n:("Fizz "*(1-n%3)+"Buzz "*(1-n%5))[:-1]or str(n)

ちょっと文章では説明しづらいですが、読解してみましょう。lambda で関数オブジェクトを作り、引数 n が 1-n%3 == 1 のときだけ "Fizz " を、1-n%5 == 1 のときだけ "Buzz " を作り出し文字列結合します。そして、最後の空白を削るために [:-1] しています。"Fizz " でも "Buzz " でもないとき、すなわち "" のときは bool 評価をすると False なので or で結んだ str(n) が返り値になります。

じっくり読めば理解できるけど、これを頭の中からひねり出すのは困難でしょう。勉強になります。

まとめ

「Python を学んで次の一歩を踏み出したいけど、適当なお題が見つからない」なら、CheckiO を試してみるのも一興かもしれません。ゲーム感覚で楽しめるし、他人のコードを読むことでプログラミング力の向上も望めることでしょう。

Python の len() について

Python の初学者は len() でコレクションのサイズを取ることについて違和感を覚えるかもしれない。Python では [1, 2, 3].length ではなく len([1, 2, 3]) でリストのサイズを取るのはなぜだろう。

この問いに対する答えを二つ紹介しよう。

.size() や .length() などのゆらぎと無縁

クラスごとにサイズを取得するメソッドを定義するとしよう。その場合、ある設計者は .size() というメソッドを作るかもしれないし、別な設計者は .length() というメソッドにするかもしれない。もしくは sizelength というプロパティを作るかもしれない。

オブジェクトごとに異なるサイズの取得方法があるというのは混乱の元である。

ユーザ定義クラスと組み込みクラスの透過性

list や str などの組み込みクラスに対する len() は C の PyVarObject 構造体から ob_size を読むことで実現される。単なるデータの読み出しなので、高速だ。

一方、ユーザ定義クラスに対する len() は オブジェクトの __len__() メソッド呼び出しで実現される。つまり、クラス定義の中で __len__() さえ実装してしまえば、組み込みクラスと同様の手段でサイズを取得することができる。

まとめ

メソッド名のゆらぎがなく、組み込みクラスとユーザ定義クラスの区別なくサイズを取得できるという意味で、Python の len() の実装は優れている。

参考資料

Python の __init__ や __getitem__ のようなメソッドの名前

Fluent Python』を読みはじめた。面白いコラムが載っていたので紹介しよう。

__init__ のようなメソッドをどう呼ぶだろうか。私はアンダースコア二つではじまり、アンダースコア二つで終わるこれらのメソッドを special methods (スペシャルメソッド) と呼んでいる。Python コミュニティでは magic methods (マジックメソッド) と呼ばれることもある。

英語圏では __init__ を “under-under-init” のように発音する人も多いらしい。日本語圏も似たようなもので、私も「アンダーアンダーイニット」と表現する人を見たことがある。しかし、これでは __init と区別がつかないので、曖昧さが残る。もっと両側のアンダースコアを強調するため、こういうメソッドを最近では dunder methods と表現するらしい。つまり、 “Double” “UNDERscore” “methods” ということだ。

英語で Python に関する記事を読んで面食らわないように、メモを残しておく。