ludwig125のブログ

頑張りすぎずに頑張る父

c++でmsgpackを使ってみる

msgpackとは

MessagePack: It's like JSON. but fast and small.

MessagePackは、効率の良いバイナリ形式のオブジェクト・シリアライズ フォーマットです。
JSONの置き換えとして使うことができ、様々なプログラミング言語をまたいでデータを交換することが可能です。
しかも、JSONよりも速くてコンパクトです。
例えば、小さな整数値はたった1バイト、短い文字列は文字列自体の長さ+1バイトでシリアライズできます。

らしい

仕事で使う機会があったのでc++でサンプルコードを実行してみる

msgpackのインストール

MessagePack: It's like JSON. but fast and small.C/C++ msgpack のページに従う

準備

` インストール条件

gcc >= 4.1.0
cmake >= 2.8.0

gccバージョン確認

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.3' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) 

cmake確認

なかったのでインストール

sudo apt-get install cmake 
$ cmake -version
cmake version 2.8.12.2

msgpackのインストール

msgpackのgitはここ

github.com

$ git clone https://github.com/msgpack/msgpack-c.git
$ cd msgpack-c
$ cmake .
$ make
$ sudo make install

msgpackのバージョンを確認

msgpackのサンプルコードを実行

msgpack-c/QUICKSTART-CPP.md at master · msgpack/msgpack-c · GitHub

First program(単なるデータのシリアライズとデシリアライズ

コード

以下を hello.cpp という名前で保存

#include <msgpack.hpp>
#include <vector>
#include <string>
#include <iostream>

int main(void) {
        // serializes this object.
        std::vector<std::string> vec;
        vec.push_back("Hello");
        vec.push_back("MessagePack");

        // serialize it into simple buffer.
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, vec);

        // deserialize it.
        msgpack::object_handle oh =
            msgpack::unpack(sbuf.data(), sbuf.size());

        // print the deserialized object.
        msgpack::object obj = oh.get();
        std::cout << obj << std::endl;  //=> ["Hello", "MessagePack"]

        // convert it into statically typed object.
        std::vector<std::string> rvec;
        obj.convert(rvec);
}

コンパイル

$ g++ -Ipath_to_msgpack/include hello.cpp -o hello

実行
 $ ./hello 
["Hello", "MessagePack"]

Streaming into an array or map(配列やマップのシリアライズとデシリアライズ

msgpack-c/QUICKSTART-CPP.md at master · msgpack/msgpack-c · GitHub

ここにはシリアライズはあるが、デシリアライズの処理がないので、自分で作ってみる

$ cat stream.cpp 
#include <msgpack.hpp>
#include <iostream>
#include <string>

#include <sstream>

int main(void) {
        // serializes multiple objects into one message containing an array using msgpack::packer.
        msgpack::sbuffer buffer;

        msgpack::packer<msgpack::sbuffer> pk(&buffer);
        pk.pack_array(4);
        pk.pack(std::string("Log message ... 1"));
        pk.pack(std::string("Log message ... 2"));
        pk.pack(std::string("Log message ... 3"));
        pk.pack(std::string("Log message ... 4"));

        // serializes multiple objects into one message containing a map using msgpack::packer.
        msgpack::sbuffer buffer2;

        msgpack::packer<msgpack::sbuffer> pk2(&buffer2);
        pk2.pack_map(2);
        pk2.pack(std::string("x"));
        pk2.pack(3);
        pk2.pack(std::string("y"));
        pk2.pack(3.4321);
//        pk2.pack(4);


        /*---- 以下自作部分 ----*/
        
        // unpack array
        msgpack::unpacked msg;
        msgpack::unpack(msg, buffer.data(), buffer.size());
        msgpack::object obj = msg.get();
        msgpack::object_array obj_array = obj.via.array;

        std::string str[4];
        for (int i = 0; i < 4; i++) {
             (obj_array.ptr[i]).convert(str[i]);
             std::cout << "str[" << i << "]: " << str[i] << std::endl;
        }

        // unpack map
        msgpack::unpacked msg2;
        msgpack::unpack(msg2, buffer2.data(), buffer2.size());
        msgpack::object obj2 = msg2.get();
        msgpack::object_map obj_map = obj2.via.map;

        for (int i = 0; i < 2; i++) {
            std::string map_key;
            //std::cout << "key: " << obj_map.ptr[i].key;
            (obj_map.ptr[i].key).convert(map_key);


            // 以下、mapのvalの方は、intの場合とfloatの場合があるので一旦floatにconvert
            // してからstringに変換した
            float f;
            // obj_map.ptr[i].valはmsgpackのobject
            // 一旦floatにconvertしてからそれを文字列に変換した
            (obj_map.ptr[i].val).convert(f);
            std::stringstream ss;
            ss << f;

            std::cout << "key: " << map_key << " val: " << ss.str() << std::endl;


            // これを実行するとintは2, floatは4と表示される
            //std::cout << "type: " << (obj_map.ptr[i].val).type << std::endl;

            // 以下のようなif文で判定できるが、このプログラムでは一括してfloatに変換している
            //if ( (obj_map.ptr[i].val).type == msgpack::type::POSITIVE_INTEGER ) {
            //}
        }
        

        //  $ g++ -Ipath_to_msgpack/include stream.cpp -o stream
}

実行結果

$ g++ -Ipath_to_msgpack/include stream.cpp -o stream
$ ./stream 
str[0]: Log message ... 1
str[1]: Log message ... 2
str[2]: Log message ... 3
str[3]: Log message ... 4
key: x val: 3
key: y val: 3.4321

上の修正は以下を参考にした

msgpackのオブジェクトとしてここを参考にした

    MSGPACK_OBJECT_NIL                  = 0x00,
    MSGPACK_OBJECT_BOOLEAN              = 0x01,
    MSGPACK_OBJECT_POSITIVE_INTEGER     = 0x02,
    MSGPACK_OBJECT_NEGATIVE_INTEGER     = 0x03,
    MSGPACK_OBJECT_FLOAT32              = 0x0a,
    MSGPACK_OBJECT_FLOAT64              = 0x04,
    MSGPACK_OBJECT_FLOAT                = 0x04,
#if defined(MSGPACK_USE_LEGACY_NAME_AS_FLOAT)
    MSGPACK_OBJECT_DOUBLE               = MSGPACK_OBJECT_FLOAT, /* obsolete */
#endif /* MSGPACK_USE_LEGACY_NAME_AS_FLOAT */
    MSGPACK_OBJECT_STR                  = 0x05,
    MSGPACK_OBJECT_ARRAY                = 0x06,
    MSGPACK_OBJECT_MAP                  = 0x07,
    MSGPACK_OBJECT_BIN                  = 0x08,
    MSGPACK_OBJECT_EXT                  = 0x09              
  • 注意点として、msgpackのバージョンによるのか、関数名や引数が参照渡しかポインタ渡しかなどが違うみたい
  • 単純に例と同じようにやってもうまく行かなかった

User-defined classes(MSGPACK_DEFINE)

msgpack-c/QUICKSTART-CPP.md at master · msgpack/msgpack-c · GitHub

You can use serialize/deserializes user-defined classes using MSGPACK_DEFINE macro.

とある通り、ユーザ定義のクラスをMSGPACK_DEFINEというマクロを使ってシリアライズ/デシリアライズできる

$ cat msgpack_define.cpp
#include <msgpack.hpp>
#include <vector>
#include <string>

#include <iostream>

class myclass {
//private:
//    std::string m_str;
//    std::vector<int> m_vec;
public:
    std::string m_str;
    std::vector<int> m_vec;

    MSGPACK_DEFINE(m_str, m_vec);

    myclass() {
        m_str = "default";
        m_vec.push_back(1);
        m_vec.push_back(2);
        m_vec.push_back(3);
    }
};

int main(void) {
        std::vector<myclass> vec;
        // add some elements into vec...

        vec.push_back(myclass());


        // you can serialize myclass directly
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, vec);

        msgpack::object_handle oh =
            msgpack::unpack(sbuf.data(), sbuf.size());

        msgpack::object obj = oh.get();

        // you can convert object to myclass directly
        std::vector<myclass> rvec;
        obj.convert(rvec);

        for(std::vector<myclass>::iterator it = rvec.begin(); it != rvec.end(); ++it) {
            std::cout << (*it).m_str << std::endl;

            for(std::vector<int>::iterator m_vec_it = (*it).m_vec.begin(); m_vec_it != (*it).m_vec.end(); ++m_vec_it) {
                std::cout << (*m_vec_it) << std::endl;
            }
        }
}

実行結果

$ g++ -Ipath_to_msgpack/include msgpack_define.cpp -o msgpack_define
$ ./msgpack_define 
default
1
2
3

MSGPACK_DEFINEの定義

v1_1_cpp_adaptor · msgpack/msgpack-c Wiki · GitHub

ソースコードは以下 - https://github.com/msgpack/msgpack-c/blob/55b51c506fee9ce496e9b98aca33cadade681479/include/msgpack/adaptor/define_decl.hpp#L28-L42

#define MSGPACK_DEFINE_ARRAY(...) \
    template <typename Packer> \
    void msgpack_pack(Packer& pk) const \
    { \
        msgpack::type::make_define_array(__VA_ARGS__).msgpack_pack(pk); \
    } \
    void msgpack_unpack(msgpack::object const& o) \
    { \
        msgpack::type::make_define_array(__VA_ARGS__).msgpack_unpack(o); \
    }\
    template <typename MSGPACK_OBJECT> \
    void msgpack_object(MSGPACK_OBJECT* o, msgpack::zone& z) const \
    { \
        msgpack::type::make_define_array(__VA_ARGS__).msgpack_object(o, z); \
    }

同じソースコードに下に以下も定義されているので、MSGPACK_DEFINE がMSGPACK_DEFINE_ARRAYに置き換わる
#define MSGPACK_DEFINE MSGPACK_DEFINE_ARRAY

pythonトラブル対応

エラー

AttributeError

AttributeError: module 'json' has no attribute 'dump'

誤ったインタプリタです: そのようなファイルやディレクトリはありません

pip3を使おうとしたらこんなエラーが

[~/git/work/src/python/memo/pandas] $ pip3 install pandas_ply
/home/ludwig125/.pyenv/pyenv.d/exec/pip-rehash/pip: /home/ludwig125/.pyenv/versions/3.5.4/bin/pip3: /home/前のユーザ名/.pyenv/versions/3.5.4/bin/python3.5: 誤ったインタプリタです: そのようなファイルやディレクトリはありません

Ubuntu14.0.4でホスト名とユーザ名を変更する - ludwig125のブログ

これでユーザ名を変えてしまったせいみたい

解決できないのでpyenvごと削除して作り直す

[~] $ pyenv versions
* system (set by /home/ludwig125/.python-version)
  3.5.4
[~] $ pyenv uninstall 3.5.4
pyenv: remove /home/ludwig125/.pyenv/versions/3.5.4? yes
[~] $ 


[~] $  pyenv install 3.5.4
Downloading Python-3.5.4.tar.xz...
-> https://www.python.org/ftp/python/3.5.4/Python-3.5.4.tar.xz
Installing Python-3.5.4...
Installed Python-3.5.4 to /home/ludwig125/.pyenv/versions/3.5.4

$ pyenv local 3.5.4で移動

これでpip3を使えるようにになった

[~] $ 
[~] $ pip3 --version
pip 9.0.1 from /home/ludwig125/.pyenv/versions/3.5.4/lib/python3.5/site-packages (python 3.5)
[~] $ 

Ubuntu14.0.4でGoogleChromeが起動しない

問題

VMUbuntuChromeをアップデートしたあとで、 Google Chromeのアイコンを押しても起動しなくなってしまった

コマンドでgoogle-chromeをしたら以下のエラーが

$ google-chrome
[11644:11689:1103/213846.450610:FATAL:nss_util.cc(632)] NSS_VersionCheck("3.26") failed. NSS >= 3.26 is required. Please upgrade to the latest NSS, and if you still get this error, contact your distribution maintainer.
中止 (コアダンプ)

解決方法

askubuntu.com

これらを参考にパッケージをアップグレード

sudo apt-get upgrade
sudo apt-get update

これで開けるようになった

[shingo-virtual-machine ~/git/work] $ google-chrome
ATTENTION: default value of option force_s3tc_enable overridden by environment.
ATTENTION: default value of option force_s3tc_enable overridden by environment.
[18255:18293:1103/215655.013441:ERROR:simple_version_upgrade.cc(164)] File structure does not match the disk cache backend.
[18255:18293:1103/215655.014000:ERROR:simple_backend_impl.cc(659)] Simple Cache Backend: wrong file structure on disk: /home/shingo/.cache/google-chrome/Default/Cache
[18255:18255:1103/215655.772279:ERROR:account_tracker.cc(328)] OnGetTokenFailure: Invalid credentials.
[18255:18255:1103/215655.779440:ERROR:account_tracker.cc(328)] OnGetTokenFailure: Invalid credentials.

Ubuntuのパスワードを求められたので入力したら解決

apt-get参考

qiita.com

VMのUbuntuにWebサーバを立てる

概要

  • 色々苦戦したのでメモ
  • やったこと

  • 1.VM上のubuntupythonで簡易的にweb serverを立ち上げる ポート8181

  • 2.VM内のブラウザで localhost:8181 → 当然見られる
  • 3.ホストPCのWindowsのブラウザで、VMのプライベートIPアドレスを指定して192.168.19.137:8181を見る → これも見られる
  • 4.しかしiphoneからはアクセスできない
  • 5.ルータのネットワーク外からポート8181のアクセスが来た時に、VMのWebサーバに行くようにポートフォワード(ポート開放)する
  • 6.ルータがポートフォワードできるIPアドレスの範囲がVMIPアドレスと違うー
  • 7.なので、VMIPアドレスをポートフォワードできるものに変更
  • 8.ファイアウォールの設定も変更しよう ⇒ ufwで8181のポートをallowに
  • 9.まだつながらない → 面倒だから 自宅ルータから直接VMをブリッジで接続しよう
  • 10.出来た iphoneやノートPCのブラウザからUbuntu内のファイルの情報が見られた
  • 11.グローバルIPアドレスを設定して見られないか確認

ここまで2,3日

手順

1.VM上のubuntupythonで簡易的にweb serverを立ち上げる ポート8181

python3の入っている環境で以下の通り、Webサーバ立ち上げる

ポートは8181

$ python3 -m http.server --cgi 8181
Serving HTTP on 0.0.0.0 port 8181 (http://0.0.0.0:8181/) ...

2.VM内のブラウザで localhost:8181 → 当然見られる

f:id:ludwig125:20171028223645p:plain

3.ホストPCのWindowsのブラウザで、VMのプライベートIPアドレスを指定して192.168.19.137:8181を見る → これも見られる

Windows側のブラウザでは上のlocalhostの部分をVMIPアドレスにしたものを表示 - VMIPアドレスはifconfigで取得した(IPV4のもの)

4.しかしiphoneからはアクセスできない

みられない

会社PCからも見られない

pingもtracerouteもVMのアドレスに対してやってもtimeoutする(ホストPCであるWindowsIPアドレスに対しては問題なし)

$ ping 192.168.19.137
PING 192.168.19.137 (192.168.19.137): 56 data bytes
ping: sendto: Host is down
ping: sendto: Host is down
Request timeout for icmp_seq 0
ping: sendto: Host is down
Request timeout for icmp_seq 1
ping: sendto: Host is down
Request timeout for icmp_seq 2

$ traceroute -v 192.168.19.137
traceroute to 192.168.19.137 (192.168.19.137), 64 hops max, 52 byte packets
 1  * *^C

なぜつながらないのか?

あとからもう少しわかることだったが、ここで繋がらなかった理由はこの時点のVMのネットワークの設定がNATになっていて、ホストPC側の設定が正しくなかったからかもしれない

5.ルータのネットワーク外からポート8181のアクセスが来た時に、VMのWebサーバに行くようにポートフォワード(ポート開放)する

家のルータはソフトバンク光の 光BBユニット(EWMTA2.3)だった

そうしたら以下のように言われた

f:id:ludwig125:20171028224431p:plain

転送先IPアドレスに誤りがあります。IPアドレスの範囲内で半角数字で入力してください

6.ルータがポートフォワードできるIPアドレスの範囲がVMIPアドレスと違うー

以下によると、転送先のIPアドレスの範囲が限られているらしく、VMのアドレスと異なるので転送できない・・・

f:id:ludwig125:20171103222942p:plain

7.なので、VMIPアドレスをポートフォワードできるものに変更

以下の方法でVMIPアドレスを、ポート開放できる範囲に変える

実践初級ITブログ VMwareのUbuntuを固定IPにする

もともとのUbuntu
IPアドレス 192.168.19.137
ブロードキャストアドレス 192.168.19.255
サブネットマスク 255.255.255.0
デフォルトルート 192.168.19.2
第一DNS 192.168.19.2


VMのUbuntuのIPを以下に変更
192.168.3.11

変える前

f:id:ludwig125:20190306044115p:plain

変えた後

f:id:ludwig125:20190306044131p:plain

f:id:ludwig125:20171103224244p:plain

ifconfigなどでIPアドレスが変わっていることを確認 再度ポート転送を設定すると成功

f:id:ludwig125:20171103224629p:plain f:id:ludwig125:20171028225748p:plain

8.ファイアウォールの設定も変更しよう ⇒ ufwで8181のポートをallowに

utfいじる

  • ここでallowにしたポート以外はファイアウォールが有効なので、ホストOSからは接続できない

第76回 Ubuntuのソフトウェアファイアウォール:UFWの利用(1):Ubuntu Weekly Recipe|gihyo.jp … 技術評論社

 $ sudo ufw status    
状態: 非アクティブ
 $ sudo ufw enable
ファイアウォールはアクティブかつシステムの起動時に有効化されます。
 $ sudo ufw status    
状態: アクティブ
 $
$ sudo ufw default DENY
デフォルトの incoming ポリシーは 'deny' に変更しました
(適用したい内容に基づいて必ずルールを更新してください)

$ sudo ufw allow 8181
ルールを追加しました
ルールを追加しました (v6)


$ sudo ufw status    
状態: アクティブ

To                         Action      From
--                         ------      ----
8181                       ALLOW       Anywhere
8181 (v6)                  ALLOW       Anywhere (v6)

 $  sudo ufw allow http
ルールを追加しました
ルールを追加しました (v6)

9.まだつながらない → 面倒だから 自宅ルータから直接VMをブリッジで接続しよう

以下の方法でブリッジに変更した - VMware上のLinux Webサーバに外部からアクセスできるようにする | あみだがみねのもろもろ備忘録

最初はNATに設定されていた f:id:ludwig125:20171028231018p:plain

ブリッジに変更 f:id:ludwig125:20171028230950p:plain

よくよく考えると、VMのネットワークをブリッジ接続にしたので、ゲートウェイDNS サーバーのIPアドレスはルータのIPアドレスが正しいはず なのに、それらがVMIPアドレスを変える前のままになっている 以下は間違い

f:id:ludwig125:20171103224244p:plain

以下が正しい

f:id:ludwig125:20171103224539p:plain

10.出来た ! iphoneやノートPCのブラウザからUbuntu内のファイルの情報が見られた

f:id:ludwig125:20171103224731p:plain

11.グローバルIPアドレスを設定して見られないか確認

上の接続はあくまで同一ネットワーク内からVMのプライベートIPアドレス 192.168.3.11 に繋いだだけだった

自分のグローバルIPアドレスが何か? - ルータの設定が書かれた以下のWAN側IPアドレスでも見られる - http://172.16.255.254/settei.html

LAN外のネットワークからルータのグローバルIPアドレスを設定して、 グローバルIP:8181で外からも接続できるか確認

  • Ubuntu側でWebサーバを立てる
$python3 -m http.server --cgi 8181 (git)-[master]
Serving HTTP on 0.0.0.0 port 8181 (http://0.0.0.0:8181/) ...
  • ネットワーク外からアクセスする

    • 注意点として、スマホからアクセスする場合はWifiを外して無線LAN外からアクセスする必要がある
    • ネットワーク内からグローバルIPに対してアクセスすることはできない
  • Wifiを切ったスマホから「グローバルIP:8181」でアクセスして、同様の画面が見られることが確認できた

図で書くとこんな感じだと思う(間違っていないはず・・)

f:id:ludwig125:20171103232200p:plain

pythonメモ

準備

コード規約

pipインストール参考

pyenv

必要なライブラリインストール
$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils


pyenvのインストール
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv


$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc


パスの再読込
exec $SHELL

pyenvの確認

$ pyenv install -l
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4
  2.4.1
  2.4.2
多いので省略
  • 3.5.4をインストール
$ pyenv install 3.5.4
Downloading Python-3.5.4.tar.xz...
-> https://www.python.org/ftp/python/3.5.4/Python-3.5.4.tar.xz
Installing Python-3.5.4...
                                                                                                                           Installed Python-3.5.4 to /home/ユーザ名/.pyenv/versions/3.5.4                                                                                        
  • バージョン確認
$ pyenv versions
* system (set by /home/ユーザ名/.pyenv/version)                                                                                
  3.5.4
  • バージョン切り替え
$ pyenv shell 3.5.4
$ pyenv versions
  system    [                                                                                           
* 3.5.4 (set by PYENV_VERSION environment variable)

pyenv local 3.5.4で環境を切り替えても、その上のディレクトリには適用されていないようだった(要確認)

  • pyenv環境の削除
 $ pyenv uninstall 3.5.4
pyenv: remove /home/ludwig125/.pyenv/versions/3.5.4? yes
$ 

環境変数

os.getenv

os.getenv(varname[, value])

  • 環境変数 varname が存在する場合にはその値を返し、存在しない場合には value を返す

os.environ

例
「host101, host201, host301, host401」
「host_role」というkeyのroleに上記のサーバを登録した場合、roleに登録されたサーバの確認方法は以下のようにする
for role in env.roledefs.keys():
    print env.roledefs[role]

→実行結果
['host101', 'host201', 'host301', 'host401']

文法

リスト(配列)

data = []
for i in range(1, 6):
    data.append(i * 2)

print data

リスト内包表記

data2 = [i * 2 for i in range(1, 6)] print data2

map

mapは配列の各要素に対して関数を実行する

以下はmap(関数, 配列)

data3 = map(lambda x : x*2, range(1, 6))
print data3

実行結果

$ python list.py
[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]

リスト内包表記

  • 10以下の奇数を作成する
    • リスト内包表記 のあとにif文でフィルタリングできる
>>> [ i for i in range(1, 11) if((i % 2) == 1)]
[1, 3, 5, 7, 9]

python デコレータ

デコレータ例

  • 関数が実行にかかった時間を表示するデコレータ
import time                                                                                     


def time_log(func):
    def wrapper(*args, **kwargs):
        print("start: " + func.__name__)
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print("end: " + func.__name__ , " elapsed time:" + str(end_time - start_time))
        return res
    return wrapper

@time_log
def func1():
    print("Boys, be ambitious")
    time.sleep(3)
    print("Girls, be ambitious")

func1()

実行結果

$ python deco_time.py 
start: func1
Boys, be ambitious
Girls, be ambitious
('end: func1', ' elapsed time:3.00378608704')

serial

どんなタスクも serial を指定すると設定を無視してシリアルで実行します。 http://fabric-ja.readthedocs.org/ja/latest/usage/parallel.html

roles

正規表現

match

文字列のエスケープとmatch - http://python-doc-ja.readthedocs.org/en/latest/howto/regex.html

ホスト名からホスト番号を取り出す

例:
ホスト名:host022101.co.jp
→ 022101を取り出す
host = "adsearch022101.co.jp"
pattern = r"([a-z]*)(\d*)"
m = re.match(pattern, host)
host_num = m.group(2)
print host_num
 
⇒ 022101

辞書

Tips

一つの長い行を途中で折り返す
方法1.バックスラッシュ「\」を使う
test = '%s \
         %s' % ("aaa", "bbb")
 
ただしこれだと 折り返した後の行頭からの空白が出力されてしまう
>>> test = '%s \
...          %s' % ("aaa", "bbb")
>>> print test
aaa          bbb
方法2.括弧で囲う
test2 = ('%s '
         '%s' % ("aaa", "bbb"))
 
これなら余計なスペースは入らない
>>> test2 = ('%s '
...          '%s' % ("aaa", "bbb"))
>>> print test2
aaa bbb
 
 
これでも大丈夫
test2 = ('%s '
         '%s' 
         % ("aaa", "bbb"))

>>> test2 = ('%s '
...          '%s'
...          % ("aaa", "bbb"))
>>> print test2
aaa bbb

GUI

参考:実践力を身につける Pythonの教科書 | マイナビブックス

Tkinter

import tkinter.messagebox as mb

ans = mb.askyesno("question", "Do you like nooble")

実行

$ python3 dialog.py

最初失敗

$ python3 dialog.py
Traceback (most recent call last):
  File "dialog.py", line 1, in <module>
    import tkinter.mesagebox as mb
  File "/usr/local/lib/python3.6/tkinter/__init__.py", line 36, in <module>
    import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter'
$ sudo apt install python-tk tk-dev
$ pyenv install 3.5.1

再度実行

$ python3 dialog.py

f:id:ludwig125:20171021230910p:plain

あとでまたできなくなったので、改めて確認

ludwig125.hatenablog.com

Webサーバを立てる

参考:実践力を身につける Pythonの教科書 | マイナビブックス

pythonでWebサーバを起動

8181ポートでWebサーバを起動してみる

python3 -m http.server --cgi 8181

詳細はこちらに記載

ludwig125.hatenablog.com

Webサーバとして、URLのパラメータの値を取得する

参考:実践力を身につける Pythonの教科書 | マイナビブックス

chap5/5-2/cgi-bin] $ cat show-params.py 
#!/usr/bin/env python3

import cgi

# header
print("Content-Type: text/html; charset=utf=8")

print("")

print("<pre>")
# URLパラメータを取得する
form = cgi.FieldStorage()

# 特定のパラメータを取得して表示
mode = form.getvalue("mode", default="")
print("mode=", mode)

# すべてのパラメータを取得して表示
print("--- all params ---")
for k in form.keys():
    print(k, "=", form.getvalue(k))                       

cgi-binより上のパスでWebサーバ起動

chap5/5-2] $ python3 -m http.server --cgi 8181
Serving HTTP on 0.0.0.0 port 8181 (http://0.0.0.0:8181/) ...
192.168.3.2 - - [31/Oct/2017 23:51:32] "GET /cgi-bin/show-params.py?mode=test&n=30&q=500 HTTP/1.1" 200 -

f:id:ludwig125:20171101000253p:plain

インスタンス

クラスのオーバーロード

class Pos:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        x2 = self.x + other.x
        y2 = self.y + other.y
        return Pos(x2, y2)

    def add(self, other):
        # オーバーロードではなく関数呼び出しで同じ結果を得ることができるか・・?
        x2 = self.x + other.x
        y2 = self.y + other.y
        return Pos(x2, y2)

    def __str__(self):
        return "{0}, {1}".format(self.x, self.y)


p1 = Pos(10, 20)
p2 = Pos(100, 400)

p3 = p1 + p2 # +演算子をオーバーロードした__add__を使う
print(p3)

p3 = p1.add(p2) # 上記のp1 + p2 はこれと同じこと
print(p3)

結果

$ python3 pos-add2.py
110, 420
110, 420

テスト

unittest

pytest

  • 参考:Python testing 勉強会(1) pytestを使ってみる
インストール
flake8入れる
flake8
sudo easy_install-2.7 flake8
pip入れる
pip
sudo easy_install-2.7 pip
pytest入れる
sudo pip install pytest

pytest実行

-v

pytestに「-v」を付けると差分が詳細表示される --caputure=no --caputure=no でテスト中のprint文などを出力する

monkeypatch

http://thinkami.hatenablog.com/entry/2017/03/07/065903 https://docs.pytest.org/en/latest/monkeypatch.html http://niwaringo.tumblr.com/post/66948561978/pytest%E3%81%AEmonkeypatch%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6urllibrequest%E3%81%AE%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%E3%83%86%E3%82%B9%E3%83%88%E3%82%92%E3%81%99%E3%82%8B

トラブル対応

ludwig125.hatenablog.com

vimメモ

vimrcメモ

.vimrcの設定メモ - ludwig125のブログ

vim参考

http://uguisu.skr.jp/Windows/vi.html

現在の設定を出力する — 名無しのvim使い

自分のメモ

ビジュアル矩形モード

  • ubuntuのterminalを使っていて、ビジュアル矩形モードがCtrl+vでできないので悩んでいたけど、Ctrl+Shift+vに割り当てられていた
  • Terminalの設定でペーストを デフォルトのCtrl+Shift+vからCtrl+v に変えたことが関係しているんっだろうか。。? とりあえずこれでやって今度調べようかな