simudaru's blog

Python, Rなどのメモを残していこうと思います。  よろしくお願いいたします。

Eclipseのショートカット

自分用メモ。
なので、随時更新。

  • タブの切り替え
    • Ctrl + F6
  • タブを閉じる
    • Ctrl + W
  • 矩形選択モードの切り替え
    • Shift + Alt + A
      • 矩形選択モードでShift押しながらカーソル移動すれば良い

【python】PyQt4のQtGuiを使ってみる その2

以下を参考にした。zetcode.com


# coding: utf-8
import sys
from PyQt4 import QtGui

class Example(QtGui.QMainWindow):
    
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()
        
    def initUI(self):
        # テキストボックス
        textEdit = QtGui.QTextEdit()
        self.setCentralWidget(textEdit)
        
        # closeにconnectするアクションを作成
        exitAction = QtGui.QAction(QtGui.QIcon('hoge[f:id:simudaru:20150809214147p:plain].ico'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
        
        # ステータスバーを作成
        self.statusBar()
        
        # メニューバーを作成
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAction)
        
        # ツールバーを作成
        toolbar = self.addToolBar('Exit')
        toolbar.addAction(exitAction)
        
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Main Window')
        self.show()
        
def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())
    
main()

f:id:simudaru:20150809212904p:plain
f:id:simudaru:20150809214147p:plain

・QMainWindowクラスを継承
・QTextEditは自由に編集できるテキストボックス

・QActionでアクションを作成
・statusBarでステータスバーを作成
・menuBarでメニューバーを作成
・addToolBarでツールバーを作成

【python】PyQt4のQtGuiを使ってみる その1

以下を参考にした。zetcode.com

# coding: utf-8
import sys
from PyQt4 import QtGui, QtCore

class Example(QtGui.QWidget):
    u'''
    下記内容の練習
    http://zetcode.com/gui/pyqt4/firstprograms/
    
    ・終了ボタンの設置。
    ・終了ボタンにバルーンヘルプを設定。
    ・ウィンドウ右上の終了ボタン押されたときに確認のダイアログを出す。
    ・ディスプレイの中心に表示。
    '''
    
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()
        
    def initUI(self):
        self.resize(250, 150)
        self.center()
        
        quit_button = QtGui.QPushButton(u'終了(確認なし)', self)
        quit_button.setToolTip(u'アプリケーションを終了します')
        quit_button.clicked.connect(QtCore.QCoreApplication.instance().quit)
        quit_button.resize(quit_button.sizeHint())
        quit_button.move(50, 50)
        
        self.setWindowTitle(u'First programsの内容')
        self.show()
    
    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def closeEvent(self, event):
        reply = QtGui.QMessageBox.question(self, u'確認',
                                           u'終了してよろしいですか?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
        
        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

main()

・QApplicationオブジェクトは必須
・QApplicationオブジェクトのexec_でアプリケーションを実行
・QWidgetオブジェクトはユーザーインターフェース

・QPushButtonはボタン

・QMessageBox.questionはYes/No付きメッセージボックスなどが作れる

・QToolTipを使うとウィジェットにマウスオーバーした際に
 バルーンヘルプが出せる

・QIconとsetWindowIconを使うとアイコンを設定できる

ipython notebookをAWSで利用

下記を参考にしたが、構成が変わっていた。
http://dev.classmethod.jp/cloud/aws/run-ipython-notebook-as-server-on-amazon-ec2/

まずはサーバーとして起動するための設定を行う

プロファイルを作成

ipython profile create nbserver


続いて、.ipython/profile_nbserver/ipython_config.pyに下記情報を追加。
参考URLでは.ipython/profile_nbserver/ipython_notebook_config.pyだったが、今日試したら同ファイルがなかった。

ポート番号は19999で書いているが、各自適当な番号に変更してください。

(冒頭)
# coding: utf-8

(末尾)
c.IPKernelApp.pylab = 'inline'
c.NotebookApp.ip = '*' # ローカルホスト以外からもアクセス可能にする
c.NotebookApp.open_browser = False # ブラウザが自動で開かないようにする
c.NotebookApp.port = 19999 # サーバーのポートを指定する

セキュリティー設定

AWSのセキュリティーグループから、インバインドのカスタムTCPで、指定したポートを空けておく。

サーバーとして起動

ipython notebook --profile=nbserver &

ブラウザからアクセス

ブラウザからアクセス
パブリックIP:ポート番号でアクセス
(http://パブリックIP:ポート番号)

【python】コードの品質管理について その3 unittest

下記の続き。simudaru.hatenablog.com
simudaru.hatenablog.com

下記を参考にした。
Python Project Howto (日本語訳) — Python Project Howto 日本語訳
d.hatena.ne.jp

unittest

前回に引き続き、fizzbuzzの例を示す。

fizzbuzz.py
# coding: utf-8
""" FizzBuzz問題 """


def fizzbuzz(x):
    """ FizzBuzz関数

    引数xが3で割り切れる場合には'Fizz'を、
    引数xが5で割り切れる場合には'Buzz'を、
    引数xが3でも5でも割り切れる場合には'FizzBuzz'を、
    それ以外の場合は引数xを返す
    """
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    else:
        ans = 'Buzz'
    return ans


参考URLに従い、以下のような構成とした。
./FizzBuzz
|--/src
| |--__init__.py
| |--fizzbuzz.py
|--/test
| |--sample_fizzbuzz.py
|--setup.py

__init__.py
from fizzbuzz import *
test_fizzbuzz.py

unittest.TestCaseを継承したテスト用クラスを作成し、
テストの関数を作成する。

unittest.TestSuiteを利用するとテストをまとめることができるのかな。
今回はテストが1個だが、利用しておく。

# coding:utf-8
import unittest
from fizzbuzz import fizzbuzz


class TestFizzbuzz(unittest.TestCase):
    def test_15(self):
        self.assertEqual('FizzBuzz', fizzbuzz(15))
        self.assertEqual('FizzBuzz', fizzbuzz(45))

    def test_3(self):
        self.assertEqual('Fizz', fizzbuzz(3))
        self.assertEqual('Fizz', fizzbuzz(12))

    def test_5(self):
        self.assertEqual('Buzz', fizzbuzz(5))
        self.assertEqual('Buzz', fizzbuzz(20))

    def test_x(self):
        self.assertEqual(1, fizzbuzz(1))
        self.assertEqual(4, fizzbuzz(4))


def suite():
    suite = unittest.TestSuite()
    suite.addTests(unittest.makeSuite(TestFizzbuzz))
    return suite
setup.py

パスを通し、テスト対象のsuiteを指定する。

# coding:utf-8
from setuptools import setup, find_packages
import sys
sys.path.append('./src')
sys.path.append('./test')


setup(
    name="Fizzbuzz",
    version="0.1",
    packages=find_packages(),
    test_suite='test_fizzbuzz.suite'
)


これでテストが可能になる。
$ python setup.py test

running test
running egg_info
writing Fizzbuzz.egg-info\PKG-INFO
writing top-level names to Fizzbuzz.egg-info\top_level.txt
writing dependency_links to Fizzbuzz.egg-info\dependency_links.txt
reading manifest file 'Fizzbuzz.egg-info\SOURCES.txt'
writing manifest file 'Fizzbuzz.egg-info\SOURCES.txt'
running build_ext
test_15 (test_fizzbuzz.TestFizzbuzz) ... ok
test_3 (test_fizzbuzz.TestFizzbuzz) ... ok
test_5 (test_fizzbuzz.TestFizzbuzz) ... ok
test_x (test_fizzbuzz.TestFizzbuzz) ... FAIL

======================================================================
FAIL: test_x (test_fizzbuzz.TestFizzbuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test\test_fizzbuzz.py", line 20, in test_x
    self.assertEqual(1, fizzbuzz(1))
AssertionError: 1 != 'Buzz'

----------------------------------------------------------------------
Ran 4 tests in 0.003s

FAILED (failures=1)

エラーが出ないようにコードを修正し、pep8やpylintも再度使用して、最終的に以下のようなコードが完成した。

fizzbuzz.py
# coding: utf-8
""" FizzBuzz問題 """


def fizzbuzz(x):
    """ FizzBuzz関数

    引数xが3で割り切れる場合には'Fizz'を、
    引数xが5で割り切れる場合には'Buzz'を、
    引数xが3でも5でも割り切れる場合には'FizzBuzz'を、
    それ以外の場合は引数xを返す
    """
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    elif x % 5 == 0:
        ans = 'Buzz'
    else:
        ans = x
    return ans

$ python setup.py test

running test
running egg_info
writing Fizzbuzz.egg-info\PKG-INFO
writing top-level names to Fizzbuzz.egg-info\top_level.txt
writing dependency_links to Fizzbuzz.egg-info\dependency_links.txt
reading manifest file 'Fizzbuzz.egg-info\SOURCES.txt'
writing manifest file 'Fizzbuzz.egg-info\SOURCES.txt'
running build_ext
test_15 (test_fizzbuzz.TestFizzbuzz) ... ok
test_3 (test_fizzbuzz.TestFizzbuzz) ... ok
test_5 (test_fizzbuzz.TestFizzbuzz) ... ok
test_x (test_fizzbuzz.TestFizzbuzz) ... ok

----------------------------------------------------------------------
Ran 4 tests in 0.003s

OK

今回はpep8やpylintを通してからunittestを通したが、この辺は臨機応変にやったほうが良いか。
あるいは、手順決めておいたほうが良いか。


pylintで8点以上取ろうとするとドキュメンテーションコメントが必要になるので、この程度のコードでも時間がかかる。
その分、品質は上がる気はする。

pep8は慣れれば修正少なく済みそう。

unittestはこれも時間がかかるが、品質は間違いなく上がるはず。
実際、今回コードのバグを防ぐことができた。
(わざとらしい例ではあるが)

何度かやって慣れる必要がありそうだ。

【python】コードの品質管理について その2 pylint

下記の続き。simudaru.hatenablog.com

下記を参考にした。
Python Project Howto (日本語訳) — Python Project Howto 日本語訳

pylint

pipでインストール可能
コードの多くの潜在的な問題を警告してくれる。
参考URLによると、8点以上というのが一つの基準のようだ。


前回に引き続き、fizzbuzzの例を示す。

fizzbuzz.py
# coding: utf-8
# ---------------------------------------------------------
# FizzBuzz問題
# ---------------------------------------------------------


def fizzbuzz(x):
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    else:
        ans = 'Buzz'
    return ans

$ pylint fizzbuzz.py

No config file found, using default configuration
************* Module fizzbuzz
W:  3, 0: Cannot decode using encoding "utf-8", unexpected byte at position 10 (
invalid-encoded-data)
C:  1, 0: Missing module docstring (missing-docstring)
C:  7, 0: Invalid argument name "x" (invalid-name)
C:  7, 0: Missing function docstring (missing-docstring)


Report
======
8 statements analysed.

Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|class    |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|method   |0      |NC         |NC         |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|function |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+



Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |8      |53.33 |NC       |NC         |
+----------+-------+------+---------+-----------+
|docstring |0      |0.00  |NC       |NC         |
+----------+-------+------+---------+-----------+
|comment   |4      |26.67 |NC       |NC         |
+----------+-------+------+---------+-----------+
|empty     |3      |20.00 |NC       |NC         |
+----------+-------+------+---------+-----------+



Duplication
-----------

+-------------------------+----+---------+-----------+
|                         |now |previous |difference |
+=========================+====+=========+===========+
|nb duplicated lines      |0   |NC       |NC         |
+-------------------------+----+---------+-----------+
|percent duplicated lines |0   |NC       |NC         |
+-------------------------+----+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |3      |NC       |NC         |
+-----------+-------+---------+-----------+
|refactor   |0      |NC       |NC         |
+-----------+-------+---------+-----------+
|warning    |1      |NC       |NC         |
+-----------+-------+---------+-----------+
|error      |0      |NC       |NC         |
+-----------+-------+---------+-----------+



Messages
--------

+---------------------+------------+
|message id           |occurrences |
+=====================+============+
|missing-docstring    |2           |
+---------------------+------------+
|invalid-name         |1           |
+---------------------+------------+
|invalid-encoded-data |1           |
+---------------------+------------+



Global evaluation
-----------------
Your code has been rated at 5.00/10

色々出力された。最後に点数が出力される。
指摘事項を直していくと、最終的に以下のようになった。

fizzbuzz.py
# coding: utf-8
""" FizzBuzz問題 """


def fizzbuzz(x):
    """ FizzBuzz関数

    引数xが3で割り切れる場合には'Fizz'を、
    引数xが5で割り切れる場合には'Buzz'を、
    引数xが3でも5でも割り切れる場合には'FizzBuzz'を、
    それ以外の場合は引数xを返す
    """
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    else:
        ans = 'Buzz'
    return ans

$ pylint fizzbuzz.py

No config file found, using default configuration
************* Module fizzbuzz
C:  5, 0: Invalid argument name "x" (invalid-name)


Report
======
8 statements analysed.

Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |1          |=          |100.00      |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|class    |0      |0          |=          |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|method   |0      |0          |=          |0           |0        |
+---------+-------+-----------+-----------+------------+---------+
|function |1      |1          |=          |100.00      |0.00     |
+---------+-------+-----------+-----------+------------+---------+



Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |8      |40.00 |8        |=          |
+----------+-------+------+---------+-----------+
|docstring |8      |40.00 |8        |=          |
+----------+-------+------+---------+-----------+
|comment   |1      |5.00  |1        |=          |
+----------+-------+------+---------+-----------+
|empty     |3      |15.00 |2        |+1.00      |
+----------+-------+------+---------+-----------+



Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |0        |=          |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |0.000    |=          |
+-------------------------+------+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |1      |2        |-1.00      |
+-----------+-------+---------+-----------+
|refactor   |0      |0        |=          |
+-----------+-------+---------+-----------+
|warning    |0      |0        |=          |
+-----------+-------+---------+-----------+
|error      |0      |0        |=          |
+-----------+-------+---------+-----------+



Messages
--------

+-------------+------------+
|message id   |occurrences |
+=============+============+
|invalid-name |1           |
+-------------+------------+



Global evaluation
-----------------
Your code has been rated at 8.75/10 (previous run: 7.50/10, +1.25)

引数名が短すぎるというメッセージが残っているが、
この程度の関数ならxで十分だろう。

次回はUnittestについて。

【python】コードの品質管理について その1 pep8

コードの品質管理について少しメモ。

下記を参考にした。
Python Project Howto (日本語訳) — Python Project Howto 日本語訳

pep8

pipでインストール可能
「PEP 8」というスタイルガイドに従っているかチェックしてくれる。
これを使えば、コードのフォーマットを揃えるのに役立つはず。

pypi.python.org


単純な例を示す。

fizzbuzz.py
# coding: utf-8
# ---------------------------------------------------------
# FizzBuzz問題
# ---------------------------------------------------------

def fizzbuzz(x):
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    else:
        ans = 'Buzz'
    return ans

$ pep8 --first fizzbuzz.py

fizzbuzz.py:6:1: E302 expected 2 blank lines, found 1

詳細は以下のようにして確認できる
$ pep8 --show-source --show-pep8 hoge.py

fizzbuzz.py:6:1: E302 expected 2 blank lines, found 1
def fizzbuzz(x):
^
    Separate top-level function and class definitions with two blank lines.

    Method definitions inside a class are separated by a single blank line.

    Extra blank lines may be used (sparingly) to separate groups of related
    functions.  Blank lines may be omitted between a bunch of related
    one-liners (e.g. a set of dummy implementations).

    Use blank lines in functions, sparingly, to indicate logical sections.

    Okay: def a():\n    pass\n\n\ndef b():\n    pass
    Okay: def a():\n    pass\n\n\n# Foo\n# Bar\n\ndef b():\n    pass

    E301: class Foo:\n    b = 0\n    def bar():\n        pass
    E302: def a():\n    pass\n\ndef b(n):\n    pass
    E303: def a():\n    pass\n\n\n\ndef b(n):\n    pass
    E303: def a():\n\n\n\n    pass
    E304: @decorator\n\ndef a():\n    pass


最初の関数やクラスの前には2行の空白行を開けるらしい。なるほど。

参考にfizzbuzz.pyを直す

fizzbuzz.py
# coding: utf-8
# ---------------------------------------------------------
# FizzBuzz問題
# ---------------------------------------------------------


def fizzbuzz(x):
    if x % 15 == 0:
        ans = 'FizzBuzz'
    elif x % 3 == 0:
        ans = 'Fizz'
    else:
        ans = 'Buzz'
    return ans

$ pep8 --first fizzbuzz.py

fizzbuzz.py:6:1: E302 expected 2 blank lines, found 1

再度実行
$ pep8 --first fizzbuzz.py

メッセージが出なくなればOK。