2016/11/29

[py]buffer()とbytearray()の違いはなんだろう?

よくわからないまま、どこかからコピーしたコードを使うことがしばしばある。
それによって、これってなんだろう?という疑問が湧くこともしばしば。

 

いま、paho-mqttでpublish()するところを見ていたのだが、こんな書き方をしていた。

publish(topic, buffer(data1) + bytearray(data2))

なんとなく、buffer()もbytearray()も似たようなことをしてくれそうだ。
何が違うのだろう?

 

以前、16進数の配列を作る際に、こういうやり方があることを知った。

cmd = bytearray([0x03, 0x12, 0x34, 0x56])

これだと、cmd[1]などで数値が取ってこれるので、そのままif文や添字として使える。
bytearrayは組み込み型で、バイト配列を返すシーケンスとのこと。

 

一方、bufferは毛色がなんか違う。
bufferオブジェクト、なのだ。
CのAPIを使うときなどに出てくるようなので、素のバイト配列なのだろう。

 

data1 = 15
data2 = '1234abcd'.decode('hex')

buf = buffer(chr(data1)) + buffer(data2)
print 'buf=', buf.encode('hex')

dat1 = ord(buf[0])
dat2 = buf[1:]
print 'dat1=', dat1
print 'dat2=', dat2.encode('hex')

buf= 0f1234abcd
dat1= 15
dat2= 1234abcd

data1 = 15
data2 = '1234abcd'.decode('hex')

buf = bytearray(chr(data1)) + bytearray(data2)
print 'buf=', str(buf).encode('hex')

dat1 = buf[0]
dat2 = buf[1:]
print 'dat1=', dat1
print 'dat2=', str(dat2).encode('hex')

buf= 0f1234abcd
dat1= 15
dat2= 1234abcd

 

bytearrayはencode('hex')がないし、str型ではないからstr()で囲んだり、ord()が不要だったりという違いがある。

 

data1 = 15
data2 = '1234abcd'.decode('hex')

buf = buffer(chr(data1)) + bytearray(data2)
print 'buf=', buf.encode('hex')

dat1 = ord(buf[0])
dat2 = buf[1:]
print 'dat1=', dat1
print 'dat2=', dat2.encode('hex')

buf= 0f1234abcd
dat1= 15
dat2= 1234abcd

混合できて、その場合はstr型と同じ扱いになるようだ。

 

paho-mqttのpublish()は、payloadとして文字列を使いたいようだ。
intとか送りたかったらstruct.pack()してくれ、と書いているし。
bytearray型を引数にして使えているのだが、これはpahoがstr()で囲んだりしてくれているからかもしれん。

・・・と思ったが、違った。
bufferを与えると例外が発生したのだ。

TypeError: payload must be a string, bytearray, int, float or None.

bytearrayは許可してたのね。。。
そしてintはstruct.pack()してくれ、だと思ったのだけど、例外の内容を見るとintも許可しているような感じだな。
まあ、使わないから調べないけど。

2016/11/28

[py3]2to3ではdecode/encode('hex')などは変換してくれないようだ

さて、いま作っているプロジェクトもpython3対応しようと、2to3.pyにかけてみた。
ワイルドカードで指定できなかったので、cygwinでxargsを使ったが、printがprint()になっているので変換できたのだろう。
よし、とpyCharmの設定もpython3にして開いてみると、指摘がたくさん。。。

こんなのが指摘されている。

struct.pack('<H', length).encode('hex')

bytes = lenstr.decode('hex')

 

hiro99ma blog: [py]python3は16進数の扱いが違うんだ

違うんだ、を実感した瞬間である。


decode/encodeはstr型用だから、bytes型だと使えない。
struct.pack()はbytes型で返すようになっている。
だから、bytes型の扱いに変換すればよいだけのことだ。

文字.decode('hex')は、bytes.fromhex(文字)にすればよいはずだ。
そこはそれで済みそうだが、"\xab\x12"のようにして作っていた文字列をbytes型に変換しないと、fromhex()したデータとの足し算というか連結ができないことがわかった。
これは、文字列の前に「b」を付けるだけでよいようだ。

と、やってみたのだが、bytesの要素をord()したりstruct.unpack()すると怒られる。。。

ord(cmd_bytes[0])

strがほしいのにintが渡されている、ということだった。
デバッガで見てみると、bytes配列の要素はint型になっていた。
そうか、ord()しなくてもいいんだ。。。

が、これはこれで別の問題が起きた。
辞書のkeyとして"\xab"のような値を使っていたのだが、これをbytes型にしないと検索できなくなった。
しかし、検索するのはbytesから1バイト取ってきたデータなので、そのままだとint型になってしまう。
よくわからんので、cmd_bytes[0].to_bytes(1, byteorder='little')、などとしてbytes型に変換して、動きはしたのだけど、ダサい。。。

4. 組み込み型 — Python 3.5.2 ドキュメント
なるほど、要素として取り出すとintになるから、サイズ1の配列として取り出せばよいのか。

cmd = cmd_bytes[pos: pos+1]

こんなのでよい。
数値にしたければ、cmd[0]とすればよいだけなので、こっちの方が扱いやすいな。

 

encode('hex')するのは目で読める文字にするとき、decode('hex')するのは実際のデータにするとき、という使い分けをしていた。
これは、bytes型にhex()というメソッドがあり、それでよかった。


私がbytes型を使うときのやり方をまとめると、こう。

  • 文字列でエスケープシーケンスを使って16進数を表していた→あたまに「b」を付ける
  • decode('hex')していた→bytes.fromhex()にする
  • ord()していた→bytesを1要素として取り出す(data[3]など)
  • bytes型として切り出したい→配列として取り出す(data[3:4]など)
  • encode('hex')していた→hex()にする

struct.pack/unpack()は、to_bytes()もあるし、あまり使わないかも。
to_bytes()の逆はなさそうだから、unpack()は使うことになるか。。。あ、int.from_bytes()というのもあるようだ。
to_bytes()はメソッドなのに、from_bytes()はstaticメソッドなのはなんでだろう?

 

pyCharmで指摘が出ているのは、あからさまにbytes型になったと分かる箇所だけだ。
型指定がないから、引数でもらったものをdecode('hex')などとしていても、そこは出てない。
だから、たくさん指摘が出ていると思ったけど、氷山の一角なのだ。
2to3でやってくれよーと思ったのだが、これはちょっと無理だな。

 

また、変換しようとしていたpythonプロジェクトは、str型のbytearrayで扱う場合と、str型で16進数文字列を扱う場合が混在していて、あっちではstruct.pack/unpack、こっちではdecode/encode('hex')と、実にまとまりがない。

今回は、python3にするのだったら、もう一度書き直した方が早そうだ。。。

2016/11/27

[pyCharm]フォルダが表示されなくなったら、Content Rootを疑う

なぜか、pyCharmのプロジェクトツリーにフォルダが表示されなくなった。
先週は普通に使っていた気がするのだが、何をしたのか記憶にない。。。

 

あれこれ見てみたが、Settingsダイアログを開き、「Project:xxx > Project Structure」を見ると、Add Content Rootのところが赤文字になっていた。
よくわからないながらも、一度削除して、また追加すると直った。

 

困ったことに、これはUNCパスの場合はうまくいかなかった。
結局、一度Windowsのローカルフォルダに移動させ、pyCharmの設定を修正して、またUNC上に戻すことになった。

まあ、推奨していないから仕方ないんだけどね。

[c/c++]Cクイックリファレンス第2版

オライリーの、Cクイックリファレンス第2版を買ってきた。
2016年11月に出たばかりだ。

O'Reilly Japan - Cクイックリファレンス 第2版

C11準拠ということで、私の知らないことがいろいろ出ているのだろう。
まあ、使うときになら無いと読まないような気がするのだが、もしマルチスレッド処理が標準で書けるのならば「RTOS採用するほどのことでもないしなぁ。でも後から使った方が良くなるかも」と迷ったときに、労力が少ないから最初からマルチスレッドで書いておこう、という選択肢が出てくるかもしれない。

 

さて、まえがきのコラム欄に、日本語版だけだと思うがコーディング規約ESCRのことが書かれていた。
ESCRが何なのか知らなかったが、Embedded System development Coding Referenceの略で、IPAが出している資料にもあるやつだった。

「【改訂版】組込みソフトウェア開発向けコーディング作法ガイド[C言語版]Ver.2.0(ESCR Ver.2.0)」PDF版と付録データの公開:IPA 独立行政法人 情報処理推進機構

私も、いくつかこれを読んだときの記事を書いている。
検索して3つ出てきたが、たぶんまだあるだろう。

 

このESCRだが、PDFでダウンロードできるものを読んだ範囲では、pythonのPIP-8とはちょっと違う。
「コーディングスタイル」ではなく「コーディング規約」なので、インデントはどうの、改行はどうの、というようなルールは書いていない。
保守性4で「統一した書き方にする」という決まりを作っているだけで、どう書くべきかというところには踏み込んでいない。

まあ、C言語の人にそういうのを強要すると、嫌がるよねぇ。
私も嫌だ。
本のコラム欄では、astyleなどの自動整形ツールに任せると効率がよい、とあり、私も賛成だ。

ただ、期待するastyleのオプションを決めるのは、なかなか難しい。
私は最近、タブをスペースで書くようになってきたので、こうしている。

--style=k/r --indent=spaces=4 -j

正解はないので、自分のプロジェクトなら自分のスタイルに、他のプロジェクトに参加するならそのスタイルにしていくことになるだろう。

 

これがテキストエディタと連携して動的に表示されると書いている間に修正するだろうけど、書いているリズムが狂ってしまうので嫌かもしれない。
難しいねぇ。

2016/11/26

[py2]feature無きprint()は、タプル扱い

「動力無きK村」(炎色反応の覚え方)みたいだが、その話ではない。

python2ではステートメントのprintがあるから、組み込み関数のprint()が使いたい場合にはimport文を書くように、となっている。
28.4. future_builtins — Python 3 のビルトイン — Python 2.7.x ドキュメント

が、python2.7でprint()とprintを両方書いたが、どちらも動いた。
なぜだろうか?

 

PEP 3105 -- Make print a function | Python.org
featureのimportを書いていない場合は、print()の関数、ではなく、printステートメント+タプル、という動作になっているということか?

print('Hello! I\'m Python2', 'not feature')

これをpython2.7.12で実行すると、こうなった。

("Hello! I'm Python2", 'not feature')

python3.5.2だと、こうなる。

Hello! I'm Python2 not feature

なるほどねぇ。

[py3]2to3で変換してみよう

作業場にて。。

Aさん「このpython、バージョンは何で書いてるの?」
私「2.7です」
Aさん「3じゃないんだ。。。」

というわけで、そろそろpython3を視野に入れないといかんようだ。

 

python2.7をインストールすると、Tools\Scriptsの中に2to3.pyというスクリプトがある。
これがpython2をpython3に変換してくれるツールらしいので、試してみよう。


print 'Hello! I\'m Python2'


単純すぎで済まん。。。
私が思いつくpython2と3の違いは、printで括弧がいるかどうかなのだ。

これを「python2.py」というファイル名で保存して、2to3にかけてみる。
うちはWindowsで、python2.7はC:\Winappli\Python27というフォルダにインストールしている。


C:\Prog\python\py3test>python C:\Winappli\Python27\Tools\Scripts\2to3.py python2.py
RefactoringTool: Skipping optional fixer: buffer
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: set_literal
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored python2.py
--- python2.py  (original)
+++ python2.py  (refactored)
@@ -1 +1 @@
-print 'Hello! I\'m Python2'
+print('Hello! I\'m Python2')
RefactoringTool: Files that need to be modified:
RefactoringTool: python2.py


オプションを付けないと、差分だけ表示するが、-wを付けるとファイルに書き込んでくれる。
前のファイルは.bakを付けて残される。


print('Hello! I\'m Python2')


まあ、予想通りの結果だ。
python3で実行しても動く。
めでたしめでたし。

 

ではあるのだが、これをpython2で動かしても、ちゃんと動くのだ。
じゃあ、最初からprintも括弧を付けて書いておけばいいのに、なんでそういうサンプルになっていなかったのだろう?

軽く調べたところ、python2で括弧無しのprintは、passやbreakと同じ「print」というステートメントという扱いらしい。
6. 単純文 (simple statement) — Python 2.7.x ドキュメント

そして、2.7の方で動いたのは組み込み関数のprint()なのだが、これは2.6から追加されているようだ。
2. 組み込み関数 — Python 2.7.x ドキュメント

python2では当初print()関数がなかったから、ステートメントのprintで書いているため、それを見て覚えた人がまたステートメントのprintを使って。。。ということで、脈々と受け継がれたということだろう。

ああ、新参者の私には分からぬ事情であったことだよ。

2016/11/25

[git][win]GitExtensions 2.49

Windows用のgit GUIツール(フロントエンド?)の1つであるGit Extensionsが、16日前にバージョンアップしていた。

Release Version 2.49 · gitextensions/gitextensions

 

ばりばりに使う人だったら、コンソールからgitコマンドを使うのだろうけど、自信がないのでツールにお任せしている。
おかげで、サーバにSSHで接続してやるときはコマンドが分からず苦労するのだけどね。。。

 

こういうツールは海外製が多いのだが、日本語に差し替えができるものもある。
GitExtensionsもできる。
が、gitの使い方を検索するとだいたいコマンドを使うやり方なので、コマンドが日本語に訳されているとわからなくなるのだ。
まあ、だいたいカタカナになっているだけなのでわかるのだけど、本当に英単語をカタカナにしただけなのか心配になるので、英語表記のまま使っている。

 

個人的には、gitで困ったことをやらかしたときの対処がツールにほしいところだ。
普通にcommitするとかだったら私でもできるし、GUIツールでもできるのだが、「○○してしまった!」みたいな場合はコンソールでやらないと戻せないことが多い。

そして、そういうやり方は覚えていないので、ネットで検索する。
やり方はコマンドを使う方法なので、コンソールになる、ということになる。
汎用性があってよいのだけど、手軽にやれるとよいなぁ、とも思うのだ。

そういうツールこそ自分で作ればよいのだろうけど、gitコマンドに対する技術が向上しないので作ることができない、という悪循環だ。。。

2016/11/24

Google Playにあげていたアプリを非公開にしました

数年前にアップしたままにしていたAndroidのアプリだが、今日は「動かない」というメールが来ていた。
アプリは「ニモカ残高」というアプリで、PaSoRiが必要なのだが、たぶんPaSoRiをつないでいないのだと思う。

が、これは私のタイトルの付け方が悪かった。。。
あたまに「PaSoRiで」くらい付けておかないと、中身なんて普通は読まないのだ。
私も今回指摘されて「そういえば読まない」と気付いた。

 

これは私が悪かったので、ついでにアプリを全部非公開にした。
もう改造する気力もないので、さっさと非公開にしておけばよかったのだよ、私。。。

 

メールをくれた人、ありがとうございます!
来ないと気付きませんでした。

 

なお、nimocaなど交通系でSuicaと相互に使えるものは、たぶんSuicaを読むアプリで使えるので、そのアプリを使うのがよいと思う。

[py]pyCharmでUNCのパスを開くのは推奨していないそうだ

冬になり、デスクトップ環境だと足が寒くなった。
そうなると、自然とコタツ開発になってくる。

image

 

今作っているpythonスクリプトはLinux上で動かす前提だ。
うちはWindowsメインなので、VirtualBox上でLinuxを動かしている。
そして、そこにpythonスクリプトも置いている。

コタツにはノートPCがあり、そこからVirtualBox上の環境にアクセスするには、VirtualBoxのネットワーク設定を「ブリッジアダプター」にせねばならなかった。
「ホストオンリー」だとデスクトップ環境からしかアクセスできないのだ。

 

そうやってノートPCからVirtualBox上のLinux環境にアクセスできるようになった(Linux上ではSambaを動かしている)。
pyCharmで作ったプロジェクトも、ごそっとLinux上に移動させた。

そこまではよかったのだが、Windowsでネットワーク上のファイルアクセスする場合は\\serverのようなUNC名でアクセスすることになるのだが、pyCharmのプロジェクトを開くダイアログでUNCのパスを入力してもアクセスできないのだ。

 

検索したところ、pyCharmというかJetBrain系のツールかもしれんが、UNCでのアクセスは推奨していないようだった。
ネットワークドライブを設定してくれ、というような回答が見つかった。

しかし、それはめんどうなので、UNCでアクセスすることにした。


やり方は難しくなくて、ExploreからUNC先のフォルダを開き、そのpythonファイルをpyCharmで開くだけだ。
UNCのところには、あらかじめpyCharmのプロジェクトファイルを置いていなくてはならないだろう。
だから、一度ローカルでプロジェクトを作って、UNC先にコピーすることになるかな。

pyCharmで開くのは、pyファイルに関連づけていなければ、コンテキストメニューの「プログラムから開く」で選べばよいだろう。

一度開くと、pyCharmのプロジェクト一覧にはUNCの名前でも残るので、それをアクセスすればよい。
まあ、推奨されていないので正しく動かなくても知らんけどね。
うちの場合は実行がローカル環境じゃないので、単なるエディタとして使っているが、今のところ問題なさそうだ。
もちろん、Linux先のpython環境を参照するわけではないので、importでローカルに入っていないものがあればエラーが出てしまうが、そういうのはなんとかしよう。

2016/11/23

[py]1バイト分のstrを数値に変換するならord()が使える

先頭にデータ長が付いたstr型のデータを扱うことが多い。
こんなのだ。

cmd = '\x03\x12\x34\x56'

Cだったら、先頭のデータ長を取ってきたい場合、こうするだろう。

cmd = "\x03\x12\x34\x56";
uint8_t length = (uint8_t)cmd[0];

pythonだと、いつもこうやっている。

cmd = '\x03\x12\x34\x56'
length = struct.unpack('B', cmd[0])[0]

 

これが、ぱっと頭に思いつかない。。
そして、長い。
他に方法はないのだろうか?


1つ私が勘違いしていたのは、16進数でデータを突っ込んだ文字列はbytearray型だと思い込んでいたことだ。
文字列は、文字列だ。だからstr型になる。

これがッ、bytearray型だッ!

cmd = bytearray([0x03, 0x12, 0x34, 0x56])

まあ、他に記述方法があるのかもしれんが、見つけたのがこの書き方だった。
Cの書き方に近い。

この書き方の利点は、数値を取ってくることが可能なところだ。

cmd = bytearray([0x03, 0x12, 0x34, 0x56])
print 'cmd[0]=', cmd[0]

期待通り!

ただ、str型ではないので、こういうのはできない。

print 'cmd=', cmd.encode('hex')

が、これならいける。

print 'cmd=', str(cmd).encode('hex')

 

そうか。。。SQLiteで取ってきたBLOB型をstrして使っていたが、こういう意味だったのか・・・。
そういえば、BLOB型にINSERTとかするときも、bytearrayで囲んでいるし。

 

今はstrベースでやっているので、こういう感じで使うのがよさそうだ。

cmd = '\x03\x12\x34\x56'
print 'cmd=', cmd.encode('hex')
length = bytearray(cmd)[0]
cmd_byte = cmd[1: 1 + length]
print 'cmd_byte=', cmd_byte.encode('hex')

これだと、3バイト分表示されるので、これでいこう。

lengthに代入するのが「bytearray(cmd[0])」だとダメだった。
1バイト分取ってくるという意味では同じそうに見えるのだが。。。


などとごにょごにょ調べていたら、もう1つ別の方法を見つけた。
ord()だ。

length = ord(cmd[0])

こういうのを求めてたんだよ!

 

逆のパターンの、数値を文字列化する場合はchr()だそうだ。
今までこうやって書いていたのだけど、

%02x' % length

これでよいことになる(lengthの範囲によるけど)。

chr(length)

こう書くと、「cmd2= 02789a」となる。

cmd2 = chr(2) + chr(0x78) + chr(0x9a)
print 'cmd2=', cmd2.encode('hex')

 

組み込み関数は、私が求めているものが多そうなので気に掛けておかねば。

2016/11/22

[py]python3向けに書いた方が良いのか?

本屋さんでpythonの本を探していた。
だが、入門書か、えらく難しいものしかなさそうだった。
私が使う内容が今のところバイナリを作るだけなので、本を買うほどでもないというところかもしれん。

 

何冊かぱらぱらと眺めたのだが、その中に「python3で書く」というような項目があった。
もう、焦点がpython3に移っているので、まだpython2は数年くらい使われると思うけれども、3の方がいいよ、というような内容だったと思う。

 

今のところ、python2.7.12を使っているのだが、python3にした方がよいのだろうか?
コマンドラインで動かすスクリプトしか作っていないし、サーバに持っていきたいとしてもサーバから作ることになるから、バージョンは特に気にしていなかったのだ。
適当にインストールしたら2.7だった、という程度である。

 

前にスコープのことを調べたとき、ブロックスコープがないということを逆手に取り、importして例外が発生したらcatch...じゃなくてexceptで受けて別のimportを行う、という手法が紹介されていた。
Community Blog - Python の名前空間とスコープ

そんな感じで、置き換えはできるのかもしれない。
こんなのもあるし。
25.4. 2to3 - Python 2 から 3 への自動コード変換 — Python 2.7.x ドキュメント

 

が、ようやく少し慣れてきたところで、似ているけどちょっと違うものをやり始めると、混乱してしまいそうな気がしているので、やるのはもう少し後にしよう。

2016/11/21

[py]処理は小分けにした方がよさそうだ

前回、pythonのスコープのことを書いた。
いつも使っているC/C++と違って、関数やモジュールの単位しかないので、何気なく変数を使ってしまうと、それがスコープを外れないまま使われてしまうことになる。

まあ、通常はスコープ外と思って代入から始めるから問題はないのだけれども、思っていない変数が再利用されているというのは気持ちが悪いし、pyCharmも指摘してくるのでなんとかしたい。

 

ひとまず、グローバルにしたい、と思った変数は、大文字にしてしまうか、可変な場合は「g_」をつけて、まずは見た目で分かるようにした。
なんというか、自分がC/C++で書くときと同じルールを採用したということだ。

できれば、staticみたいなものがあるとよいのだけど、pythonにあるのかわからん。
たぶん、アンダーバーをつけるというのが、そういうやつなのだろう。
大文字の名前を付けるのと同じようなものか。

今のところ、まだモジュール間で変数を持ち合いたいような処理がないのでこうしているが、そうなっても問題ないように「g_」じゃなくて「_」だけにした方がよかったかもしれん。
まあ、検索のしやすさを考えて「_g_」とかか?
キャメルでの変数名は推奨されていないようだから、アンダーバーでつないで長くなってしまうけど、そこは仕方あるまい。

 

ただ、こうやっても名前を見て分かるだけで、「g_」がついていない変数はローカルスコープのつもりで扱うように、という管理をしなくてはならん。
これだと、pyCharmで指摘されるのは避けられないから、

  • 代入しなくてよい変数は作らず、直接引数に渡す
  • 処理単位ごとに関数に分ける

というのがよいのではないかと思った。

pydocで平文があると実行されるから「if __name__ == '__main__'」にしましょう、という記事見かけるが、スコープの観点からもそうした方がよさそうだ。
処理を関数に分けてしまえば、変数もその中だけになるので、使い回しにはならなくて安心だ。

 

という、理屈は分かるのだ!
わかるのだけど、言語に対する理解が足りていないので、処理をだらだらと書いてしまう。。
あれだな、C言語初心者の書いたコードを読んで「ここら辺は関数にすればよいのに」と思うのと同じことだろう。
頭で分かっていても、コードが付いていかないということがあるのだな。

 

こういうのは新しい言語を覚えるときにしか出てこないので、いろいろ言語を使い分けられるようになると、その言語自体に慣れる前に対応できるかもしれない。
その域に達することができるだろうか。。。

2016/11/19

[py]スコープはモジュールと関数しかないそうだ

pythonのスコープが全然理解できていない。
初出場の変数でエラーになるかと思えば、別の場所で使っている同じ変数名で「また使ってますよ」みたいな警告が出たりする。

なんなのだ、いったい!

 

Community Blog - Python の名前空間とスコープ

python 2.7.2の記事だが、スコープはモジュールと関数しかない、と書かれている。
それって、ブロック内の変数という見方ができない、ということか。。。
if文の中で使った変数が、他のところで同じ名前を使うと警告される理由が分かった。

変数をもっと局所的にしたいときは、関数の中に関数を書くことができるから、それで分離するとよいらしい。

val1 = 10


def func1():
    val2 = 20
    print 'val1=', val1
    print 'val2=', val2

    def func1in(v):
        if v == val1 * 2:
            return val1 * 4
        else:
            return -1
    val2 = func1in(val2)
    print 'val2=', val2
func1()

結果

val1= 10
val2= 20
val2= 40

func1in()の引数をなくして、これでもいける。

val1 = 10


def func1():
    val2 = 20
    print 'val1=', val1
    print 'val2=', val2

    def func1in():
        if val2 == val1 * 2:
            return val1 * 4
        else:
            return -1
    val2 = func1in()
    print 'val2=', val2
func1()

ただ、func1in()の中でval2への代入を行うと、ifで使っているval2がエラーになる。

val1 = 10


def func1():
    val2 = 20
    print 'val1=', val1
    print 'val2=', val2

    def func1in():
        if val2 == val1 * 2:
            val2 = val1 * 4
        else:
            val2 = -1
    func1in()
    print 'val2=', val2
func1()

じゃあ、func1in()の中に「global val2」を書けばよいかというと、これは実行時エラーになってしまう。
もしかして「globalじゃなくてlocalでは?」とやってみたが、そんなキーワードはなかった。。。

できなさそうな感じがするけれども、根拠の情報は出てこなかった。
まあ、初出場のグローバルじゃない変数は代入した時点でローカル変数になるらしいから、これも同じことか。

2016/11/18

[py]モジュールがあるフォルダのファイルを指定したい

SQLiteを使ってデータ管理をしている。
単独で使いたいこともあるので、ファイルを別にして、関数にして呼べるようにした。

そこまではよかったのだが、SQLiteへはファイル名しか指定していないので、pyファイルが別のフォルダにあると、そのフォルダでDBファイルを作ってしまうのだ。
これではDBにしている意味が無い。。

 

どこか固定のフォルダにした方がよいのだろうけど、フォルダを設定するのも面倒なので、SQLiteの処理を関数化したファイル(モジュール、でよいのか?)がある場所にDBファイルを作ることにした。

FULLPATH = os.path.realpath(__file__)
PATH, FNAME = os.path.split(FULLPATH)
DBFILE = PATH + os.sep + 'txlist.db'

os.sepは、パスのデリミタらしい。
「/」とか「\」とか。
Windowsもスラッシュだったらいろいろ楽だったのにねぇ。

 

pythonは、const/final/readonlyのような定数がないので、慣れないといろいろ気を遣ってしまう。
スコープも私が思っているような範囲と違うので、スクリプト言語ならではなのかもしれん。

2016/11/17

[py]外部変数と同じ名前のglobalではない変数がある場合、書込みを行うとローカル変数ができる

まだまだpythonはわからないことだらけ。。。

いま、pyファイルにべたっと処理を書いているので、少しずつ関数化させている。
ライブラリのような形ではなく、ファイルをモジュールと見なして、中で値を持つような作りにしている。
後で不都合が出そうだが、そういうのも含めて勉強だ。

 

DB_NAME = 'db_all.db'
sql = 'CREATE TABLE IF NOT EXISTS clients(filename TEXT, owner TEXT)'


def create_db():
    conn = sqlite3.connect(DB_NAME)
    cur = conn.cursor()
    cur.execute(sql)     ...

SQL文を変数にする理由はないし、関数外に置く理由はさらにないのだが、ちょっと外に置いてみた。
そうすると、一番最後の「sql」でpyCharmがエラーを出している。
Unsolved referenceとのこと。

私の理解では、

  • 関数の外に置いた変数は、グローバル変数
  • 関数内で値を変更したかったらglobal指示するけど、参照だけなら気にせずできる

だったのだが、そうではないのか?
pyCharmが強い警告の意味で表示させているのかと思ったが、実行させるとエラーだった。

でも、ファイル名のDB_NAMEはエラーになっていない。。
試しにsqlをSQLにすると、これだけでエラーにならない。
慣習じゃなくて、言語として大文字かどうかを判定しているのか??

 

が、実は上のコードには続きがもう少しある。

DB_NAME = 'db_all.db'
sql = 'CREATE TABLE IF NOT EXISTS clients(filename TEXT, owner TEXT)'


def create_db():
    conn = sqlite3.connect(DB_NAME)
    cur = conn.cursor()
    cur.execute(sql)

    sql = 'SELECT * FROM clients WHERE filename=?'
    cur.execute(sql, ('file1.txt',))     ...

この後ろに、さらに同じ名前の変数に代入する処理があったのだ。
そちらがあるために、その前にあるsqlはグローバル側のsqlを参照できなくなったようなのだ。
試しに、グローバル側をsql2にして、さっきエラーになったところもsql2にすると、エラーが出なくなった。
そういうものなんだ。。。

 

9. クラス — Python 2.7.x ドキュメント

ここに記載があった。
今回の場合では、グローバル側に同じ変数名sqlがあって読み出し専用になるのだけど、その後ろにsqlへの書込みがあるため内側のスコープで新しいローカル変数sqlを作ることになり、結果としてその前にあるsqlもローカル変数のsqlとして見られるようになり、初出場で参照しようとすることになってエラー、という流れだろう。

インタプリタだから上から順に見ていくのかと思ったけど、この動作からするとファイルを一度読んで構築するか、少なくとも関数レベルでは一度に構築しているのだろう。
順番は大切、ということだ。

2016/11/16

[py]連想配列ではなく「辞書」

やりたいのは、構造体だったのだ。
classで実現するのだろう、きっと。

それをグローバル変数でいくつか持っておいて、MQTTでメッセージを受信したとき、受信内容からグローバル変数の内容を参照する、というようなことをやろうとしている。
構造体は後回しにするとして、グローバル変数の中から期待するデータを取り出す、という検索のしくみが必要になるのだ。

データをどのくらいの期間つかうことになるのか見積もりできてないのだけど、短期間でよかったり、データ量が少ないのであれば連想配列がよいのかな、と思った。
C++でいうところの、std::mapだ。

 

pythonだと、辞書、というそうだ。
そして、オブジェクトでデータを扱うからか、数値だろうと文字列だろうと扱えるようだ。

ary = {'val1': 2, 'mon': 'ロンドン橋'}
print ary['val1']
print ary['mon']

 

ただ、キーは文字列限定のようである。
まあ、数字をキーにしたかったら、数字を文字列に変換させればよいだけのことか。

 

渡す値は、

{ キー : 値 }

というようにコロンで分けられている。
これを、間違えてコンマにしてしまうと、「dictionary update sequence element ~」というエラーが出て悩むことになる(pyCharmでもwarningが出ない)ので、注意しよう(10分くらい悩んでいた)。

2016/11/15

[py]sqlite3でテーブルがあるときに出る例外がうっとうしい

pythonで、データを保持する処理をしたくなった。
最初はファイルに保存することを考えていたのだが、SQLiteが使えるようなので、それを使っている。

 

が、C APIではエラーで済むところで例外が返ってくるので、「成功したらそれでよいし、失敗してもそれはそれでよい」というような場合の処理を書くのが面倒だ。
特に、今はきっちりした処理を作っているわけではないので、その気持ちが強い。

たとえば、こんなコードを書いたとしよう。

conn = sqlite3.connect(DB_NAME)
cur = conn.cursor()
cur.execute('CREATE TABLE clients(filename TEXT, owner TEXT)')

DBファイルがないときは通るのだが、既にテーブルがあると例外が起こる。

Traceback (most recent call last):
  File "sqlitest.py", line xx, in 
    cur.execute('CREATE TABLE clients(filename TEXT, owner TEXT)')
sqlite3.OperationalError: table clients already exists

じゃあ、こう書くか?

exists = os.path.exists(DB_NAME)
conn = sqlite3.connect(DB_NAME)
cur = conn.cursor()
if not exists:
    print 'create new TABLE'
    cur.execute('CREATE TABLE clients(filename TEXT, owner TEXT)')

回避はできるのだけど、わざわざこれやるの?という気もしてしまう。
それに、SQLiteのことをやるのにファイルの有無で確認する、というところがすっきりしない。

もちろん、tryで囲んでしまえばよいのだけど、CREATEのところだけ囲むのも格好がよくない気がする。
うーーん・・・

 

と、探していると、こういうのがあった。
Python sqlite3.OperationalError Examples

IF NOT EXISTS ?
そういうのがあるんだ!

conn = sqlite3.connect(DB_NAME)
cur = conn.cursor()
cur.execute('CREATE TABLE IF NOT EXISTS clients(filename TEXT, owner TEXT)')

うん、例外が出なくなった。
そうね、SQLのことはSQLのことで済ませられるということなのね。。。

2016/11/14

[esp8266]RTOS版がgithub移行?

GO TO GITHUB for LATEST SDK|请至 Github 下载最新 SDK - ESP8266 Developer Zone

いつものEspressifの人じゃないのだけど、githubがespressifだから本家なのかな?

 

https://github.com/espressif/ESP8266_RTOS_SDK

今日(2016/11/14)のところ、1.5.0が上がっている。
11/11に上がったようだ。

[Latest Release/最新发布] ESP8266 SDK-20161111 - ESP8266 Developer Zone

 

以前、ノーマルのSDK版を使って、受信バッファに1回では収まらないデータを処理するのがめんどうだったのだ。
Linuxみたいに、同期で受信待ちにできないので、「○○受信中状態」みたいなのを作り、一度コールバックを抜けてまた受信したら継続する、なんてことをやっていた。

RTOS版だったら、楽にできたのだろうか。
気になるが、気力がなかなかわかないのよねぇ。。。

 

Windowsでコンパイルする準備もできているようなので、そちらは準備してみたいところだ。
コンパイラは、こちらのようだ。
pfalcon/esp-open-sdk: Free and open (as much as possible) integrated SDK for ESP8266/ESP8285 chips

思い出した。
この前、Ubuntu on Windowsで64bit環境を作ろうとして、結局あれこれやってやめたやつだ。
micropythonというやつも気になるし、うーーーん。。。

2016/11/13

[py]未使用の引数を黙らせたい

pythonでMQTTしてみようと、pahoというライブラリを使っている。
接続したときにコールバックしてもらいたいのだが、そのコールバック関数の内容(signatureというのか)はこうなっている。

on_connect(client, userdata, flags, respons_code)

userdataやflagsなどは使わないのだが、使わないとpyCharmが「未使用ですよ」と言ってくる。
GCCだとvoidでキャストして黙らせることもあるのだが、pythonというかpyCharmだとどうやるのだろうか?

 

python - How can I denote unused function arguments? - Stack Overflow

1番目の回答は、ここから後ろ全部不要、という場合だろう。
(あまり調べてない)

2番目の回答で、delというキーワードを使うようになっていた。
リストの要素を消すときなどに使うようなのだが、オブジェクトの削除の意味でもあるようだ。

 

今回はdelで消すことにした。

[py]グローバル変数は前方参照じゃないんだ

こんなコードを書いた。

fname = ''

def change_fname(name):
    global fname
    fname = name

fname = 'default'
print fname
change_fname('kuma')
print fname

動くのだが、pyCharmが「default」を代入しているfnameのところでwarningを出している。

image

 

グローバル変数は最初に定義しないとダメだと思っていたのだが、まさか・・・。

def change_fname(name):
    global fname
    fname = name

fname = 'default'
print fname
change_fname('kuma')
print fname

warningが消えた。
それに、ちゃんと動く。
動くんだ。。。

 

いやぁ、スクリプト言語って、難しいわあ。

[py]sqlite3のfetchall()は吸い取る

眠たいので、起きている現象だけ書いておく。

pythonでデータを保存しようとして、SQLiteを使うことにした。
ファイルがないときは、connect()してcursor()で取得したら、CREATE TABLEして、INSERT INTOさせるようにした。
そして、そのあと確認のため、select文を実行させるようにした。

 

ネットで調べると、cursorに対してSELECTのexecute()したあと、fetchall()で件数分の処理しているようだった。
が、まねしても件数が0になっている。。
なぜだ・・・。

sql = 'SELECT * FROM clients'
ret = cur_all.execute(sql)
print 'len all=', len(cur_all.fetchall())
lists = cur_all.fetchall()
print 'lists all=', len(lists)
これで試したのだが、'len all='のところは数字が出てきて、'lists all='のところは0のままだった。
 
順番を入れ替えてわかったが「fetchall」だから、データを吸い取ってしまうようだ。
だから、fetchall()した後で見に行くと、0になっているのだ。
 
そうか、そうなのか。。。

2016/11/11

[py]pydocはHTMLに出せばUTF-8日本語も見える

使い方が面倒なpythonライブラリを作っていたので、後から思い出せないだろうと思い、コメントを書いている。
ライブラリを作っているというよりは、コードを書いて、ここは他でも使えるかも、と思ったら関数化しているだけなので、かなり行き当たりばったりだ。

 

こんな感じのソースを作っている。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
test library
"""

##
# @file    test.py
# @brief   test library

##
# テストデータ
TEST_VALUE = '\x12'


##
# テスト関数
# @param[in]        msg         メッセージ(str)
# @return           bytearray値
def testfunc(msg):
    # テスト関数
    return msg.decode('hex')

 

これを、cygwinのpydocに通すと、こうだ。

image

しかし、-wオプションを付けてHTML出力すると、こう。

image

コンソールでちょっと確認する、という用途には使えないのだが、まあ、これはこれでよいかな、と思う。
doxygenコメントを入れているので、pydocでもフォーマットはされていないながらなんとなく引数の説明もできているし。

 

doxygenに通すと、こんな感じだ。

image

悪くないんじゃないかね。

2016/11/09

[py]範囲の条件は連続して書ける

値が、1~16の間だけ別の処理をしようとした。

if (1 <= val) and (val <= 16):
    ...

しかし、pyCharmが警告を出してくる。
ちゃんと&&じゃなくてandを使ってるし、なぜ?

ま、まさか。。。

if 1 <= val <= 16:
    ...

おお!
こんな書き方ができるんだ!
けっこう衝撃的でした。

 

高校の時だったと思うけど、丸括弧が値を含まない、角括弧が値を含む、という条件式の書き方があったと思う。
もし1より大きくて16以下だったら、val=(1, 16]、というような書き方だ。
手元に教科書がないのだけど、あの表現方法は何だったのだろう?

不等号 - Wikipedia
区間 (数学) - Wikipedia

区間を表すのに使われると書かれていた。
どちらかというと、集合論の使い方になるのか。

[win10]Windows Update v.s. 私 (敗北)

なんだ、このタイトルは・・・。
経緯は、少し前のブログを見ていただきたい。
hiro99ma blog: [win10]Home版でWindows Updateは止まるか?

今の時刻は、2016/11/09 1:11。
Windows Updateの更新日だ。
Windows10 Proはよいとして、Home版でWindows Updateを行わないようにさせたい。
想定しているのは、通常時はWindows Updateを勝手にしてもらって構わないのだけど、これから2,3日間はPCをつけたままテストを行わなくてはならないため、再起動されては困る、という状況だ。
再起動しないのであれば、別にWindows Updateが動作しても構わないのだ。

で、その準備としてスリープ状態から復帰させたのだが・・・。
以前作った、Windows Updateに関連するスケジュールの停止とタスクの停止を行うバッチファイルを動かしたのだが、止めても止めてもスケジューラが復活してくる。。。
どれかというと、"Scheduled Start"だ。
このタスクは、無効にしても起き上がるし、削除しても復活。
手の打ちようがない。

Scheduled Startのイベント履歴を有効にしているのだが、どうも30分おきにNT AUTHORITY\SYSTEMがイベントを登録しているように見える。
うぅむ、SYSTEMには勝てないような気がする。。

今の時刻は2016/11/09 9:42。

昨晩から電源ONしたままのWindows10 Home版は、まだ再起動していない模様。
通知の方にも何も出ていない。

まあ、それを言えば、今起動したWindows10 Pro版も更新通知をしてこないから、同じことか。
しかし、Scheduled Startタスクはきっと起きているだろう。
そして昨日無効にしたときには、次回の起動が明日の0時くらいになっていたように思う。
仕方ないので、Home版は起動したまま仕事に出ることにしよう。

今の時刻は、2016/11/09 22:28。

まだ、再起動していないようだ。
リストを見ると「要再起動」があるから、やってれば再起動するか、少なくとも通知に出ているだろう。
2016 年 11 月のセキュリティ情報 (月例) – MS16-129 ~ MS16-142 – 日本のセキュリティチーム
ここでWindowsUpdateの設定画面を見てみたいところだが、それをやってしまうと意味がなさそうなので、ぐっと我慢だ。

ただ、今日寝るまでに再起動してなくても、明日の朝まではONにしたままにしておこうと思う。
なんというか、期待する結果としては「Scheduled Startタスクが復活してくるので、これではダメでした」というところなのだ。
もしこの程度で止めることができると、それはそれでなぁ、と複雑な心境になりそうだ。
説明が付けられれば、止まってもいいんだけどね。

今の時刻は、2016/11/10 1:07。

「くっ、大技『日付越え』をくらって生きているとは、おぬし・・・」という心境だ。
ブラウザを使ったりしていたけれど、今までだとその程度だと無視して再起動していたしなぁ。
Excelの編集中ですら、容赦なく再起動されたこともあったし。

もしかすると、最近のアップデートによって、あそこまでの強制的な再起動は行わないようにした、という可能性もある。
または、多少でもユーザが使っている雰囲気があればやらない、とか。
そうだとすれば、Update日を過ぎ、ユーザ操作もなくなるこの一晩は耐えられないんじゃなかろうか。


午前1時30分。
ノートパソコンの方から通知音が。。。
来るべきときが来ただけかもしれない。
明日だ、明日。

今の時刻は、2016/11/10 8:39。

はい、再起動していました。
起動していたアプリはまた立ち上がったものの、復帰に対応していないアプリは単に起動しただけだ。
つまり、私の負けだ。私負けましたわ。

今回分かったのは、こういうところか。

  • WindowsUpdateのタスクを無効にすると、ユーザ操作からも更新できなくなる
  • スケジューラのWindowsUpdate/Scheduled Startは止めても削除してもSYSTEMが復活させる
    • その復活を止めればなんとかなるのかは、不明

となると、どうしてもやりたくないようにするなら、WindowsUpdateタスクを無効にするしかないということか。
Windowsの不要なサービスを停止、無効化する - labunix's blog

sc config "wuauserv" start= disabled

で無効になり、

sc config "wuauserv" start= demand

で手動(トリガー開始)になるようだ。

また来月だな。

2016/11/08

[c++]catch(...)の「...」は取ってこられないみたい

駅前が陥没して通勤路をどう迂回するか検討中だけど、まあよかろう(よくはない)。

 

pythonで作ったデータをパースしてくれるアプリがいて、そのアプリはC++で書かれている。
データが正しいかどうかはそこそこ判定してくれているのだけど、だんだん複雑なプロトコルを作ることができるようになったためか、とうとう「unknown error」というどうしようもないメッセージしか出してくれなくなった。。。
やむなく、アプリにprintfログを埋め込んで、どこが悪そうなのか当たりを付けることにした。

そうすると、どうやら例外が発生しているようだった。
そして、それはcatch(...)で捕捉していて、その場合に「unknown error」としているようだった。
ちっ。

 

さて、このcatch(...)。
関数の引数であれば、va_argsなどで取ってくることができるけれども、例外はどうなんだろうか?

調べた範囲では、取ってくることはできなさそうだった。
『プログラミング言語C++第3版』の§14.6.3.2に書いてありそうな雰囲気だったのだが、そういう感じではない。
今回のアプリは、どうやら標準例外を使ってくれているようで、別途catchを追加してエラー出力を追加するようにした。

しかしまあ、オープンソースで公開されているアプリとはいえ、規模が大きくてデバッガも使えないような状況だと、例外だけでもソース解析がつらいですな。
例外を投げるしくみにするときは、例外用クラスをぽこぽこ作るのではなく、標準例外を継承して作るようにした方がよいのだろう、たぶん。

[py]エンディアンをひっくり返す(bytearrayの)

pythonをいま使っている範囲では、凝った使い方は全然していない。
計算して、printするくらいだ。

そうなるとどうなるかというと・・・ネタがすぐに切れるということになる。
しばらくpythonネタを続けられるとほくそ笑んでいたのだが。。。

 

小ネタとして、エンディアンをひっくり返す話でも書くとしよう。

struct系のAPIには、<や>を使ってエンディアンを変更する方法があるけれども、bytearrayになっているものは特にAPIが無さそうだった。
自力で回す関数を作ったのだけど、こんなのでよいのか?

def reverse_endian(msg):
    rev = ''
    for lp in msg:
        rev = lp + rev
    return rev

うん、forで1byteずつ抜き出して、頭に追加するだけだ。
間違ってはいないと思うが、まだ格好のよい方法があるのかもしれん。

 

まだdecode('hex')する前の文字列でも、エンディアンを変更したいことがあった。
そっちは、こうやっている。

def reverse_endian_str(msg):
    rev = ''
    for lp in range(0, len(msg) / 2):
        rev = msg[lp * 2: lp * 2 + 2] + rev
    return rev

うーん、2つずつスキップする方法もなさそうだったから、先頭から2文字ずつ抜き出して先頭に追加する、をやっただけだ。
そのまますぎるのだけど、他にないよね?ないよね??

 

最近の言語だから、なんか格好のよいやり方があるかも!と模索して時間を費やしてしまうことが多いのだが、大したことない作業だったら自分でやる、という方がスクリプトとしては良いのかもしれない、と思うことにしよう。

2016/11/05

[py][nfc]nfcpyでRC-S380を動かす(Windows10)

数週間pythonを触ったので、そろそろnfcpyもわかるようになってきたんじゃなかろうか。

nfcpy/nfcpy: A Python module to read/write NFC tags or communicate with another NFC device.

いつの間にかgithubになってるし、READMEを読んだところではpipでインストールできるらしい。
ドキュメントはこちららしい。

Python module for near field communication — nfcpy latest documentation

 

過去に動かしたことはあるのだが、もうすっかり記憶にないので、ちょうどよいだろう。
うちの環境は、こう。

  • Windows10 Pro 64bit
  • PaSoRi RC-S380/P

PaSoRiのドライバはインストールされている。
が、たぶんそれは切り離すことになるだろうね。


Overview — nfcpy latest documentation

pythonは2.6以降。でも、3は対応していないとのこと。
それと、libusbを使うようで、そのpythonライブラリがpython-libusb1らしい。
libusbは、APIが0.x系と1.x系があったので、その1.x系ということだろう。
pyserialはPaSoRiでは不要なのだけど、無しでもよいのかな?

 

Getting started — nfcpy latest documentation

pythonは既にインストールしているので、それを使う。
幸い、pipの場所もPATHに追加しているようで、コマンドプロンプトから"where pip"で見えた。

> pip install libusb1

これで、v1.5.3がインストールされたようだった。
これだけだとWindowsではlibusbがないので、そっちは自前でインストールする。

説明ではいろいろ書かれているけど、たぶんこういう手順だろう。

  1. zadigを使って、PaSoRiをWinUSBドライバで扱うように変更する
  2. libusbをインストールする

zadigでドライバを差し替えられるのだが、libusbKやlibusb-win32という名前に引きつけられず、WinSUBを選ぶ。

image

デバイスマネージャでは、こう見えるようになる。

image

 

libusbは、ここから、「Downloads」をクリックするとsourceforgeに飛んでダウンロードされる。
このサイト、ずっと「libusbX」とばかり思っていたのだが、Xに見えていたのは単にケーブルがクロスしている画像だったのか?
いや、libusbxというサイトもあるな。まあいいや。

使うのはDLLファイルだけのようで、私は64bit環境なので、MS64\dll\libusb-1.0.dllになるだろう。
c:\Windows\System32にコピーするよう書かれているが、DLLってPATHのどこかに置けばよいのではなかったっけ。
まあ、試してダメだったらコピーしよう。


次は、bzrで最新版を取ってくるよう書かれているが、これはgithub版でいいや。
pipで取ってこれると書いてあったから、それでよいのかも。
最新のリリース版は、v0.11.1で、これが2016年4月29日。
うーん、半年以上経っているからgithubの最新版を使うことにしよう。

 

以前から気になっていたのだが、こういうライブラリには「setup.py」というファイルがだいたいついている。
これは何だろうか?
説明によると、配布する際の情報を書くようだった。
ということは、このファイルがあればPYTHONPATHなどに書かなくてもよいようにインストールできるのだろうか?

> python setup.py install

なんか、だーっと流れた。
「python27\lib\site-packages」に置いたというようなメッセージが出たので見に行くと、nfcpy-latest-py2.7.eggというファイルがあった。
eggって、卵?
まあ、いいや。


そして、もうexmaplesを動かす。
ここでは、examples/tagtool.pyというコマンドを動かすようだ。
なんとなく、タグを読むサンプルのような気がするので、PaSoRiの上にMIFARE Ultralightのカードを置いておく。

さっきのlibusb-1.0.dllは、うちではC:\Winappliというフォルダの中に置いているので、そこにパスを通す。

>set PATH=%PATH%;c:\Winappli

そして、実行。

>python examples/tagtool.py show
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:002:015
** waiting for a tag **
Type2Tag 'NXP NTAG203' ID=04079672B92981
NDEF Capabilities:
  readable  = yes
  writeable = yes
  capacity  = 142 byte
  message   = 0 byte

 

へー、これだけで動くんだ。
pynfcもだけど、汎用のUSBアクセスができるlibusbの力は偉大ですな。

 

もしかしたら、Ubuntu on Windowsでも動くのでは?と思ったが、今のところUSB機器をサポートしていないらしい。
http://stackoverflow.com/questions/38954691/is-usb-supported-on-bash-on-ubuntu-on-windows-10

実際、ダメだった。
今後のアップデートでストレージは使えるようになるかもしれないけど、libusbはどうなるか微妙なところだと思う。
好みの環境を作るのは難しいねぇ。

2016/11/04

[win10]Bash on Ubuntuで大文字と小文字のファイルが作ることができた

今までWindows上では何かとcygwinを使って開発していたのだが、Bash on Ubuntuが使えるので、そろそろcygwinを使わなくてよいのかもしれない。
コマンドプロンプト風だと使いづらいので、TeraTermでcygtermが動くような感じで使えるとよいのだが。
SSHが動くという話を聞いたので、そのうち試そう。

 

Bash on Ubuntuのファイルシステムは、エクスプローラでパスを直書きしないと見えないようなところにあるのは分かったが、ext4みたいな扱いなのだろうか?
試すのは簡単なので、やってみた。

image

場所はc:\Tempというフォルダで、ドライブはWindows10 Homeプレインストールされている。
バージョンは知らないが、NTFSだ。

FAT32まではなんとなく仕様を把握していたのだが、このレベルでLFNにはならなかったはずだ。
cmd.exeで”dir /x”としても、違うファイル名があるわけではない。
ということは、少なくともNTFSでは大文字小文字で別に判断するようになったということだろうか。

エクスプローラでも別のファイル名として見えはするのだが、アクセスできるのは大文字のファイル名の方だけだ。
ここら辺は、FATの仕様を踏襲しているのかも。

[py]C言語風に書けない条件式

エスケープシーケンスはC言語と同じように書けたpythonだが、そんなことを気にせず書いていてエラーになったところがある。
条件式だ。

if (len(message) == 3) && (message[0] == 'K'):
  print 'けけけ'

とか、

result = some_boolean_method()
if !result:
  print 'oops!'

とか。

括弧の数が合っていないのでは、とか、前の方に書いた式がどこか間違っているのでは、とかとか、いろいろ調べて、ようやく&&やら||やらが無いということに気付いた次第だ。

 

否定はnotよりも!のほうがうれしいのだけど、論理積と論理和はandとorでいいんじゃないかな、と思う。
ぼーっとして、ビット演算の&や|と間違うことがたまにあるのでね。

[win10]Home版でWindows Updateは止まるか?

みんな悩んでいるWindows10のUpdateで勝手に再起動問題。
うちはPro版しか無かったので気にしていなかったのだが、最近Home版のPCを購入した。
もはや他人事とは言っていられない…。

なお、今回は新しいPCからブラウザで更新しているので、普段と見栄えが違うかもしれん。

Windows Updateはサービスだから、まずはサービスを止めてみた。
「スタートアップの種類」を「無効」にしたのだ。
まあ、一番確実そうな手段だ。

しかし、これはよろしくなかった。
自動での更新を止めて、手動でボタンを押して更新するように仕様と考えていたのだが、更新ボタンを押すとエラーになってしまったのだ。

そこで元に戻したのだが、よく見ると「手動」ではなく「手動(トリガー開始)」になっている。
調べてみると、トリガー開始というのはタスクスケジューラなどのトリガーで開始するようだ。


管理ツールのタスクスケジューラを開き、タスクスケジューラライブラリの中のMicrosoft/Windows/WindowsUpdateを開いた。
(どうでもよいことだが、「タスクスケジューラー」と延ばさないんだな。。)

そこには、項目が4つあった。
  • Automatic App Update
  • Scheduled Start
  • sih
  • sihboot
Appはストアアプリっぽいから生かして置いてもよい気がするが、よくわからんので4つとも無効にしてみた。
Windowsを再起動させても、無効は維持できているようだ。


これが効くかどうかは、よくわからん。
WindowsUpdateが確実に行われる日に動作しなかったら、たぶん効いているのだろう。
ただ、このタイマの2番目は、手動でWindowsUpdateを行うと開始されるようだ。
だから、手動で更新して、再起動する必要がないようであれば、サービスとスケジュールの両方を止めればよいような気がする。
サービスはsc.exeを管理者権限で呼び出せば止まりそうだけど、スケジューラはschtasks.exeで制御するのかね。

それかもう、スケジューラから設定を削除してしまって、サービスを止めるだけにしてしまう、という手段もとれるかもしれない
エクスポートして残しておけば心配は少ないのだが、忘れそうだ。。。

いっそのこと、スケジューラを使ってWindowsUpdate関連を定期的に止めてしまうようにしてしまえばよいかもしれん。
ただ、管理者権限で実行できるようにできるのかわからん。


まったく、再起動のタイミングを制御できないというだけで、ここまで苦労することになろうとは。。。

[2016/11/04更新]
だめだ・・・。
いつの間にかスケジューラが起動しているようだ。
現代の知識では、まだ克服できそうにない。

おそらく、Windows Updateの処理が始まってしまうと、再起動まで止めることはできないように思う。
気付けば再起動オプションで変更できるかもしれないが、数日放置するテストをしているときなんかは、気がつかないかもしれない。
であれば、何か長時間の処理を行う前にWindows Update関連を止めてしまえばなんとかならないだろうか。

そんなことを考えて、こういうバッチファイルを作った。

schtasks /change /TN "Microsoft\Windows\WindowsUpdate\Automatic App Update" /Disable
schtasks /change /TN "Microsoft\Windows\WindowsUpdate\Scheduled Start" /Disable
schtasks /change /TN "Microsoft\Windows\WindowsUpdate\sih" /Disable
schtasks /change /TN "Microsoft\Windows\WindowsUpdate\sihboot" /Disable
sc stop wuauserv
pause

最後のpauseは、結果を見たいだけだ。
これを管理者権限で実行すると、取りあえず書いている内容については止まるようだ。
だからといって、これでWindows Updateが停止できるかどうかというのは、また別の話だ。
さて、どうやって確認したものか。。。


[2016/11/05更新]

Scheduled Startタスクが強い・・・。

このタスクがいつも準備状態になるので削除したのだが、スリープから復帰するとタスクが生き返っていた。
スリープから復帰する程度で甦るんだったら、ずっと起動しているだけでも復帰させられてしまいそうな気がする。

 

それとは別の話だが、ちょうど今、新しいデバイスをUSB接続しようとしているので、その前後でタスクやサービスが自動で起き上がるか見ておこう。
なお、デバイスドライバを自動でダウンロードする設定は「いいえ」にしている。

 

いざ!
・・・あれ、デバイスマネージャで普通に認識されてしまった。
PaSoRi RC-S380だったのだけど、NFC Forum認証デバイスだけあって、既に組み込まれていたのだろうか?
ただ、NFC Port Softwareまではインストールさせなかったので、完全ではないだろう。

しかし、これはダウンロードしない設定だったからというよりも、ユーザに確認する画面で私が「いいえ」にしたからインストールされなかっただけで、自動でやらない設定にしていたためではないような気がする。
試しに、空のタグを置いてみたのだが、タグを認識した音が聞こえた。
うーん、もっと特殊なデバイスじゃないとわからんな。

そしてサービスとタスクスケジューラだが、タスクスケジューラに変化はなかったものの、Winodws Updateサービスは実行状態になっていた。
油断がならん。

直近のWindows Updateの日は、来週の水曜日だ。
何時くらいなのかは、PC依存なのか。。。
ということは、火曜日の寝る前に作ったバッチファイルを動かしてそれっぽいものを停止させ、PCを付けたまま寝て、翌朝確認すればよいのだな。
おっと、無操作のスリープや休止状態を無効にしておかないとな。
https://technet.microsoft.com/ja-jp/security/hh224643

2016/11/03

[win10]ドライバの「ダウンロード」をしたのにインストールまでされた

単なる事例報告だ。

Windows10 Proを使っているが、自動的に再起動されると困るので、gpedit.mscでWindows Updateは「ダウンロード前に通知」にしている。
ダウンロードとインストールを別々に操作するのが多少面倒だが、作業している間にダウンロードしてしまって、終わったらインストール、というようにしている。
「ダウンロードしたら通知」もあるけど、ダウンロード自体したくないかもしれないのでね。

 

今日は起動すると通知が出てきたので更新内容の一覧を見ると、グラフィックドライバ1件だけだった。
異論は無いので「ダウンロード」ボタンを押したのだが・・・・インストールまでされてしまった。
グラフィックドライバがインストールされると、デュアルモニタで開いているウィンドウが1つに集められるし、ウィンドウサイズもVGAくらいに小さくなってしまうので、元に戻すのが面倒なのだ。

 

インストールを自動でされた理由がまだ分かっていないのだが、これだろうか?

image

 

別のことを調べてるとき、Windows10でExcelがうまく動かない現象は、プリンタのデフォルト出力先設定をOSが行うようにする(既定)を戻したら直った、という情報を見たこともある。
こういう風に、どの設定がどこに関わっているか分からないというのは、なかなかつらいものだ。

 

こうなった私の予想としては、今までWindows Updateをしなくて不具合が起きたことによるサポート電話とかがひどく多かったので、「ええい、うるさい!」ということでHomeを使っているユーザが一番多いだろうから強制的にインストールやらUpdateやらさせるようにした、というものだ。

来年の頭にまた大きいアップデートがあるらしいから、そこに期待するか。。
変更が柔軟になったのはそこそこ喜ばしいのだが、OSの基本機能が許容できる範囲になっていないとつらいものだ。

2016/11/02

[py]エスケープシーケンスで16進数

pythonで16進数を扱うのに疲れてきた・・・。
前回classを作ってはみたものの、お仕事で作っているライブラリはもう終わりかけなのでわざわざ書き直す気になれないけれども、使っているとやっぱりミスをしばしば。。。

 

さて、今まで16進数をbytearrayに突っ込むのに、文字列で16進数を書いてdecode('hex')する、という技しか知らなかったのですが、エスケープシーケンスが使えることをようやく知りました。
今さらかよ、私・・・。

'1234'.decode('hex') ==> '\x12\x34'

うん、固定値の場合はこっちの方がわかりやすい。
いやぁ、いままで1byteのときも「'01'.decode('hex')」などと書いていて、げんなりしていたのだ。

まだ応用が利かないので、じわじわやっていくしかないですな。

 

 

この辺の書き方がC言語と同じなのは、興味深いところだ。
ただ、Cだとお尻に\0が付いてしまうので、{ 0x12, 0x34 }と書く方を私は使う。

使うのだけど、プロトコル中に埋め込む文字列を定義するときは、{ 'h', 'e', 'l', 'l', 'o' }などと書きたくないので、目をつぶって"hello"と書いて、sizeof()して1引いて使っている。

ろ、ROMに余裕が無いときは、ちゃんとやってますから!

2016/11/01

[py]pyCharmのProject表示とStructure表示を別にする

pyCharmをほぼ初期状態で使っている。
キーバインドは覚えられないので、Eclipse設定にして、知っているものだけ使っているくらいで、ぜんぜん使いこなしている感じはしない。。

まあ、これからだ。

 

pyCharmは、初期状態だとだいたいこういうウィンドウ構成になっていると思う。

image

左側のTool Buttonsのところに、ProjectとStructureのボタンが並んでいる。
(まあ、Windowsだけか知らんが、文字が化けていて読めないのだが。。)

そのボタンを押すと、黄色の部分に表示される内容が、Projectだとファイル構成になるし、Structureだと関数一覧などになる。

 

しかし、右側が広く空いているのだ。
長い行数にするとエディタが警告してくるので、自然とテキストウィンドウエリアは幅を取らなくなってしまう。
もったいないので、右側にStructureを移せないだろうか?

 

調べて分かったのだが、Tool Buttonsのボタンはドラッグアンドドロップで移動できるようだ。
しかも、違う場所へも移動できる。
つまり、ウィンドウの右側にボタンを移動させることができるのだ。

そうすると、ボタンの近い方に窓が開いた。

image

そして、近い方の内容をちゃんと表示してくれるようだ。