すなぶろ

Pythonistaを目指しているつもりが、Hyのおかげで無事脱線。Clojurian目指すことになりました。

Python初心者が中級者になるためのスタートダッシュ 【ググるのは時間の無駄】編

皆さん今日もググってますか? 私のようにRubyから転向したPython初心者にとっては、Googleは神のようなサービスです。「Rubyではこう書けたけど、Pythonではどう書けばいいの?」という質問に、Google先生は(基本的には)誠実に応えてくれます。

しかし、この学習方法には大きな問題があります。RubyのコードをいくらPythonに移植しても、Pythonらしい書き方が身に付くわけではないからです。キーワード引数デコレータジェネレータイテレータ……似たようなものはRubyにもありますが、決して同じ使い方をするものではないはずなのです。

ひとつひとつ調べていたのでは、いつまで経っても初心者を卒業できません。できたとしても膨大な時間が必要でしょう。あくまでも包括的な説明を読んで、芯からPythonic Wayを身に着けたいのです。

ではどうすればいいのか。簡単です。教科書を使いましょう。ただの教科書ではいけません。Pythonの教科書です。Javaで説明するには一工夫も二工夫も必要なくらいPythonらしい書き方を説明してくれる、Pythonにどっぷり浸かったPythonの教科書です。

スマートPythonプログラミング、略してスマパイです。そこらの入門書は読破したけど、「Pythonらしい」という感覚がわからないあなたにお勧め。私はこの本でPythonistaの仲間入りをします。

本の紹介

この本の作者さんは、実は同じくはてブロユーザーであるもみじあめさんです。

「こんな人におすすめ」という項目に全部該当していてびびりました。技術力のある方が気軽に本を出せる時代になったのは、私にとっては助かります。紙媒体も好きですけどね。

PythonシェルとしてIPythonを使う

この本はUbuntu向けに書かれていますが、Windowsでも応用することができます。というより、Pythonのインストールやpipの使い方の説明を統一するためにUbuntuに絞っているとのことです。

ところでpythonとタイプすると起動するPythonシェル(REPL)、私はずっと使いづらいと思っていました。tabキーで補完ができないし、Rubyで言うところのpryのようなものはないかな、と思っていたらいきなり紹介されてました。

IPythonを使うことでtabキーによる自動補完をサポートしたREPLが使えるようになるとのこと。?とタイプすることでいろいろ機能が出てくるので、自動補完に限らず便利に使えそうです。

f:id:sandmark:20171014171424p:plain
IPythonでResponderをインポート

デバッガはpdbじゃなくてpudbを使え。Windows? 知らんな

実は前の記事でマルコフ辞書を実装するときに、バグに遭遇したことがありました。テストを書いていなかったせいなのですが、テストの書き方がわからなかったせいでもあります。

sandmark.hateblo.jp

そこでpdbというPython組み込みのデバッガを使って解決したのですが、サードパーティ製のpudbを使うとGUIインターフェイスデバッグできるんだとか。試してみましょう。

……と思ったのですが、現時点ではWindowsに対応していないようです。

D:\Users\sandmark\repos\unmo>pudb3 unmo.py
Traceback (most recent call last):
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "D:\Users\sandmark\AppData\Local\Programs\Python\Python36-32\Scripts\pudb3.exe\__main__.py", line 9, in <module>
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\pudb\run.py", line 34, in main
    steal_output=options.steal_output)
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\pudb\__init__.py", line 64, in runscript
    dbg = _get_debugger(steal_output=steal_output)
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\pudb\__init__.py", line 50, in _get_debugger
    dbg = Debugger(**kwargs)
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\pudb\debugger.py", line 137, in __init__
    self.ui = DebuggerUI(self, stdin=stdin, stdout=stdout, term_size=term_siz        e)
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\pudb\debugger.py", line 1881, in __init__
    self.screen = ThreadsafeRawScreen()
  File "d:\users\sandmark\appdata\local\programs\python\python36-32\lib\site-packages\urwid\raw_display.py", line 89, in __init__
    fcntl.fcntl(self._resize_pipe_rd, fcntl.F_SETFL, os.O_NONBLOCK)
NameError: name 'fcntl' is not defined

fcntlLinuxカーネルシステムコールなので、Windowsで使えるわけがありませんね。

StackOverFlowにリトルハックがありましたが、pudbに対応させるにはfcntlのプロパティまで定義しなくてはならないので、APIポーティングを行わないと難しそうです。

本格的なプログラミングとなったらVirtualBoxを使うので、pudbはそれまで待機していてもらいましょう。

エディタの設定 - Emacsの場合

私は何でもかんでもEmacsを使う古いタイプの人間で、AtomやSublimeTextといったモダンでハイカラなエディタを使うには歳を取りすぎていますし、言語によってエディタを変えるなんて器用なことはとてもできません。

というわけで、以下の点に対応した自分のPythonEmacs設定を晒してみたいと思います。

  • シンタックスハイライト
  • virtualenvwrapperへの対応
  • flycheckによる動的コードチェックとlint警告
  • jediによるインテリセンスコード補完
  • autopep8によるコーディング規約管理

Emacsのパッケージ管理にはuse-packageを使っています。というわけで必要なEmacsパッケージは6つ。

  • use-package
  • python
  • auto-virtualenvwrapper
  • flycheck
  • jedi
  • py-autopep8
(let ((packages '(use-package python auto-virtualenvwrapper
                  flycheck jedi py-autopep8)))
  (package-refresh-contents)
  (dolist (package packages)
    (package-install package))
  )

Pythonに必要なパッケージもインストールしてしまいましょう。

pip install autopep8 jedi epc pylint

あとは~/.emacs.d/init.elの設定です。

;;; You need to install packages below via pip:
;;; pip install autopep8 jedi epc
;;; pip install pylint # for flycheck
(use-package python
  :mode ("\\.py$" . python-mode)
  :bind (:map python-mode-map
              ("C-m" . newline-and-indent))
  :init
  (add-hook 'python-mode-hook
            (lambda ()
              (smart-newline-mode 0)
              ))

  (use-package auto-virtualenvwrapper
    :init
    (add-hook 'python-mode-hook 'auto-virtualenvwrapper-activate)
    )

  (use-package flycheck
    :init
    (add-hook 'python-mode-hook (lambda ()
                                  (flycheck-mode 1)))
    )
  (use-package jedi
    :bind (:map jedi-mode-map
                ([(C-tab)] . nil)
           :map python-mode-map
                ("C-c t" . jedi:goto-definition)
                ("C-c b" . jedi:goto-definition-pop-marker)
                ("C-c r" . helm-jedi-related-names)
                )
    :init
    ;; (setq jedi:complete-on-dot t)
    (add-hook 'python-mode-hook
              (lambda ()
                (jedi:setup)
                (setq ac-sources '())
                (add-to-list 'ac-sources 'ac-source-jedi-direct)))
    )

  (use-package py-autopep8
    :init
    (setq py-autopep8-options '("--max-line-length=200"))
    (setq flycheck-flake8-maximum-line-length 200)
    (add-hook 'python-mode-hook (lambda () (py-autopep8-enable-on-save)))
    )
  )

わざわざC-mnewline-and-indentを割り当てているのは、別パッケージのsmart-newlineを無効化するためです。Pythonはインデントが崩れると話にならないので、smart-newlineとは相性が悪いです。

jediauto-completeと組み合わせて使っています。ただ、他のac-sourcesがあるとうまく動かないので空にしています。jedi:complete-on-dotはメソッド呼び出しのときに候補を表示してくれる機能ですが、あまりに処理の負担があるとEmacsそのものがフリーズするので、様子見でコメントアウトしています。

py-autopep8は透過的に動くよう、Pythonスクリプトを保存するときにコードを自動整形するようにしています。

flycheckpylint)のおかげで「docstringがない」「self使わないのにメソッドである必要あるの?」「変数名がわかりづらい」などといろいろ文句助言がもらえます。

次回へ

次は実際のコーディングです。といっても新たに何か作るわけではなく、『恋するプログラム』シリーズで作った各種ファイルのドキュメントを生成したり、複雑さをチェックしてリファクタリングしていきます。