ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

pythonでfloat()やint()で変換可能かどうかを調べる関数

標準では提供されてなかったようなので、自作helper関数として作ります。
与えられた文字列が小数 or 整数かを正規表現で調べる関数を作ったのですが、作った後でテストしているときに、そんなことしなくても例外をキャッチすればいいだけだと気づきました。

###############################################################################
# str文字列がfloat()変換できるかどうかを判定する
###############################################################################
def is_float(s):
  try:
    float(s)
  except:
    return False
  return True

同様に、int(), long(),complex()変換可能かどうかも簡単に作れます。こうして見ると例外キャッチってすごい便利ですね。

Pythonに完全なプライベート関数がないのは、きっとユニットテストのしやすさを優先させたから

だと思います。

Pythonで完全なプライベート関数を作るとき、関数名の前に__(アンダースコア2つ)をつけます。しかし、このような使い方をしているコードは余り見たことありません。
Pythonの標準ライブラリのソースコードを眺めてみてもdef _func()ばかりが目につき、def __func()と書いてあるものは少ないように感じます。

現代プログラミングの手法にでテスト駆動開発というものがあります。テストの通っていないプログラムはGitに上げるなと言われるくらいです。自作関数をunittestするとき、当然テストしたい関数をしていするのですが、例えばクラス内のプライベート関数(__hoge()みたいなやつ)をテストさせようと思うと、ちょっと工夫が必要になります(ググれば出ます)。
その工夫をすればクラス内のプライベート関数でも外部アクセスできるようになり、ユニットテストしやすくなるのですが、工夫をすればアクセスできるということはそもそも「プライベート関数じゃないじゃん」となります。
だったらもうプライベート関数かユニットテストか、みたいな話になって、結果ユニットテストを優先したのではないでしょうか、という根拠のない妄想です。

確かにプライベート関数なくてもプログラミングに慣れた者同士のチーム開発なら問題ないと思うのですが、例えば初学者を交えた開発とか、初学者に対してプライベート変数とかの概念を教えることが難しいなどの理由から、今でも初学者向け学習のプログラミング言語C言語に軍配が上がるのかなあなどと思ったりなんたり。
いや、もしかしたらデータ構造や命名規則をしっかり学習すれば、プライベート変数みたいなスコープの概念は必要ないというアンチテーゼなのかもしれない。

まあ、ろくに調べはわけではないので、もしかしたらちゃんとした理由があるのかもしれません。適当に思ったことを書きましたとさ。

AtomのRemote-FTPを使ってラズパイのファイル操作をする

今までWin-SCPを使ってサクラエディタでファイル操作していたのですが、常々できることならAtomを使いたいと思っていました(サクラエディタは好きですが、フォルダの階層を行き来しながらファイル操作するのが大変)。どうやらAtomを使ってリモートでファイル操作をするパッケージがあるようなので、それを使ってみます。

Remote-FTPAtomにインストールする

File > Settings > Install から、Remote-FTPをインストールします。

ローカルにプロジェクトファイルを作る

File > Open Folder から、適当なフォルダを開きます
例えば私の場合、ラズパイのprojectAというフォルダをリモート操作したいので、適当にローカルの"C:\Users\hoge\workspace\projectA"というフォルダを作成し、そのフォルダを開きました。

ftpconfigの設定

Packages > Remote-FTP > Create SFTP config file
すると.ftpconfigというファイルが開くので、それを編集します。

"protocol":"sftp"
"host":"ラズパイのIPアドレス"
"port":"SSHのポート番号(デフォルト22番)"
"user":"ラズパイにログインするときのユーザ名"
"pass":"ラズパイにログインするときのパスワード"
"remote":"ラズパイの開きたいディレクトリを絶対パスで指定"

他はデフォルトでいいと思います。

例えば私の場合、

"protocol":"sftp"
"host":"192.168.10.131"
"port":"49999"
"user":"pi"
"pass":"raspberry"
"remote":"/home/pi/projects/projectA/"

みたいにしました。

編集したら保存します。

ラズパイに接続する

Packages > Remote-FTP > Connect をクリックすると、接続を試みます。接続できたら「Connected」みたいなメッセージが出るはずです。
Connectedできてもラズパイのディレクトリ構造が表示されない場合、Packages > Remote-FTP > Toggleをクリックします。

ファイルを操作する

おそらく2つのトグル画面が表示されていると思いますが、
・左側がリモート(ラズパイ側)のフォルダ「/」
・右側がローカル(PC側)のフォルダ「Project」
になります。
リモート側のファイルをダブルクリックするとローカル側にファイルがダウンロード(コピー)されます。
リモート側のファイル(フォルダ)を右クリック > Downloadでも同じことができます。
ローカル側のファイルを自由に編集した後、保存すると自動でリモート側にアップロードされるようです。

すぐタイムアウトしてしまう

デフォルトではちょっとほっておいたらすぐタイムアウトしてリモートと接続を切ります。これが嫌な場合"connTimeout"や"keepalive"の値をいじれば良さそうです。ですが、リモートとの接続が切れている状態でも、ローカルのファイルを保存すると自動で接続・アップロードまでしてくれるので、別に気にしなくてもいい気がします。

これでAtom一つでフォルダ階層を行き来しながらファイル編集できます。すごく便利。Atomは神。ちょくちょくエラー出たり重かったりするけど。

Atomで"や'の補完機能を無効にする

Atom(というか多くのリッチなエディタ)では、「"」と打つと自動で「""」と補完してくれる。補完して...くれる...?補完しないでください。

http://hakomof.hatenablog.com/entry/2015/05/07/210328
上記サイトに方法が書いてあります。

File > Config をクリックすると、config.csonファイルが開きます。
そこに「"bracket-matcher": autocompleteBrackets: false」を追加することで無効にできます。

"*":
    "atom-ctags":{}
    "autocomplete-plus": {}
    ...
    (略)
    ...
    "bracket-matcher":
        autocompleteBrackets: false

あらゆるエディタ・ IDE についてるけど邪魔だと思ったことこそあれ、便利だと思ったことはない。無効。

完全に同意。

packet_write_wait: Connection to "IPアドレス": Connection reset by peer

SSHでラズパイに接続中、頻繁にぶつぶつ接続が切れる問題に遭遇。
接続が切れるときに、次のようなエラーメッセージが表示されました。

packet_write_wait: Connection to 192.168.8.132: Connection reset by peer

色々調べた結果、IPアドレスの衝突が原因でした。
ラズパイを固定IPアドレスで運用していると、別のDHCPで運用している端末にIPアドレスを奪われてしまう現象が起きていました。
DHCPでのIPアドレスの分配はホスト部が小さい数字から割り当てられるようになっていることが多いので、固定IPアドレスホスト部はなるべく大きい数字にしましょう。

Pythonで親ディレクトリのファイルをインポート

実行スクリプトの親ディレクトリのファイルをインポートする - Pythonで遊ぶよ - pythonグループ

長年これを探していました…!

hoge.py
└tests/
  └test_hoge.py

test_hoge.pyからhoge.pyをインポートします。

test_hoge.py

import os
import sys
sys.path.append(os.pardir)
import hoge

systemdのサービスの起動順序を決める

hoge1.serviceとhoge2.serviceという2つのサービスを作成しました。
「hoge1.seriveのExecStartで指定したスクリプトが完全に終了してからhoge2.serviceを起動する」ということをしたい場合は、サービスの起動順序を記述する必要があります。

[Unit]セクションにAfterとBeforeを記述すれば起動順序を指定できますが、これだけだと意図した順序で起動してくれませんでした。
原因は起動完了判定のタイミングで、[Service]セクションのTypeも考える必要があります。

Type = simpleは、「サービス起動と同時に起動完了と判定する」
Type = oneshotは、「サービス起動して、ExecStartで指定したスクリプトが終了したら起動完了と判定する」
Systemd入門(4) - serviceタイプUnitの設定ファイル - めもめも


なので、今回のような場合はhoge1.serviceをType = oneshotにする必要があります。

hoge1.service

[Unit]
Description = hoge1.sh runs before hoge2.sh
Wants = multi-user.target
Before = hoge2.service

[Service]
ExecStart = /home/pi/hoge1.sh
Restart = no
Type = oneshot

[Install]
WantedBy = multi-user.target

hoge2.service

[Unit]
Description = hoge2.sh runs after hoge1.sh
After = hoge1.service

[Service]
ExecStart = /home/pi/hoge2.sh
Restart = no
Type = simple

[Install]
WantedBy = multi-user.target

実際に意図した順序で起動しているかを確認してみます。
Systemdのサービスの依存関係を調べる方法 - ククログ(2015-12-28)

$ systemd-analyze plot > systemd.svg

作成されたsystemd.svgファイルを適当なブラウザにドラッグ&ドロップすると、デーモンの起動順序を確認できます。
f:id:takeg:20170215220336p:plain
hoge1.serviceの後にhoge2.serviceがactiveしていることがわかります。
どうやらこれで良さそうです:)