Yura YuLife

ITエンジニアの覚え書き。

Misskey Play (AiScript) で文字列をシャッフルする

シャッフルする関数みたいなのは見当たらなかったので、ナイーブに実装しました。

let string = "あいうえお"
let length = string.len

let chars = []
for (let i, length) {
  chars.push(string.pick(i))
}

for (let i, length) {
  let a = (length - i - 1)
  let b = Math:rnd(0 (length - i - 1))
  let t = chars[a]
  chars[a] = chars[b]
  chars[b] = t
}

let result = chars.join("")  // "うおえあい" みたいになる

参考サイト

qiita.com

programming-place.net

Python の attrs で validation をかける

以前 Qrunch に投稿してた記事を持ってきました。


Python の attrs が便利すぎて、データ保持用のクラスを作る時なんかは専らコレばっかり使っています。

そんな attrs で入力されるデータに validation をかける方法です。

attrs で入力データをチェック

例えば Pose というクラスに対して、位置を表す position は長さ 3 の配列、向きを表す orientation は長さ 4 の配列(クォータニオン) であることをチェックする場合は以下のように書くことができます。

from attr import attrs, attrib


@attrs
class Pose:
    position = attrib()
    orientation = attrib()

    @position.validator
    def check_position(self, attribute, value):
        if len(value) != 3:
            raise ValueError("position must be a list with size=3")

    @orientation.validator
    def check_orientation(self, attribute, value):
        if len(value) != 4:
            raise ValueError("orientation must be a list with size=4")

正しい値を代入した場合

>>> Pose(position=[0, 1, 2], orientation=[0, 0, 0, 1])
Pose(position=[0, 1, 2], orientation=[0, 0, 0, 1])

不正な値を代入した場合

>>> Pose(position=[0, 1], orientation=[0, 0, 0, 0, 1])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<attrs generated init d25cdc317f9cca07dcc37d3210f62862e6055553>", line 5, in __init__
  File "<stdin>", line 8, in check_position
ValueError: position must be a list with size=3

普通の class だと __init__ が肥大化したりしがちですが、これだとスッキリ書けますね!

関連サイト

周波数からC3やF4などのノート名に変換する

以前 Qrunch に投稿してた記事を持ってきました。


Python 3 で周波数からノート名に変換

A4 は 440Hz、 C3 は 130.8Hz のようにノート毎に周波数が決まっていますが、周波数からノートに変換するコードを Python 3 で書いてみました。

import math

SCALE_LIST = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
C0_FREQUENCY = 16.35

def frequency_to_note(freq):
    n = round(math.log2(freq / C0_FREQUENCY) * 12)
    return SCALE_LIST[n % 12] + str(n // 12)

実行するとこんな感じ。ノートの音程ぴったりじゃない場合は四捨五入で丸めています。

>>> frequency_to_note(55)
'A1'
>>> frequency_to_note(440)
'A4'
>>> frequency_to_note(130)
'C3'
>>> frequency_to_note(185)
'F#3'

参考URL

TRIX - ゴクロウサンの歌詞

ずっと聞き取れないところがあるなーと思っていたんだけど、イヤホンを変えてみたらだいぶ聞き取りやすくなったのでメモメモ。


毎朝満員電車に揺られてゴクロウサン あぁ大変だ
会社で家庭で小言を言われてゴクロウサン もうたくさんです


毎朝満員電車に揺られてゴクロウサン あぁ大変だ
会社で家庭で小言を言われてゴクロウサン もうたくさんです
朝から早起き育児にパートにゴクロウサン あぁ大変だ
毎日炊事に掃除に洗濯ゴクロウサン もうたくさんです


朝から晩まで営業スマイルゴクロウサン あぁ大変だ
景気が全く回復しないや困ったなぁ もうたくさんです
毎朝満員電車に揺られてゴクロウサン あぁ大変だ
会社で家庭で小言を言われてゴクロウサン もうたくさんです


フュージョンバンドだし歌詞サイトには載ってないしで、ずっとモヤモヤしてたんだけどコレでスッキリ!

Pythonでファイルに書き出さずにzip圧縮

この記事では、Python でファイルを生成せずに zip 圧縮したデータを生成する方法を紹介します。

zip 圧縮したデータを Python 内からアップロードしたい場合なんかに、ファイルに書き出して後から削除する手間を避けたかったり、FaaS などそもそも ReadOnly のファイルシステムで使ったりすることを想定しています。

動作環境

動かし方

Python の zipfile ライブラリと、 io.BytesIO を用いて実現します。

# zip 圧縮したデータをファイルに書き出す代わりに BytesIO のストリームを作成
zip_stream = io.BytesIO()

# ファイルに書き出す代わりに zip_stream に zip 圧縮したデータを出力
with zipfile.ZipFile(zip_stream, 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
    # foo.txt というファイル名で abcdef という文字列をzipファイルに追加
    new_zip.writestr("foo.txt", "abcdef")
    # ローカルの foo.png を zip ファイルに追加
    new_zip.write("foo.png")

# 生成された zip 圧縮データを出力
# 実際には print の代わりに HTTP の POST とか、S3 へのアップロードとかに使うイメージ
print(zip_stream.getvalue())

参考URL