uitspitss blog

プログラミングと音楽とエッセイ ※記載内容は個人の見解であり、所属する組織とは一切関係がありません。

オンラインジャッジでの Python Tips

最近、時間があるときにオンラインジャッジの競技プログラミングもどきをやっている。 オンラインジャッジでは、入出力がCLIで行われるため、 入出力周りで何度となく同じようなコードを書く。 しかし、1ヶ月くらい別の言語をいじってたりすると、 そのようなコードを書くのに少し時間が掛かってしまう。 ということで、よく使う(使った)ものをまとめておこうと思った。

input系

単純に入力が数値のときには、input()から得られたstrをintに変換しておくと、 後で数値演算したときにエラーを吐かれることがない。

int_single = int(input())  # <= 1
print(int_single) # => 1

スペース区切りで数値が複数渡されたときは、strのsplit()で分割して、 intに変換しておく。これで、ループに使うときも変換がいらない。 多重代入もよく使う。

int_list = [int(x) for x in input().split()] # <= 1 2 3
print(int_list) # => [1, 2, 3]

a, b, c = [x for x in input().split()] # <= test1 test2 test3
print(a, b, c) # => test1 test2 test3

上と同じ1行スペース区切りだが、数値文字列だけではなく、 通常の文字列も含まれていて、そのままintに投げてしまうとエラーになる。 そんなときは、内包表記内に三項演算子で条件分岐処理を入れ込む。 strのisdigit()は結構使う。

# <= l1 10 20 30\nl2 10 20 30
labeled_list = [[int(x) if x.isdigit() else x for x in input().split()] for i in range(2)]
print(labeled_list)
# => [['l1', 10, 20, 30], ['l2', 10, 20, 30]]

複数行で文字列が入力されるときは、range()ループで必要な回数分、 ループを回せばOK!

str_list = [input() for i in range(3)] # <= 1\n2\n3
print(str_list) # => [1, 2, 3]

複数行の入力がある場合かつ終了条件がある場合、 これは諦めて、while Trueループを書いちゃってる。

input_text_list = []
while True:
    input_text = input() # <= test1\ntest2\ntest3\ntest4\ninput end.
    if input_text == "input end.":
        break
    input_text_list.append(input_text)
print(input_text_list) # => ['test1', 'test2', 'test3', 'test4']

loop系

whileループやforループのelse句はよく使う。 フラグ処理が省略できるので、楽々。

cnt = 0
while True:
    cnt += 1
    for i in range(10):
        cnt += 1
        if cnt > 100:
            break
    else:
        print(cnt)
        continue
    print("last cnt: {}".format(cnt))
    break
# => 11\n22\n33\n44\n55\n66\n77\n88\n99\nlast cnt: 101

zip()は複数のリストやタプルをまとめてループできる。 それと、内包表記の多重ループ。平面グリッド走査のような全ての組み合わせでループを回すときなどで使える。 あと、文字列のjoin()もよく使う。

upper_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lower_str = "abcdefghijklmnopqrstuvwxyz"
upper = ["{}:{}".format(u, ord(l)-32) for u,l in zip(upper_str, lower_str)]
lower = ["{}:{}".format(u.lower(), ord(l)) for u in list(upper_str) for l in list(lower_str) if u == l.upper()]

print("\n".join(upper)) # => A:65\nB:66\nC:67\n …
print("\n".join(lower)) # => a:97\nb:98\nc:99\n …

pythonでEmail自動生成スクリプトを作って得たTips

久しぶりの備忘録的なブログ。
この前、Email処理を楽にするスクリプトを書いたとき、ちょっとした知見が得られたので、備忘。
今回、メールを送信する前に人間の目で最終確認、ちょこっと編集をしたかったので、 任意のディレクトリ下にメールファイル(.eml)を生成していくスクリプトを作っていました。 そこで、気になったことが1つ。 生成したメールファイル(.eml)を開くと、メールソフトが立ち上がるのですが、 編集状態ではなく、受信したメールと同様に編集不可の状態で開かれてしまいました。 これは、Windows Live Mail (WLM) での動作のようで、 私が私的にメインで使っている Thunderbird では、 再送信(再編集)の項目がメニューにあり、ひと手間かかるようですが、再編集状態にできました。 ただ、仕事でWLMを使えと言われたら、使わないといけませんので、どうにかしようと思って検索をしていたら見つけました。

Windows Liveメールの再送方法

上記のページを読むと、Header中の X-Unsent に 1 を入れればよい、とのこと。
そして、肝となる部分を抜粋してきたコードが以下。

環境

  • python 3.5.1
  • email(標準ライブラリ)
import email
from email.mime.text import MIMEText
from email.utils import formataddr
from email.header import Header
from email import generator

from_addr = 'from_addr@mail'
to_addr = 'to_addr@mail'
subject = "メール件名"
body = "メール本文"

encoding = 'utf-8'
sender_name = Header('fromのニックネーム', encoding).encode()

message = MIMEText(body.encode(encoding), 'plain', _charset=encoding)
message['Subject'] = Header(subject, encoding)
message['From'] = formataddr((sender_name, from_addr))
message['To'] = to_addr
message.add_header('X-Unsent', '1')

with open('test.eml', 'w') as eml:
    gen = generator.Generator(eml)
    gen.flatten(message)

print("** end **")

node.jsでScratchXとDigisparkをつなげる

今年の頭にやっていたことを振り返って、ターゲットとして初心者を想定した割に、 手順が多すぎると感じたので、node.js(electron)で手順を少なくした。
※毎度のことですが、実際にやるときは自己責任でお願いいたします。

f:id:uitspitss:20160930052102j:plain

electronでバイナリ化

最終的な形としては、これを目指していて、Windowsでもこれがやりたかった。
現時点、Macのみ対応。Windowsについては後述。
動作確認した環境は

  • OS X 10.11 (El Capitan) - 64bit
  • macOS 10.12 (Sierra) - 64bit

準備

Digispark

Digisparkには、ArduinoIDEを使って、File > Examples > DigisparkUSB > DigiBlinkの DigiBlink.inoを書き込んでおく。

libusb
  • libusbが必要になるので、パッケージマネージャーのHomebrewを入れる。
  • Homebrewを使って、libusbをインストール。 brew install libusb
app

実行

app実行時にクリップボードにURLのコピーが行われるので注意!
DigisparkをUSBに挿した状態で、中に入っているappを実行すると、以下のようなウィンドウが立ち上がる。

f:id:uitspitss:20160930051712p:plain

appを立ち上げたときに、ファイアウォールからの警告が出てきたら、「許可」「拒否」どちらかを選択で警告ウィンドウは消す。

あとは、立ち上ったウィンドウに表示されているURLにウェブブラウザ(Chrome推奨)でアクセスすると、 以下の画像のように、その他(Others)のところにDigispark用のブロックが読み込まれているはず。

f:id:uitspitss:20160930051707j:plain

この読み込まれたブロックを組み込んでプログラムを書くとその通りに動く。

Windows

Windowsでは、electronとnode-usbの相性問題でelectronがコケてしまうので、 electronを使わずにCLIで動くものも書いた。

環境

動作確認した環境は

  • Windows10
  • node.js - v6.1.0
  • npm - 3.8.6

準備

Digispark

ここは、上述のelectronバージョンと同様。

libusb

Windowsではzadig(usbドライバ書き換えソフト)を使ってインストール。

  • zadigをダウンロードする。
  • zadigでDigiUSBのドライバをWinUSBに変更する。
node

まず、下のリポジトリをクローンしたら、コマンドプロンプト(cmd.exe)で落としてきたディレクトリの中に入る。

uitspitss/electron_scratchX-digispark

そして、 npm installで必要パッケージをインストールする。 (package.jsonのelectronは不要であれば、はずしてしまっても大丈夫)

実行

パッケージのインストール後、同ディレクトリの中で node no_electron.js とすると、 以下のような出力が出てくる。

-master>node no_electron.js
Digispark is opened.
ACCESS to following URL
http://scratchx.org/?url=http://localhost:9911/myscratch.js
R:255(100%), G:255(100%), B:255(100%)
R:130(51%), G:10(4%), B:8(3%)
R:212(83%), G:105(41%), B:222(87%)
R:245(96%), G:145(57%), B:161(63%)
R:77(30%), G:229(90%), B:171(67%)
R:214(84%), G:184(72%), B:222(87%)
R:117(46%), G:0(0%), B:26(10%)
R:217(85%), G:41(16%), B:102(40%)
R:41(16%), G:242(95%), B:224(88%)
R:61(24%), G:66(26%), B:194(76%)

-master>

実行後に出力されるURLにブラウザ(Chrome推奨)でアクセスすると、 上述したelectronのものと同様の動作をする。 R:~以下の部分はScratchXで組み込まれたブロッグが実行されると出力されるもの。

終了するときは、Ctrl-Cで終了。

Windows環境においてのelectronとnode-usbの問題

electronは、使用するパッケージ内部のnodeのバージョンとelectron内部のnodeのバージョンを合わせるようにパッケージをリビルドする機能がある。 しかし、このリビルドがコケてしまい、electronで起動すると、node-usbでできなかった。 このあたりは、node-usbのissuesのあたりに前例はあったけど、VisualStudioのバージョンも噛んだりしていて、私の環境では解決しなかった…

まとめ

技術的なところ

今回は、できるだけnode.jsで使うパッケージを減らす方向で作り始めた。 というのも、下調べ段階で、node.jsとelectronがともにのバージョンアップが頻繁であり、 パッケージのバージョン違いでビルドが失敗しているのをよく見かけたため。

javascriptのコードがES6の書き方をしているのもあれば、 ES5?の書き方をしているもあるのは、そのせい。

思ったこと

最近では、Arduinoなどを使えば、ハードウェアに飛び出していけるものが簡単に作れるようになった。 しかし、それを使うには、プログラミングをする環境をそろえたり、そこに出てくる問題を解決したりしなければいけない。 それがプログラミングのおいしいところにたどり着くまでの障害になっていることもよくある。

そこで、使い方によっては、繰り返し処理(for,while)や条件分岐(if,else)などの深いところまで 使うことができる、ScratchXをベースとして、手軽にプログラミングを楽しみたい。楽しませたいのである。 特にハードウェアに結果が出力されるものは、個人的におもしろいと感じるので、Digisparkを使っている。

最後に、node.jsやelectronに詳しい方は、ぜひ、Windowsバージョンのバイナリ化に挑戦してみてください! 成功しましたら、ご連絡いただけると大変うれしいです。

ダ○ソーで売っていたLEDランプの外装をランプカバーにすると、かわいい。

参考にしたサイト