読者です 読者をやめる 読者になる 読者になる

ベスパライフ

日記・備忘録。ベスパもってないです。

python3では文字列中の部分文字列検索や辞書にキーが存在するかはin演算子を使おう

公式がそう言っているので、そうしましょう。
https://docs.python.jp/3/library/stdtypes.html

文字列中の部分文字列検索

注釈
find() メソッドは、 sub の位置を知りたいときにのみ使うべきです。 sub が部分文字列であるかどうかのみを調べるには、 in 演算子を使ってください:

>>>
>>> 'Py' in 'Python'
True

辞書にキーが存在するかを調べる

>>>
>>> dict = {}
>>> dict["A"] = 1
>>> dict["B"] = 2
>>> dict["C"] = 3
>>> "A" in dict
True
>>> "D" in dict
False

Pythonでclassの中にclassを作成する

class TemperatureHumidity:
  class Temperature:
    def __init__(self):
      self.value = None
      self.count = 0
    def print(self):
      print("Temperature:", self.value, self.count)
  class Humidity:
    def __init__(self):
    self.value = None
    self.count = 0
    def print(self):
      print("Humidity:", self.value, self.count)

  def __init__(self):
    self.t = self.Temperature()
    self.h = self.Humidity()
  def print(self):
    self.t.print()
    self.h.print()
  def increment_count(self, _obj):
    _obj.count += 1

if __name__ == "__main__":
  t_h = TemperatureHumidity()
  t_h.t.print()
  t_h.h.print()
  t_h.increment_count(t_h.t)
  t_h.t.print()
  t_h.h.print()

継承するときはselfはいらない

以下のコードはTemperatureクラスがDataクラスを継承していますが、self.Dataと書いてはいけません。

class TemperatureHumidity:
  class Data:
    def __init__(self):
      self.value = None
      self.count = 0
  class Temperature(Data):
    def __init__(self):
      super().__init__()
    def print(self):
      print("Temperature:", self.value, self.count)
  class Humidity(Data):
    def __init__(self):
      super().__init__()
    def print(self):
      print("Humidity:", self.value, self.count)

  def __init__(self):
    self.t = self.Temperature()
    self.h = self.Humidity()
  def print(self):
    self.t.print()
    self.h.print()
  def increment_count(self, _obj):
    _obj.count += 1

if __name__ == "__main__":
  t_h = TemperatureHumidity()
  t_h.t.print()
  t_h.h.print()
  t_h.increment_count(t_h.t)
  t_h.t.print()
  t_h.h.print()

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アドレスホスト部はなるべく大きい数字にしましょう。