くろねこ日記

ソフトウェアに関する技術メモが多いです.

VimのコンパイルとJedi-Vimの設定と第二回Sapporovimのお礼

はじめに

Vimコンパイル(オプション指定をメモ)とjedi-vimではまったところをメモしておきます.

というのもhomebrewやバイナリ配布のVimではpyenvにあるpythonパスを読んでくれないためにjedi-vimがうまく動いてくれなかったからです.

そこで今回は解決策の一つとしてらぁさんが作っているvimenv(https://github.com/raa0121/vimenv)を使ってvim7.4を導入して,そのときにビルドすることで~/pyenv/shims以下を呼ぶようにします. そのあとにjediのインストールを行なって補完なども効くようにするというものです.

何度かこの方法を使う機会がありました.そのたびに,コマンド履歴を参照して調べるのがツラいので今日こそメモしておきます.

あとここに書いてあることは第二回Sapporo.vimで@thincaさんと@raa0121さんに教えていただきましたのでここでお礼を述べさせていただきます.

ありがとうございました!

vimenvの導入

vimenvは次のような手順で導入してください

git clone https://github.com/raa0121/vimenv.git ~/.vimenv

そのあとにこちらのブログで紹介されているvim-buildを導入します http://yasu-n1.hatenablog.com/entry/2013/10/03/201819

cd ~/.vimenv
git clone https://github.com/yasu-n/vim-build.git ~/.vimenv/plugins/vim-build
exec $SHELL -l

ここまで行ったら次にvimのビルドを開始します.ただし,pythonとタイプすると~/.pyenv/shims/pythonから呼べるようにしておいてください.

今回のvimはluajitもオプションに加えようと思います. 僕の場合,luajitは以下のようにluaenvで導入したものを使ってます.

luaenv install luajit-2.0.3
luaenv global 2.0.3
luaenv rehash

ではここからvimenvでvimをインストールしましょう.

vimenv install -- --with-compiledby=kuroneko --enable-pythoninterp --enable-perlinterp --enable-python3interp --enable-rubyinterp --with-lua-prefix=/path/to/.anyenv/envs/luaenv/versions/luajit-2.0.3 --enable-luainterp --with-luajit --enable-multibyte --enable-fail-if-missing

長いですがこんな感じです.

jediでつまづいたところ

jedi-vimpythonを強力に補完したり,pydocをコード中に参照してくれるプラグインです.

ただし,jediはvim上で動くpythonpathから参照するため,pythonpathの設定をやらないでおくとコード補完がうまく効かない恐れがあります. 僕はしばらくの間これで悩んでいたのですがPYTHONPATHの設定を追加しておけば良かったようです.

たとえば,pyenvの3.4.1のライブラリをjediに参照させたいなら zshrcかbashrcの上で

export PYTHONPATH='/path/to/pyenv/versions/3.4.1/lib/python3.4/site-packages/'

の一文を追加するだけです

これでvimを起動して

:python import sys;print(sys.path)

で今追加したPATHが表示されることを確認してください.

第二回Sapporo.vimへのお礼

今日書いた内容は第二回Sapporo.vimもくもく会に参加したときにやっていたことです. PYTHONPATHがvimからうまく参照できてないところについてはthincaさんに教えていただきました(quickrunで有名な方が向かいの席でびっくり...).vimenvの紹介と使い方はらぁさんに教えていただきました.

勉強会は2時間程度遅刻したこともあって(くろねこ界の最長記録樹立!),もくもくタイム自体は少なかったのですが,有益な時間を過させていただきました.

ただ,会場についてから,自宅同然にもくもくしてしまったので勿体ないことをしてました(ただ,もくもくするのは勿体ないという声が聞こえてきましたがその通りですね).もうちょっと他の人とも交流できればよかったのですが,タイミングが掴めませんでした(このあたりコミュニケーション能力の低さが顕著に表れてますね...).またお会いする機会があれば楽しみにしております.

この日は発表もあって,@supermomongaさんがEmacs上でVimと同等の動作をさせることができるEmacsEvilの発表(Evilの今後に期待),@Linda_ppさんがVim初心者向けに講座を開いてくれました(わかりやすかったです).

ありがとうございました.

まとめ

vimenvでvim導入してみた.

jediのはまったところをメモ

第二回Sapporo.vimの感想とお礼,

PyConJPの告知とCFPが補欠だった件について

はじめに

今年もPyConJP2014が9/12~9/15に開催されます.

今回はPyConJP2014の告知のつもりで記事を書きます. というのも遠方者支援のアピールポイントに「ブログでの告知も行ないます」と書いたこともあったので後に引けなくなったからです.

PyConJPはチュートリアルと開発スプリントを含めると4日間となります.昨年,参加した僕が会場の雰囲気を紹介することで,PyConJP2014への参加に興味を持っていただければと思います.

また,CFPへの応募を今年はやってみました.応募するときに細かな項目があり,どんなことを書いたのかを載せておこうと思います.ただし,アクセプトはされず,補欠枠に回ったので発表できる可能性が低くなりました.反面教師として読んでいただければ良いと思います.

昨年のPyConAPAC

昨年開催されたのはPyConAPACであり,PyConJPではありません.しかしながら,チュートリアル→コアのカンファレンス2日→開発スプリントという構成みたいですし,APACと日程的に似ているので同じと考えても良いと思います.

チュートリアル

チュートリアルでは2コースのうちどちらかに参加することができ,僕はdjango入門のチュートリアルに参加しました.参加の動機としては僕自身Webフレームワークを使った経験が殆ど無く,前々から興味こそあったけれど手が出てなかったのでチャレンジしてみようという気持ちで参加しました.

実際に業務でdjangoを日頃から使っているプロフェッショナルの方に昼から夕方までみっちりハンズオン形式で教えてもらえます.値段にするとPyConへの参加費用よりも高いのですが,値段に比べて内容がだいぶ得だと思います.

具体的にはECサイトをハンズオン形式で作ってみようという内容でした. django初心者向けに使い方がまとまった資料(紙ベース&電子ベース)が配布されました.その資料を元に解説&演習が進んでいきました.

ハンズオン形式なので,進めていく段階でエラーが出てもすぐに聞けます.当時の僕ならエラーを読んでもピンと来なかったような気はするので初歩的なエラーで一日潰していたと思います.そんなときに講師の方にすぐに聞いてエラーの潰し方とかコツを把握できるというのは,時間短縮だけでなくウェブや本では学べないポイントの一つですね. おかげで資料の最後まで到達して一通りECサイトを手元で動かすことができて良かったです.

それから,昨年はチュートリアル後に懇親会も開かれました.チュートリアルだと定員枠が決まっており人数も少ないので,北海道からボッチ参加した僕にとっては知り合いを増やす良い機会でした. チュートリアルの懇親会だと人数が少ない分,参加者の影に隠れることが少なく,話をするきっかけが多いので案外穴場のような気がします(残念な人理論ですが).実際に数人の方と知り合いになり,残りのカンファレンスでは充実して過すことができました.

PyConJPに参加するときにはよかったら@kuroneko1988と書かれた参加証を見かけたら声かけてくれたら嬉しいです.

今年は https://pycon.jp/2014/tutorials/ にあるように - サーチエンジン開発 - Pythonの基礎研修 - PyData入門 のようです.

まだ応募してませんが,今年もどれかに参加したいです.

カンファレンス本体

チュートリアルの翌日から2日間はPyConJPのコアとなる部分です.実際に参加人数はチュートリアルとスプリントでは数十人でしたが,数百人規模となります.

基調講演も開かれており,Dropboxの開発者とSphinxの開発者の講演でした.面白かったです. カンファレンスの発表自体,英語発表が多めではありましたが,基調講演では同時通訳もあるので,英語が怖い人は通訳で聞いても良いかもしれません.でも日本に居ながらして英語と日本語が混る機会ってあまりないので,生英語を聞いても良いかもしれませんね.僕は英語得意ではありませんが,IT系の話題は横文字が多いので英語で聞いてもわかる場合が多いです.

それからランチタイムは多数の出席者が居てジョブボードや書籍販売コーナを覗いてみたりしました.

あとは企業ブースがかなり出展していて,ドリンクとかチョコレートを頂いたり,bitbucketTシャツを頂いたりもしました.

開発スプリント

開発スプリントはレベルが高くて参加するか悩むという声をチラホラ聞いていましたが,折角なので参加してみました.実際にはもくもく会+テーマが設定されているという形式でした.sphinxの翻訳をテーマにして動いているところもありましたし,人によってはもくもくと開発している人も居て放牧的な雰囲気があって良かったです.

もくもくしているだけだと自宅で作っているのと変わりないということがあるので,テーマがあるのは良いことだと思いました.もちろんもくもくしたい人は黙って作業するのも良いですね. それから開発スプリント中は他のセッションを覗いて息抜きをしたりと話かけやすい雰囲気があって良かったです.

僕はMyHDLを使ってみるという内容にしました.MyHDLはPythonでHDLコードを書けるというもので,Pythonで書いたコードがFPGAの上で動きます.FPGA自体は聞いてこそいたのですが,触ったことすらなかったので,初歩の初歩から教えてもらいました(ご迷惑おかけしました(汗)).

テーマの目標としては簡単なパイプラインを作って入力した2つの数字を四則演算するというのを作ることになりました.結果的にはタクトスイッチを押すとクロックのHIGHになり,ボタンから話すとクロックのLOWに落ちるという形を利用して人の計算速度よりも遅い計算機を作ることができました.

CFPの応募

PyConAPACに参加して多少意識が高まったところで今年はスピーカとして応募してみることにしました.事前に倍率が高そうな印象は受けていたので,ダメ元での応募でした.

前述した通り補欠枠になったので,もし読んでいる方でCFPに来年は応募するぞという方がいらっしゃいましたらこれを多少なり参考にされて挑まれることを期待してます.

とりあえず書ける範囲で載せておきます,

カテゴリ
GUI Programming / GUI プログラミング 

言語
Japanese 

Python レベル
初級 

対象者
デスクトップアプリケーションを作ったことのない方やkivyというライブラリを知らない方,kivyを知ってはいても具体的な使い方を知らない方を対象としております. 

目的
kivyというデスクトップアプリケーションの紹介,kivyを利用したデスクトップアプリケーションの作り方です. 

時間枠
30分枠希望

説明
デスクトップアプリケーションを開発するためのライブラリは様々存在しますが,今回はクロスプラットフォーム対応のデスクトップアプリケーションフレームワークkivyの簡単な使い方を紹介と個人的に使用した事例についてお話します. 

概要
デスクトップアプリケーションを開発するためのライブラリは様々存在しますが,今回はクロスプラットフォーム対応のデスクトップアプリケーションフレームワークkivyの簡単な使い方を紹介と個人的に使用した事例についてお話します.kivyの概要から導入,簡単なコードを紹介して作り方を知っていただこうと思います. 
具体的にはHelloWorldからタイマを利用したデスクトップアプリケーションを紹介させてもらいます.
最後に実際にkivyを利用したデスクトップアプリケーションの紹介をさせていただきます. 

アウトライン
    発表内容
    kivyの概要
    kivyでHelloWorld
   タイマを動かしてみる
   これまでに作製した内容を紹介
   まとめ 

追加情報
 

メモ

こんな感じですね.

応募したときの感想として項目が多いということです,発表者名・言語・対象・発表時間・概略くらいのものだと思っていたのですが,アウトラインや目的に至るまで細かく設定されています.すでに準備万端な人であればスラスラとかけると思いますが,今までやったのをせっかくだし発表してみようかなとぼんやりしたイメージでの応募ではアクセプトまではキツかったかもしれません.

アウトラインや目的の部分については概略に書いてしまっているのでだいぶ重複しており,そこが落されたポイントの一つかなという気もします.

あとは内容もkivyでデスクトップアプリの作り方を紹介してもググったり書籍を読んで何とかなるので,アクセプトされるほどの面白みには欠けたかもしれません.

そんなところでしょうか.CFPについては書き方自体をそもそも悪かったところも多いでしょうし,ここに書いてあるのはあくまでも憶測です.反面教師にして,ちょっとでも足しにしてくれれば嬉しいです.

まとめ

PyConJP2014のちょっとした宣伝のつもりで,昨年のPyConAPACの様子を書いてみました.

CFP応募した内容を載せてみました.

追記

ブログ公開した直後に次のようなご指摘がありました.

アクセプト枠,補欠枠,リジェクト枠の3つがあったんですね.ご指摘感謝.

そのため本記事の一部を修正・変更しました.

「はじめてUNIXで仕事をする人が読む本」を読んだ

はじめに

オープンソースカンファレンス2014に参加してきました(今更ですが).

オープンデータハッカソンに参加したり(楽しかったので次回も参加できたら是非), LT(カーネル空間上に草生やす発表が特に面白かったです)を楽しませてもらったり,Sinatra札幌ブースでは僕が作った未完成ゲーム(お化けをやっつけるゲーム)が走っておりヒヤヒヤしたりと(展示していただいて感謝)充実した一日でした.

オープンソースカンファレンスの懇親会にも参加させていただきました.ジンギスカン美味しかったです.懇親会ではLTが再び開かれていたり,様々なグッズが貰えるじゃんけん大会(オライリーTシャツ頂きました)や学生・駆け出しエンジニア向けにグッズのバラマキがありました.

グッズのバラマキでは,以前から読みたかった「はじめてUNIXで仕事をする人が読む本」というのを頂きました.何方から「読んだらブログに書いてね」と言われた気もしたので大分時間が経ってしまいましたが,感想を載せておきます.遅くなってすみません.

構成

以下が本書の構成です.てんこ盛りですね.しかし,これでざっと200ページ弱.なので,UNIXはどういうものか,何が便利なのかよくわからないという読者には最適な本だと思います. 事実,僕も普段からUNIX(OSXの上)を使っておりますが,周りに使える人も居ないまま独りで学んだこともあって,UNIX使いはこのくらい使えれば良いよという指標を頂いたようで安心できました. それだけでも読む価値はあったと思います.

第1部 生活環境編
第1章 ログインログアウト
1.1 そもそもログインとは
1.2 TELNETによるリモートログイン
1.3 SSHによるリモートログイン
1.4 ログアウト
第2章 UNIXの基本操作
2.1 シェル
2.2 リダイレクションとパイプ
2.3 UNIXのファイルシステム
2.4 基本のファイル操作
2.5 パーミッション・オーナーの管理
2.6 正規表現
2.7 grep
2.8 sed
2.9 awk
2.10 アーカイバ
2.11 その他のコマンド
第3章 テキストエディタ
3.1 基本のテキストエディタ
3.2 限定された環境でのファイル編集
3.3 ViとVim
3.4 Emacs
第4章 作業の自動化(シェルスクリプト)
4.1 シェルスクリプトによる作業自動化の必要性と利点
4.2 Bourne shellについて
4.3 簡単なスクリプトの作成と実行
4.4 シェルスクリプトの実用例
第5章 オンラインマニュアル
5.1 オンラインマニュアルを必要とする場面
5.2 氾濫する情報の危険性
5.3 manコマンド
5.4 infoコマンド
5.5 ヘルプメッセージ
第6章 セキュリティ
6.1 UNIXにおけるセキュリティ
6.2 ルート権限の獲得方法
6.3 共通鍵暗号と公開鍵暗号
6.4 SSHの応用
6.5 PGPによる暗号化、電子署名
第7章 UNIXシステム管理
7.1 UNIXにおける管理作業
7.2 起動とシャットダウン
7.3 ユーザとグループの管理
7.4 パッケージ管理
7.5 TCP/IPネットワーク管理
7.6 DNS(名前サービス)
7.7 サービスの管理
7.8 トラブルシュート
第2部 プログラミング環境編
第8章 UNIXプログラミング環境
8.1 プログラミング環境概要
8.2 C言語による開発実例
8.3 Javaによる開発実例
8.4 LL言語による開発実例
第9章 バージョン管理システム
9.1 バージョン管理システムとは
9.2 バージョン管理システムの種類
9.3 バージョン管理システムの使い方
9.4 Subversionの使い方
9.5 Gitの利用方法
第10章 ソースコードからのドキュメントの作成
10.1 はじめに
10.2 ドキュメント生成ツールの種類
10.3 ドキュメント生成ツールの利用方法
第11章 ソフトウェアライセンス
11.1 ライセンスを考慮する理由
11.2 オープンソースライセンス
第3部 ネットワーク技術編
第12章 UNIXとネットワーク技術
12.1 TCP/IP実装の公開と普及
12.2 LANとWAN
12.3 ネットワーク端末としてのUNIX
第13章 OSI参照モデル
13.1 OSI参照モデル
13.2 TCP/IPとOSI参照モデル
第14章 データリンク層
14.1 データリンクとは
14.2 データリンクの基本
14.3 Ethernet
14.4 無線LAN
14.5 Point-to-Point接続
第15章 IPと関連プロトコル
15.1 IPの基本
15.2 IPv4とIPv6
15.3 IPアドレス
15.4 特殊なIPアドレス
15.5 ルーティング
15.6 関連プロトコル
第16章 TCPとUDP
16.1 ポート番号
16.2 UDP
16.3 TCP
16.4 TCPのコネクション
16.5 TCPの通信
16.6 TCP通信の制御
16.7 TCPとUDPの使い分け
第17章 アプリケーションプロトコル
17.1 Webアクセス(HTTPHTTPS)
17.2 電子メール(SMTPPOPIMAP)
17.3 リモートログイン(TELNETSSH)
17.4 ファイル転送(FTPrsync)
17.5 ファイル共有(NFSSMB)
17.6 VoIP(SIPRTP)
17.7 システム運用管理(DNSDHCPNTPSNMP)
17.8 Xプロトコル
第18章 IP関連の技術
18.1 名前解決
18.2 IPアドレスの付与
18.3 アドレス変換(NAT・NAPT・IPマスカレード)
18.4 トラブルシューティング
第19章 ネットワークセキュリティ
19.1 ネットワーク上の攻撃
19.2 認証システム
19.3 通信フィルタとファイヤウォール
19.4 通信の暗号化
19.5 VPN

良かったところ

本当にざっくりと網羅的にUNIXの便利ツールの使い方と紹介が書かれており,さきほど書いた指標を知りたい人におすすめの一冊です.ただ,UNIXのみというよりも,オープンソース界隈で必要とされるツール(VCS,ソフトウェアライセンスとか)の紹介が多く,Linux使いも読んでも良さそうな記述が多かったです(ところどころLinuxの話も記載されている).

また,低レイヤな部分についても書かれており(OSI参照モデルなど)こういう大事なところもきっちりフォロウしているのは凄いと思いました.

  • とりわけ面白かったところ

    • Javaの開発事例というのがあるのですが,JDKコマンドラインツールだけで開発する事例を載せてたりとJavaの本にしてはユニークかもしれません.

    • 「限定された環境でのファイル編集」という項目では,UNIXエンジニアは,破損したファイルシステムや組み込み環境のようにテキストエディタも使えない環境で作業することがあります.というようなことが書かれております.どんな環境なのか想像しにくいですが,echoやcat,readを駆使してファイルを編集する技を見せてたりと,シェル芸が漂っていて面白かったです.

    • ツールについてもその誕生経緯など歴史的な記述も多く非常に参考になりました.

悪かったところ

網羅的に書かれすぎており,一つ一つの話について消化不良感が否めないです. ソフトウェアライセンスについてもう少し細かい紹介が欲しかったです. なので,この一冊から普段使っているツールについて新しい知識を得るということは期待しないほうが良いです(そういう本ですし).

LL言語の紹介では本書の紹介ではpythonrubyについて書いてあるにも関わらず,perlの基本的な紹介で終ったりと,ちょっとくらい対象読者に書かれていたPythonRubyについても紹介したらどうかなとは思いました.

まとめ

日頃からUNIXに触れる人にとっては一般的にこのくらい知っておけばOKという基準が示されているようで安心できます.

UNIXを使ったことがない人にとっては,網羅的に書かれているので,読んだら一つ一つ後で調べたら良いかもしれません.

gunicorn+nginx+flaskで動かしてみた

はじめに

Flask製のアプリケーションをgunicornとnginxを使って動かす方法をメモしておきます.

動かすにあたって簡単なサンプルコードを載せておきます

ここではDebian7を対象に書きます.

アプリケーションの全体構成

ここではhelloというアプリケーションでアクセスされると「Hello!」と返してくれるウェブサプリケーションを想定します.

初期の全体のディレクトリ構成は以下のようになります

/site
├── hello.py
└── tmp

FlaskでHello!を出す

hello.py

#!coding:utf-8

from flask import Flask

app = Flask(__name__)

@app.route('/hello', methods=['GET'])
def hello():
    return 'Hello!'

if __name__ == '__main__':
    app.run()

これだけです.

flaskの細かい使い方は以前のブログ記事を参考にしてください フレームワーク素人がFlask触ってみた

nginxの設定

nginxでgunicornより生成されるsocketファイルを読むための設定を行ないます.

vim /etc/nginx/site-available/default

upsteram hello{
    server unix:/site/tmp/unicorn_flask.sock
}

server {

    location /hello{
        proxy_pass http://hello
    }
}

gunicornの設定

先程nginxで指定したsocketファイルを次のように生成します.

/site上で

gunicorn hello:app --bind unix:./tmp/gunicorn_flask.sock -D

あとは

/etc/init.d/nginx reload

localhost/hello

にアクセスしてhello!が返ってくることを確認

まとめ

gunicornとnginx,flaskの連携についてまとめた.

ArduinoをCLIベースに開発できるino

はじめに

最近は電子工作にArduinoを使うことが多いです. 近年では電子工作の裾野を広げる意味では一躍買っているマイコンですね.

Arduinoの公式では書き込みやプログラミングが行えるIDEが配布されています.多くのユーザはそちらのIDEを使うことが多いかもしれません.しかし,VimEmacsなど自分の好きなエディタやCLIを使いたい方も居ると思います. 僕も普段の開発にはVimを使うので,そのような場合は作成したコードをIDEに読み込ませてからArduinoへの書き込みを行なうという面倒なことをしてました.

今日はそんな面倒なことをしているかもしれない方へinoというCLIで扱えるArduino開発環境を紹介します.

inoを使えばプロジェクトのディレクトリ生成からビルド・書き込み,シリアル通信までできます.

inoのインストールと概要

inoはpythonで作られており,pypiにも登録されているのでpipを使ってインストールができます.

ただし,python3では動作しなかったので,python2.7で導入することを推奨します.

なおインストールは

pip install ino

からできます.

inoはプロジェクト生成からコードのビルド,マイコンへのプログラムアップロード,シリアル通信までサポートしています.

以下に普段の開発で最低限使うコマンドをまとめました.

  • コマンド

    • プロジェクトの生成:init
    • ビルド:build

      • -m:arduinoの種類を設定できる(ArduinoMiniの場合:ino build -m mini)
    • 書き込み:upload

    • serial:シリアルターミナル

といったところでしょうか.他にもコマンドが沢山あります.

ino -h

から確認ができます.

実際に使ってみる

ざっくり説明したところで,具体的な使い方を示しましょう.

ここではArduinoからシリアル経由でHelloWorldをひたすら送りつづけるようなプログラムを作ることを目的に説明します.

まずはプロジェクトを生成しましょう. 空のディレクトリを生成する必要があります.

ここでは

プロジェクト名:HelloSerial(任意)

としましょう.なので

mkdir HelloSerial

でプロジェクトディレクトリを生成できます.

HelloSerialに移動して

cd HelloSerial

そしてプロジェクトの生成をします.

ino init

すると

.
├── lib
└── src
    └── sketch.ino

というディレクトリが作成されます.

あとはsrcにあるsketch.inoにコードを書いていくだけです.

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    Serial.println("HelloWorld");
}

書き込んで保存したら次はビルドです

ino build

で実行できます.

ビルドに成功したら

ino upload

Arduinoにアップロードします.

アップロードしたら今度はHelloWorldがシリアル通信で送られているか確認しましょう.

ino serial

ArduinoからHelloWorldが送られてくれば成功です.

まとめ

CLIベースのArduino開発環境inoの紹介を行った.

inoを使えば,コードのビルド,書き込み,アップロードなどArduinoで開発するときに必要なことが一通りできる.

シンプルなThreading

はじめに

昨日,Threadingを使用したコードを書きました. 書いた動機としては,もともとスレッド処理を書いたことがない僕は少してこづったことと,オブジェクト指向的なコードとかはググれば出るのですが簡単なのが少なかったからです.頭の中を整理するつもりでメモしておきます.

そもそもThreadって何?

まずスレッドの意味ですが,「プログラムの実行コード一つ辺りの単位」のことらしいです. つまり2スレッドは実行コードが2つ走っているということになります.

実行コードというのはプログラムが終了するまで実行しつづけようとします. ですので実行コードが終了するということはその実行コードのスレッドが一つ消えるということになります.

ではプログラム言語に搭載されている機能としてのスレッドとはどういう意味をなすのかですが,これは実行コードを複数扱ったり停止したり破壊したりと実行コードそのものを制御するためのものです.「実行コード中に停止させたい」,「いくつか実行コードがあってそれらを並列に動かしたい」という場面に有効です.

シンプルなThreadingコード

まずはfooという"foo"という文字列を吐きつづける実行コード(関数という形ですが)をthreadingから制御してみようと思います.

実行コードの生成と開始をして,1秒待ったあと停止させるというものです. つまり,1秒間メインコードが停止しているときでも関係なくfooは動いていることになります.ですので,1秒間fooを出力するはずです. なお,Pythonには停止にあたるものが無いので,ここではflagを使ってwhileループを抜けさせたりするのに使ってます.

import threading
import time

def foo():
    while flag:
        print("foo")

th=threading.Thread(target=foo)
flag=True
th.start()
time.sleep(1)
flag=False
th.join()

注目すべきはflagをTrueにしたりFalseにするタイミングですね.flagはfoo関数のwhileを無限ループさせるのに必要となる変数です.flag=Trueであればwhile Trueとなりprint("foo")が無限に実行されます.Falseにすればwhile Falseとなりwhile文を抜けます.

実はこのwhileの制御が少し悩みました.whileを使って書きたくないなと思いつつも,今のところはflagによる制御が簡単かなと思っています.もし二回個別に実行したいときには再びthreading.Threadで生成してあげる必要がありますので注意してください. 次のようにするともう一度実行できます.

import threading
import time

def foo():
    while flag:
        print("foo")

th=threading.Thread(target=foo)
flag=True
th.start()
time.sleep(1)
flag=False
th.join()
th=threading.Thread(target=foo)
flag=True
th.start()
time.sleep(1)
flag=False
th.join()

また,スレッドにはjoinというのがあります.これもよく使われるみたいです. これは実行コードが終了するまでメインコードの動きを止めることができます.

例えばfooとhogeの二つの関数があり,fooを終えたあとにhogeを開始したいとします. しかしスレッドではfooとhogeを次にように書くとほぼ同時に実行されてしまいます.

import threading

def foo():
    for i in range(10):
        print("foo:"+str(i))

def foo2():
    for i in range(10):
        print("hoge:"+str(i))
th=threading.Thread(target=foo)
th.start()
th2=threading.Thread(target=foo2)
th2.start()

結果

foo:0
foo:1
foo:2
foo:3
hoge:0
foo:4
hoge:1
foo:5
foo:6
hoge:2
foo:7
foo:8
hoge:3
foo:9
hoge:4
hoge:5
hoge:6
hoge:7
hoge:8
hoge:9

わかりやすくfooとhogeに対して数字を割りふりました. 同時に実行するとfooとhogeが混ざりあっているのがわかりますね.前半fooが多いのはstartのタイミングがfooのほうが早いからだと思われます.

ではfooをstart直後にjoinを置いてみましょう.

import threading

def foo():
    for i in range(10):
        print("foo:"+str(i))

def foo2():
    for i in range(10):
        print("hoge:"+str(i))
th=threading.Thread(target=foo)
th.start()
th.join()
th2=threading.Thread(target=foo2)
th2.start()

結果

foo:0
foo:1
foo:2
foo:3
foo:4
foo:5
foo:6
foo:7
foo:8
foo:9
hoge:0
hoge:1
hoge:2
hoge:3
hoge:4
hoge:5
hoge:6
hoge:7
hoge:8
hoge:9

このようにfooが終わるまで待ってくれています.この例だとシングルタスクで動かしても大差ありませんが,例えばfoo,hoge,barの3つのスレッドがあり,fooとhogeはほぼ同時に走らせてbarはfooとhogeの後に実行したいときなんかは有効ですね.

まとめ

スレッドの基本的な考えかたと使いかたをメモしました.

  • スレッドとは実行コードの単位を示す.

  • PythonにはThreadingというスレッドそのものを扱うライブラリがあり,実行コードを並列に実行したり直列に実行したりできる.

MongoEngineつかってみた

はじめに

前回MongoDBをつかってみたという記事を載せました.その記事ではpyMongoを利用したMongoDBの操作を紹介しましたが,今日はPython上でMongoDBをOSMとして扱うことのできるMongoEngineの紹介をします.

MongoEngineインストール

インストールは簡単

pip install mongoengine

のみです.

使い方

学生情報を扱うデータベースを例に話を進めていきます. まずは,ドキュメントの追加と参照について説明します

追加と参照

  • データベース名:studentinfo

  • クラス名: Student(学生情報を扱う)

    • 要素:Name(学生名)

    • 要素:Number(学生番号)

import mongoengine

mongoengine.connect("studentinfo")

class Student(mongoengine.Document):
    Name = mongoengine.StringField()
    Number = mongoengine.IntField()

#DBの初期化を行なう(ブログの内容には直接関係しない)
Student.drop_collection()

db=Student()
db.Name="Taro"
db.Number=1
db.save()

for data in Student.objects:
    print data.Name
    print data.Number

出力だけならこれだけです.

もし特定のデータ(Number1にしましょう)だけ取りだしたいなら

import mongoengine

mongoengine.connect("studentinfo")

class Student(mongoengine.Document):
    Name = mongoengine.StringField()
    Number = mongoengine.IntField()

#DBの初期化を行なう(ブログの内容には直接関係しない)
Student.drop_collection()

db=Student()
db.Name="Taro"
db.Number=1
db.save()

for data in Student.objects(Number=1):
    print data.Name
    print data.Number

のようにすればNumber1のデータだけが表示されます

親子関係にあるデータベース

では次はMongoEngineで親子関係にあるデータベースを組んでみましょう. 例題として先程のStudentの加えて試験の結果を子とします.

  • データベース名:studentinfo

  • クラス名:Student

    • 要素:Name(学生名)

    • 要素:Number(学生番号)

  • クラス名:Math

    • 要素:score(点数)
  • クラス名:Science

    • 要素:score(点数)
  • クラス名:English

    • 要素:score(点数)

とします.

この場合はStudentから各科目(Math,Science,English)を呼べるようにします.

import mongoengine

mongoengine.connect("studentinfo")

class Math(mongoengine.Document):
    score = mongoengine.IntField()

class English(mongoengine.Document):
    score = mongoengine.IntField()

class Student(mongoengine.Document):
    name = mongoengine.StringField()
    math = mongoengine.ReferenceField("Math")
    english = mongoengine.ReferenceField("English")

こうします.実際にStudentを経由してMathやEnglishのデータを書き込むには 次のようにします.ここでは[学生名taro,数学100点,英語50点]というデータと[学生名jiro,数学70点,英語80点]として書いていきます

taro = Student()
math = Math()
english = English()
math.score=100
math.save()
english.score=50
english.save()
taro.name="taro"
taro.math=math
taro.english=english
taro.save()

jiro = Student()
math = Math()
english = English()
math.score=70
math.save()
english.score=80
english.save()
jiro.name="jiro"
jiro.math=math
jiro.english=english
jiro.save()

とします.mathとenglishそれぞれのインスタンスに各点数を代入したのちstudentのクラス変数に渡してますね.

値を取り出すには

for student in Student.objects:
     print student.name
     print student.math.score
     print student.english.score

のようにします. おそらく

taro
100
50
jiro
70
80

と出力されるはずです.

もし複数件入力されており,名前が"taro"だけのデータが欲しいときには

for student in Student.objects(name="taro"):
     print student.name
     print student.math.score
     print student.english.score     

結果

taro
100
50

のようにobjectsにname="taro"のように指定するだけです.

ここの部分を一つのコードにまとめると

import mongoengine

mongoengine.connect("studentinfo")

#クラスの定義
class Math(mongoengine.Document):
    score = mongoengine.IntField()

class English(mongoengine.Document):
    score = mongoengine.IntField()

class Student(mongoengine.Document):
    name = mongoengine.StringField()
    math = mongoengine.ReferenceField("Math")
    english = mongoengine.ReferenceField("English")

#DBの初期化を行なう(ブログの内容には直接関係しない)
Student.drop_collection()

#taroとjiroのドキュメントを追加
taro = Student()
math = Math()
english = English()
math.score=100
math.save()
english.score=50
english.save()
taro.name="taro"
taro.math=math
taro.english=english
taro.save()
jiro = Student()
math = Math()
english = English()
math.score=70
math.save()
english.score=80
english.save()
jiro.name="jiro"
jiro.math=math
jiro.english=english
jiro.save()

#Studentクラスに書かれているドキュメントをすべて取得
for student in Student.objects:
     print student.name
     print student.math.score
     print student.english.score

#taroのドキュメントのみ取得
for student in Student.objects(name="taro"):
     print student.name
     print student.math.score
     print student.english.score

上書き

次に既存のデータを上書きしたときについてですが,上記のjiroをsaburoに変更してみましょう.

jiro = Student.objects(name="jiro")
jiro.update(set__name="saburo")

のようにobjectsでデータを抜きだしてからupdate文で更新します. 更新の際にはset__のようにqueryを指定することができます.set__ query以外にもpush__ , unset__ , pull__などがあります 詳しくはこちらをお読みください(http://mongoengine-odm.readthedocs.org/guide/querying.html) .

まとめ

MongoEngineでデータの追加や参照,更新についてまとめました.