nikkie-ftnextの日記

イベントレポートや読書メモを発信

#アイの歌声を聴かせて はいいぞ 🤖🎤🎼

はじめに

わたしが幸せにしてあげる!
めっちゃいいですよね、nikkieです。

残タスクもありますが、PyCon JP 2021の会期が終わって解き放たれています。
今回は最近イチオシのアニメ映画を紹介します。

目次

アイの歌声を聴かせて

10/29公開、『イブの時間』『サカサマのパテマ』の吉浦監督の作品。

ポンコツ“AI”とクラスメイトが織りなす、爽やかな友情と絆に包まれたエンターテインメントフィルムが誕生! 1

ポンコツAI シオンの秘密ってなんだろう? むしろMLOps的には、ポンコツAIなのにリリースした意思決定やパイプラインの実装が、私、気になります!」と思いながら観に行ったところ

めっちゃいいぞぉぉおおおお😭😭😭

吉浦監督の作品は初めて見たのですが、ぶっ刺さりました。

すべてを知った上で見ると、全部辻褄が合って鳥肌がヤバいんです!!

(シオンを見て、私は私を幸せにしようとしているんだろうかとも思ったり・・)

気になった方はぜひお早めに劇場でご覧ください!

「秘密はね、最後に明かされるんだよ」

(※ネタバらすわけではありません)

2回めを鑑賞した後の帰り道、脳内で結びついた別の話があります。

それが、『世界は贈与でできている』の4章「16時の徘徊」です。

  • 認知症の母親が毎日16時に外へ出ていってしまう(徘徊)
  • 息子の男性が外出を止めようとすると、暴力をふるわれる
  • ベテラン介護職員に相談。職員は母親の兄にヒアリング
  • 職員が母親に「今日は息子さん、幼稚園のお泊り会で帰ってきませんよ」と伝えると外へ出ていかなくなった

母親は「徘徊」という行為ではなく、「息子を迎えに行く」という物語の中を生きていたのでした。

息子からは母親の行動が不合理と見えていました。
介護職員が不合理の中の合理性に気づきます。
(『世界は贈与でできている』ではここから「贈与」について論じられます2

不合理と見えていたものが合理的として捉え直される構造、これが「『アイの歌声を聴かせて』でも共通している!」と思ったわけです。

サトミやクラスメイト、観客の私たちにとってシオンの行動は不合理です。
だから「ポンコツ」という評価を下すわけです(予告でも仕向けられています)。
ところが、最後に明かされる秘密、それによってシオンの行動の合理性に気づきます。
「これで全て合点がいく」私は鳥肌が立ちました。

終わりに

このブログとしてはおそらく初のアニメガタリでした。
『アイの歌声を聴かせて』、これはほんとにもうすごいので、しばらく劇場に足繁く通うことになりそうです。
会期が終わったタイミングで思いっきりハマれる作品に出会えたのは僥倖ですね。

気になった方はぜひ、劇場へ!!

LT登壇報告:2021年の夏も、予定していた全公演を駆け抜けました!🎤⚡️

f:id:nikkie-ftnext:20200914224142j:plain

はじめに

ういっすういっすういっすー!✌️nikkieです。
PyCon JP 2021が一段落し、アウトプットに少しずつ時間が回せるようになってきました。

昨年の夏は、各地のPyConでトークをしたのですが、

実は今年の夏(9月)も国内のいくつかの勉強会でLTをしました。
この記事で手短にまとめます。

目次

経緯:私のアツいPyCon JP 2021広告塔活動

LTラッシュはPyCon JP 2021と関係します。

今年のPyCon JPは9/20までの早期購入特典でピザが付きました。
チケット販売開始は8/28(土)です。
せっかくのパーティーフード付きの企画ですが、締切まで1ヶ月なく、告知期間はタイトでした。
早期購入特典の期間の後はチケットの金額は変えない方針だったため、「早期購入特典付きの今が価値最大のチケットをなんとしても買ってほしい」と勉強会のLTを使ってアピールすることにしました。

LTする上で自分に課した縛りは以下2つです。

  • チケットのお知らせが主題ではない(他に題材があり、CMとしてチケットに触れる)
  • LTの再演はしない=全て新ネタPythonコミュニティの勉強会を回るので、すでに聞いたLTをまた聞くという形にはしたくない)

結果、4つの勉強会でLTしました。
なお、LTのネタは、ちょうど実装していたconnpass操作自動化(Helium)1から切り出しました。

@dataclass のような、 () を付けても付けなくてもいいデコレータはどう作る? (8/28 Python駿河 勉強会 #28)

Python駿河 勉強会 #28 ~真夏のLT大会~ - connpass

LTしてみて、デコレータの仕組みを口頭で説明するのは工夫が必要という学びを得ました。

また、嬉しいフィードバックをいただきました。ありがとうございます!

この夏くらいからドキュメントより深いところが知りたくて、ライブラリの実装やテストコードを見始めたのですが、優秀なPython使いが書いたコードには発見がいろいろあり、めちゃくちゃ楽しいです。
今後もいろいろなライブラリに潜っていく所存です!

ラクス 情報収集ハック 超LT会 - vol.4 (9/1)

情報収集ハック 超LT会 - vol.4【やっていき・初心者も大歓迎】 - connpass

3分で申告し、1分の超LTを2本やりました。
2回宣伝できると思ったからです(単純接触効果狙い 笑)

カンファレンスに行こう!

ヨーダからのメルマガ

この超LT2本ですが、タイトルは氷菓』シリーズを意識して命名できた!ので、個人的にポイント高いです。

※「試し読みをする」から目次が確認できます

週に数回connpassのイベントを作るPyCon JPスタッフは、Heliumを使って自動化しました (9/11 pycharity)

レポートは以下の記事をどうぞ
イベントレポート & LT報告 | Python Charity Talks in Japan 2021.09 を楽しみました #pycharity - nikkie-ftnextの日記

Helium - Cool Python! (9/17 はんなりPython #43)

【オンライン】はんなりPython #43 夏の終わりのLT会 - connpass

ここでいただいたフィードバック(AWS Lambdaでもブラウザ操作自動化スクリプト実行できますか?ー私がやるならdocker runですね)は、mogirin(脚注1のリンク先参照)につながっています。

総括

はんなりPythonでのLTは当日の終業後になんとか完成させたため生きた心地がしませんでしたが、それでも4本やりきりました!🙌
わたし、頑張りましたー

これらのLTに通底しているHeliumのヘルパーについては、他にも役立つ人がいそうなので、パッケージ化予定です。
Pythonの知識が付いてきて、かっこよく書けるようになり、最近はPython書くのがますます楽しいですね。

LTの機会を提供していただいた、上記の勉強会の運営の皆さま、ご清聴いただいた全てのの参加者の皆さまにお礼申し上げます。
ありがとうございました!

私のアツいスタッフ活動!技術で(も)支えたPyCon JP 2021 #pyconjp

はじめに

ういっすういっすういっすー!✌️nikkieです。
10/15, 16のPyCon JP 2021、お疲れさまでした!

今年は座長としてがっつり関わりましたが、実は裏でけっこう手を動かしてコードも書いていました。
アウトプットのリハビリも兼ねて、PyCon JP 2021を支えた技術面のアウトプットをざっと紹介します。

目次

プロポーザルレビューアプリ(Django

f:id:nikkie-ftnext:20211020103954p:plain
レビューモードです(データはfactory_boyによるダミーデータです)

2020に引き続き、プロポーザルをレビューするためのアプリをDjangoで作りました。
2021での技術的なアップデートは以下です。

項目 2020 2021
DB(postgres) ローカルマシン内 Dockerイメージ
Sign in with Slack django-slack-oauth1 django-allauth1
プロポーザルデータ投入 JSONファイルをgit commitしてherokuにだけpush django-rest-frameworkでエンドポイント作成
テストデータ - factory_boyでランダムに作成

django-allauthは罠が多く、いろんなところでハマったのですが、なんとかSign in with Slackを実装しました(詳細はまたの機会に)。

django-rest-frameworkも初めて使いましたが、akiyokoさんの『現場で使える Django REST Framework の教科書』にめちゃくちゃ助けられました。

ちなみに実装時期は7月で、金曜ロードショー細田守祭を流しながら毎週金曜の夜に実装してました。
おおかみこどもを聴きながら、DRFの教科書を真似てエンドポイントを実装できた瞬間はすごい気持ちよかった1ですし、バケモノの子を聴きながら、Sign in with Slackでハマった箇所に対処していました。

伸びしろはテストコードですね。
Djangoのテストに書き慣れていないから、テストを書こうとすると遅くなり、限られた実装時間の中ではテストを書かないことを2年とも選びました2
この夏に出たc-bataさんの『実践Django』はテスト駆動のアプローチなので、真似てみるのはいい練習になりそうです。

connpassのイベント作成操作自動化(helium)

9月の #pycharity (や他の勉強会でのLT)で聞かれた方もいるかもしれませんが、繰り返しconnpassでイベントを作るので、ブラウザ操作自動化ライブラリ helium を使って自動化しました。

PyCon JPスタッフのmtgは毎回connpassを使っており、出席者の確認やカレンダー連携、外からも活動の様子が分かると利点も大きいと感じています。
一方、「毎週connpassイベントを作るのが面倒」というスタッフの声もありました。
そこでイベント作成はnikkieに集約し、自動化スクリプトで作っています。

この自動化で得たノウハウはmogirin(後述)にも活きています。

次の技術的な挑戦としては、PyCon JP SlackにBotないしはカスタムコマンドとして導入し、スタッフ誰でも簡単にconnpassイベントを作れるようにすることですね。

ウェブサイトのタイムテーブル用に、sessionize APIの返り値をパース

2020同様3、sessionizeからトークのデータを取得し、CSVに整形するプログラムを実装しました。

今年はsessionizeのAllというエンドポイントを使ったのですが、返り値がやんちゃで、実装はけっこう大変でした(もっと単純な返り値が返るAPIの設計を強くお願いしたいです🙏)。
スピーカー、ルーム、プロポーザルの項目(前提知識など)のIDと値を対応させるdictをいくつも書くことになり、「coreモジュールが大きすぎる(返り値のパースの仕方を知りすぎている)」と頭を悩ませながら実装していました。

# coreモジュールが知りすぎていると感じた一部
def create_speaker_id_map(speaker_data):
    return {d["id"]: Speaker(d["fullName"], d["bio"]) for d in speaker_data}

speaker_id_map = create_speaker_id_map(data["speakers"])
# スピーカー作成処理(Before)
# [speaker_id_map[speaker_id] for speaker_id in session["speakers"]]

最終的にはファクトリ(作り方を知っているモノくらいの意味です)のクラスを用意し、それらにスピーカーなどを作らせることで、大量のdictはcoreから各ファクトリの属性に移すことができ、個人的にはスッキリした実装にできたと思っています。

# coreモジュールはSpeakerFactoryを作ってあとはお任せ
speaker_factory = SpeakerFactory.from_(data["speakers"])
# スピーカー作成処理(After)
# [speaker_factory.create(speaker_id) for speaker_id in session["speakers"]]

Webサイトのビルドでは0.1.1を使っているのですが、0.2.0ではCSVに出力するフィールドを指定できるようにしました。
これにより、例えば、タイトル、スピーカー名、ルームのようにフィールドを絞ってCSVを作れるようになりました!

$ python -m pyconjp_domains timetable talk_titles.csv --fields id title
$ python -m pyconjp_domains timetable interval_slide.csv \
    --fields day 'slot_number AS no' room title 'speaker_names AS name' id

(動作させるには、環境変数 ENDPOINT_ID の指定が必要です。スタッフに共有しています)

0.2.0により、似たようなスクリプトを何個も書かずに済んでとても便利でした。
Webサイトのタイムテーブル以外では、Discordのテキストチャンネル名や幕間に表示したスライドにも使っています。

Discordでの受付Bot:mogirin

PyCon JP 2021のオンライン会場、Discordには、受付(チケットのもぎり)をするBot、mogirinがいました。
こちらの実装にも関わっています。

  • 参加者はconnpassの受付票で受付番号を確認(1234567のような7桁の数字)
  • Discordの受付チャンネルで @mogirin 1234567 と呼び出す
  • mogirinは受付番号一覧のスプレッドシートを参照し、まだ受付されていない受付番号であれば、シートを受付済みに更新し、会場が見えるようにattendeeのロールを付与する

mogirin自体は他のスタッフが迅速に動作検証してくださった曳光弾コードがあったので、私はそのコードをherokuで動くようにエンジニアリングしただけです。

一方、mogirinが参照する受付番号一覧スプレッドシートの更新は、技術的に背伸びが必要なストレッチゴールでした。

  • 参加者の受付番号はconnpassから参加者情報のCSVとしてダウンロード(ブラウザ操作自動化)
  • CSVの中から、差分をスプレッドシートに追記
  • これを定期的に動かして受付番号一覧スプレッドシートを更新する

結論を言えば、Dockerイメージにして、CircleCIでスケジュール実行しています。

https://hub.docker.com/r/pyconjp/mogirin-db-synchronizer

connpassから参加者情報CSVをダウンロードする部分はheliumを使いました。
Firefoxが立ち上がるDockerイメージにheliumをインストールして動かしています。
ブラウザの表示言語の設定やDockerの中で立ち上がったブラウザのデバッグなど、けっこう大変だったのですが、これはまたの機会にアウトプットしたいですね。
なお、このあたりは10月頭にワクチン副反応と闘いながら実装していました。

ブラウザ自動操作でconnpassから参加者情報CSVをダウンロードというのは、どれくらいの頻度でやっていいのか手探りで悩ましかったです(ログインを伴うので、robots.txtは当てにできないと考えていました)。
会期直前は1時間おきに動かしていたのですが、例えば、10:30に動いた後、10:40にチケットを買った方は「すぐ受付したい」はずですが、自動化した範囲では11:30まで待ってもらうしかありません。
「運用でカバー」というやつで、待っている参加者に気づいたらスタッフにスプレッドシートを更新してもらい、回していました4
(このあたりはconnpassという外部に参加者データを保持している制約と考えています。他のPyConのWebサイトみたいに、ウェブサイトでチケットの決済までできると、内部のデータベースをmogirinから参照することで、待ち時間やスタッフの作業なく受付できたはずです。もしくは、connpassのAPI公開が待たれます🙏)

おまけ:30日後に始まる #pyconjp

観測範囲ではワニに続き47歳さんが話題ですが、#pycharityのhayaoさんの発表「日常生活で使うPython5に影響を受け、カウントダウンしました。
これをやることで @pyconjapan のフォロワーも増えるかなと思っていたのですが、この企画がフォロワーを集める要因には、単に続ける以外の要素が大きいということですね。
漫画がなかったからか・・(←違う)

# お祭りの後
$ python -m xdays_journey
-5 days, 0:00:00

終わりに

PyCon JP 2020では、「Code for PyCon JP」という発表(15分トーク)をしました。
2021はブラウザ操作中心に自動化スクリプトを追加、mogirinが参照するスプレッドシートの更新処理の実装と、振り返ってみるとめちゃくちゃ(2020の倍くらい?)手を動かしてましたね。
1スタッフとしてできることはかなり広がったと思いますし(10x Staff?)、手を動かす中で身についたと感じるトピックもいくつもあります。

f:id:nikkie-ftnext:20211020104141p:plain 技術で(も)支えたおかげで、毎日Contributionは継続しています!(2020/05/02から始めて500日突破しました)

今後の方向性としては、どれくらいの配分にするかは考慮中ですが、技術面メイン(DX担当?)で引き続きPyCon JPスタッフには関わる予定です。
目下のところは、mogirinのDockerイメージを利用して、connpass操作を代行するSlack Appを作ってみたいなと思います。

今回のアウトプットについて「他のカンファレンス・勉強会で使いたいのですが、ここはどうやったらいいですか?」といった質問・相談は大歓迎です。
リポジトリのIssueやTwitter @ftnext までお気軽にどうぞ!
(技術的な伸びしろがあれば、Pull requestで提案していただくのも嬉しいです)

私の場合は、Pythonを書いてスタッフの作業を進めたいシーンがいくつもあったので実装しています。
これくらい作れないとPyCon JPのスタッフはできないということではありません
「やりかたは自由」6ですので、スタッフに興味ある方は気楽に構えて飛び込んでみてください!


  1. Django 3.0向けに自分でパッチ当てたversionです。Slack側の仕様が変わったようで、もう動かないのではないかと思っています https://github.com/ftnext/django-slack-oauth

  2. Django Congress JP 2021前日のホテルでの思い出です

  3. 2020年積み残し解消:django-allauthを使ったソーシャルアカウント(GitHub・Slack)連携、素振りの記 - nikkie-ftnextの日記 での素振りが活きました!

  4. テストを書かないというジャッジをするのは構いません。でもそれは、スタートアップだからでもスピード優先だからでもない。自分達が未熟だからで、そこには向き合うべきだと考えます。 「スタートアップだからテストを書かない」は正しいか - An Epicurean より(そのとおりで、今年一番しびれたエントリです)

  5. セッションデータはsessionizeというサービスで管理しています。API経由でセッションデータを取得することができるので、ビルド時にセッションデータを取得し、フロントエンド側で利用しやすいように整形しています。 PyCon JP Blog: PyCon JP 2020 システムチーム振り返り【技術編】より

  6. 会期中にふと、mogirinが参照したスプレッドシートに受付番号がなかったことを契機に、スプレッドシート更新を起動するようにできたことに気づきました

  7. Python for Everyday - Speaker Deck 、ちょっとした工夫の共有、とてもよかったです。なお、#pycharityの資料は https://pyconjp.connpass.com/event/218154/presentation/ にまとまっています

  8. https://pyconjp.atlassian.net/wiki/spaces/pyconjp/pages/1019183576#%E3%82%84%E3%82%8A%E3%81%8B%E3%81%9F%E3%81%AF%E8%87%AA%E7%94%B1 参照。「よりよいやり方」がコードを書いて楽をすることだと思ったので書きました(タイダデスネー)

イベントレポート & LT報告 | Python Charity Talks in Japan 2021.09 を楽しみました #pycharity

はじめに

ういっすういっすういっすー!✌️nikkieです。
久しぶりのブログ投稿になりました(LTやPyCon JP 2021スタッフ活動を精力的にやっています)。
9/11に開催された #pycharity についてレポートします。

目次

勉強会の概要

Python Charity Talks in Japan 2021.09 - connpass

このイベントはPython Software Foundation(略称: PSF)に、100万円程度の寄付をすることを目標にした、日本国内のPythonユーザに向けたものです。
それに加え、今回のイベントは、Python Boot Campをきっかけに、日本全国で立ち上がったPython コミュニティに焦点を当てます。日本全国のコミュニティをオンラインで繋げてPythonの環の広がりを感じてください。

2020.07、2021.02に続いて3回目。
今回は各地のコミュニティにフォーカスして

  • 飛騨高山
  • 静岡
  • 山梨
  • 広島

のコミュニティから発表がありました。
各コミュニティの中で発表者をリレーしていきます(10-15分くらいの発表複数本)

アーカイブはこちら:

おそらく資料もあとでconnpassページに上がるでしょう!

今回の寄付総額👏👏👏

参加しての感想(つらつらと)

ラジオとして耳だけ入っていました。
LTの準備を仕上げたり、気になっていた調べ物を進めたりしながら聞いていました。

気になるキーワードがいくつか拾えました。
あとでスライドでガッツリ見ようと思っています(スライド無ければアーカイブを見ます)。

ざっくりすぎるきらいもありますが、以下のようにコミュニティごとに色合いが出ていたなと思います。

  • 飛騨高山:AI(画像、自然言語
  • 静岡:AWS(Step Function、サーバレス)、AI(不均衡データ)
  • 山梨:Web
  • 広島:ハード

各地のおいしいもの情報🤤

休憩時間のトークは、グルメ情報満載なのがとりわけ楽しめました。
飛騨高山と山梨はきっかけとなったPython Boot CampでTAをしており、「あのとき食べたあれは美味しかったなあ」としみじみと思い出していました。

飛騨高山

山梨

今となっては山梨はゆるキャン△が浮かびます(静岡にも当てはまりますが)。
「みのぶまんじゅう」も紹介されましたね。

TAした #pycamp を思い出し、COVID-19 で勉強会事情は一変しましたが、各地のコミュニティは続いているんだなあと独りで感じ入っていた次第です。

クイズも盛り上がりましたね

訳あって再出発した Twitterアカウント pyconjapan があまり認知されていなかったのはちょっと焦りました。
みなさん、クイズに出ますから、フォローお願いしますねー📣

LT報告:週に数回connpassのイベントを作るPyCon JPスタッフは、Heliumを使って自動化しました

PyCon JP スタッフはmtgにconnpassイベントを立てており、以下のブラウザ操作をします。

  • スタッフ共通アカウントでconnpassにログイン(イベント公開をpyconjapan Twitterに流すため)
  • 既存のイベントをコピー

「これを自動化するスクリプトを、Heliumというライブラリを使って書きました」とデモも交えて共有しました。

もともと python-as-pyconjp-staff リポジトリ以下にHeliumを使ったスクリプトはあったのですが、LTするなら見た目にこだわろうと、再利用できる形式を念頭に以下のリポジトリで開発しています。

LTに間に合った分はこちら、じゃーん!!

@using_firefox
@logged_in
def show_copy_popup(url):
    copy_existing_event(url, human_confirms=True)

共通処理をデコレータとして実装したことで関心のあるブラウザ操作の実装だけに集中でき、個人的にいい感じな気がしています!

「週に数回connpassでイベントを作る」というペルソナって私ぐらいでほとんどいないんじゃないかなと思っていたのですが、各地のコミュニティの方や(PyCon JPと頻度が近そうな)「はんなりPython」の運営の方から「気になる」という反応がZoomチャットであって、とても嬉しかったです😃

上記のリポジトリを使って、バグや使いづらいところなど気づいたことあればIssueでお知らせください。
私の普段遣いがFirefoxなのでChromeまわりは動作確認が漏れやすく、「使ったら動かなかった」はあってもおかしくないかなと思います。
試した方の声も聞きつつ、一緒にカイゼンしていければと思います。

終わりに

がっつり参加とは別のスタイルでしたが、技術的な気付きやグルメ情報など、各地のコミュニティの色合いが出て、楽しい時間でした。

9月の pycharity を皮切りに、10月 pyconjp、11月 pycon_shizu、2022年1月 pyconkとPythonイベント目白押しです。
PyCon JP 2021チケットは、9/20(月)まで早期購入特典対象ですので、よろしくお願いします!🎫🙏🐦🍕
PyCon JP 2021 カンファレンス - connpass

発表者、運営スタッフ、参加者の皆さま、半日ありがとうございました!

f:id:nikkie-ftnext:20210911220244p:plain

dataclassを使って、Pythonで値オブジェクトを実装する

はじめに

アタイも挑戦したい、管理人みたいに1
ジョゼと虎と魚たち』めっちゃいいですよね? nikkieです。

タイトルの値オブジェクトとは、値を扱うための専用クラス2です。
これを「Python@dataclasses.dataclassを使って書いたらどうなるのか」手を動かしました。
この記事は、分かったことの備忘録です。

おことわり:「今の自分が書いたらこんな感じかな」というのをまとめました。
技術的な誤りや伸びしろにお気づきの際は、コメントやTwitter @ftnext までお知らせいただけると大変ありがたいです。

目次

「アタイ」ヒロインならぬ、「アタイ」オブジェクトについてです

経緯

先日TECH StreetさんのPythonエンジニア勉強会Pythonのobjectについて10分話しました。

紹介した例は、値オブジェクトやファーストクラスコレクションを意識して実装しています。
準備の中で『現場で役立つシステム設計の原則』を参照したところ、「意識しているけど、値オブジェクトやファーストクラスコレクションにはできていないなー」と、目の前に広がる圧倒的な伸びしろを感じました。
そこで、LTとは別に実装を突き詰める機会を設けました。
今回は、値オブジェクト編のアウトプットです。

値オブジェクトとは

※『現場で役立つシステム設計の原則』の1章を参考にしています

値オブジェクトの実装は「基本データ型のインスタンス変数を1つか2つ持つだけの小さなクラス」3です。
基本データ型をインスタンス変数としてラップして、独自の型(クラス)を作ると捉えています。
値オブジェクトを使う目的は、業務のニーズに合っていない基本データ型の代わりに、業務のニーズに合わせた値の範囲を使うためと理解しました。

値オブジェクトの利点はいくつも紹介されています。
イチオシはこちら、関数の引数がめちゃくちゃ分かりやすくなりますね!

def amount(unit_price: Money, quantity: Quantity) -> Money:
    if quantity.is_discountable():
        return discount(unit_price, quantity)
    return unit_price.multiply(quantity.value)

1章の「『型』を使ってコードを分かりやすく安全にする」のJavaのコードをPythonで書き直してみました。
第1引数がMoney型、第2引数がQuantity型という型ヒントが分かりやすいと思います。

値オブジェクトの実装要件

  • 基本データ型を属性として1つか2つ持つ
    • 👉 簡単な例で練習したいので、1つにします
  • 不変
    • 👉 @dataclass.dataclass()frozen引数にTrueを指定します
    • ドキュメントによると「frozen: 真 (デフォルト値は False) の場合、フィールドへの代入は例外を生成します。 これにより読み出し専用の凍結されたインスタンスを模倣します。」4
  • 完全コンストラク
    • 「オブジェクトの生成時に、オブジェクトの状態を完全に設定してしまう」5
    • コンストラクタで、業務のニーズに合わせた値の範囲か検証します
    • 👉 @dataclass.dataclass()では__init__が自動で作られますが、完全コンストラクタにするために自分で書くことにしました

値オブジェクトの例:競走馬名

TECH StreetさんでのLTの題材にした競走馬名を表すクラスを例に選びました。

※競走馬の名前を値オブジェクトにするというのは、業務アプリケーションからかけ離れていると思います。
今回の取り組みは「値オブジェクトの実装方法」を見つける練習なので、これでいきます🐴

日本における馬名登録のルール6

  • カタカナ9文字以内7
  • 「ヰ」・「ヱ」は使用できない
  • 2文字以上9文字以内

馬の名は。値オブジェクト RaceHorseName 🐴

完成したコード

from __future__ import annotations

import re
from collections.abc import Iterable
from dataclasses import dataclass
from typing import ClassVar


@dataclass(frozen=True)
class RaceHorseName:
    """カタカナの馬名を表すクラス"""

    value: str
    MIN_LENGTH: ClassVar[int] = 2
    MAX_LENGTH: ClassVar[int] = 9
    INVALID_CHARACTERS: ClassVar[Iterable[str]] = ("ヰ", "ヱ")

    def __init__(self, value: str):
        # 完全コンストラクタの実装例
        length = len(value)
        if length < self.MIN_LENGTH:
            raise ValueError(f"不正: {self.MIN_LENGTH} 文字未満")
        if length > self.MAX_LENGTH:
            raise ValueError(f"不正: {self.MAX_LENGTH} 文字超")
        if not self.is_katakana_only(value):
            raise ValueError("不正: カタカナではない文字")
        if self.does_include_invalid_characters(value):
            raise ValueError(f"不正: 使用禁止文字 {self.INVALID_CHARACTERS} を含む")
        object.__setattr__(self, "value", value)

    @staticmethod
    def is_katakana_only(string: str) -> bool:
        return bool(re.fullmatch(r"[\u30A0-\u30FF]+", string))

    @classmethod
    def does_include_invalid_characters(cls, string: str) -> bool:
        return any(c in string for c in cls.INVALID_CHARACTERS)

不変なことの確認

>>> rice = RaceHorseName("ライスシャワー")
>>> rice.value = "ミホノブルボン"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'value'

frozen=Trueにより、ラップした値を変更できません

frozen=True を dataclass() デコレータに渡すことで、不変性の模倣はできます。 このケースでは、データクラスは __setattr__() メソッドと __delattr__() メソッドをクラスに追加します。 これらのメソッドは起動すると FrozenInstanceError を送出します。8

完全コンストラクタであることの確認

  • 2文字未満:ラ
  • 9文字超:トッテモライスシャワー
  • カタカナではない文字を含む:ライスshower
  • 使えないカタカナ:ラヰスシャワー

いずれもValueErrorが送出されます

>>> RaceHorseName("らイスシャワー")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 不正: カタカナではない文字

実装ポイント

frozen=Trueと完全コンストラク

イニシャライザ(__init__)でvalue属性に値を代入する必要があります。
これは以下の書き方をする必要がありました。

object.__setattr__(self, "value", value)

frozen=True を使うとき、実行する上でのわずかな代償があります: __init__() でフィールドを初期化するのに単純に割り当てることはできず、 object.__setattr__() を使わなくてはなりません。9

イニシャライザでself.value = valueと書くと、以下が出てしまいます(frozenにしたのでごもっともなのですが、けっこう焦りました)。

dataclasses.FrozenInstanceError: cannot assign to field 'value'

これは object.__setattr__()10で回避できました。

dataclassのクラス変数

typing.ClassVarを初めて知りました。

クラス変数であることを示す特別な型構築子です。11

フィールドが ClassVar の場合、フィールドとは見なされなくなり、データクラスの機構からは無視されます。12

dataclassのクラス変数の理解があやふやだと分かって、いくつか手を動かしました。
型ヒントをつけなければクラス変数 なんですね。

@dataclass
class C:
    a: int
    b: int = 0
    d = "Class var"
>>> c = C(108)
>>> c
C(a=108, b=0)
>>> c.d
'Class var'
>>> C.d
'Class var'

クラス変数dに型ヒントを付けるときにClassVarを使うという理解です。
これで型チェッカーの支援を受けられるとのこと13
クラス変数の扱いをさらに深めたければ、@dataclasses.dataclassの実装を見ることになりそうです。

脱線:すべてカタカナのチェック

最後に値オブジェクトとは別の話題を。
文字列がすべてカタカナかの判定は https://note.nkmk.me/python-re-regex-character-type/#_7 を参考にしています。

Future works

今回書いたコードは暫定解(よりよい方法で棄却されうる)と思っているので、今後試したい事項を挙げておきます:

終わりに

値オブジェクト、dataclassfrozen=Trueを知っていた14ので、ぱぱっと実装できるかと思いきや、意外と時間がかかりました。
完全コンストラクタの実装で、値の検証に使う変数やメソッドをクラスに持たせていき、「競走馬名をクラスで表現できた!」と満足しています😃

次は、ファーストクラスコレクション編です!(執筆時期は未定です)


  1. アタイつながりで持ってきました😝 https://youtu.be/P5LLhoKfI1E?t=36

  2. 増田 亨『現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法』 (Japanese Edition) 1章 (Kindle の位置No.687). Kindle 版.

  3. 『現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法』 (Kindle の位置No.689-690)

  4. https://docs.python.org/ja/3/library/dataclasses.html#dataclasses.dataclass

  5. 『現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法』 (Kindle の位置No.735-736)

  6. 馬名登録のルール、けっこう面白かったです。「オレハマッテルゼ」なんてあるんですね🤣 類似しているとNGだそうですが、「チョウカイテイオー」は却下で、「ナイキシャトル」は採用🤔

  7. 「アルファベットの馬名と合わせて登録する」そうですが、今回は考えません。だって、ウマ娘、カタカナの印象が強いじゃないですか!

  8. https://docs.python.org/ja/3/library/dataclasses.html#frozen-instances

  9. https://docs.python.org/ja/3/library/dataclasses.html#frozen-instances

  10. https://docs.python.org/ja/3/reference/datamodel.html#object.__setattr__ (URL末尾の__setattr__が太字になってしまいます😢)

  11. https://docs.python.org/ja/3/library/typing.html#typing.ClassVar

  12. https://docs.python.org/ja/3/library/dataclasses.html#class-variables

  13. Here ClassVar is a special class defined by the typing module that indicates to the static type checker that this variable should not be set on instances. ref: https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations

  14. hoboroさんのトークで知りました。詳しくは イベントレポート | オンラインで開催された #pycon_shizu 、私の知らないPythonがいくつもありました! - nikkie-ftnextの日記

自分用 2021年Python関連アウトプット先カレンダー(カンファレンス・技術同人)

f:id:nikkie-ftnext:20210424205310p:plain

はじめに

頑張れば、何かがあるって、信じてる。nikkieです。

昨年の夏は、世界各地のPyConでオンライン登壇しました。

今年の夏も近づいてきて、プロポーザル募集中のカンファレンスもいくつか見かけるようになりました。
自分用のメモとしてPython関連のアウトプット先(カンファレンス中心)をまとめます1

英語・日本語関係なくリストアップしましたが、ここにあるものはごく一部です2
また、この記事をメンテナンスしていくかは未定です3

目次

カンファレンス

PyCon Taiwan 2021(プロポーザル 〜4/26(月))

8/20(金)〜22(日) 開催。リモートスピーカーも歓迎

Django Congress JP 2021(プロポーザル 〜5/12(水))

7/3(土) 長野で開催(オンライン参加もあり)

Euro Python 2021(プロポーザル 4/26(月)〜)

7/26(月)〜8/1(日) オンライン開催

Speaker Mentorship Programなるものがあるようです(申込 〜4/26)

In the EuroPython community, we emphasize the importance of diversity and inclusion. We also encourage and support potential first-time speakers. To help us achieve the goal, we will have the Speaker Mentorship program for EuroPython 2021.

PyCon APAC 2021(プロポーザル 〜8/26(木))

11/18(木)〜11/23(火) 開催

技術同人誌

技書博 #5(サークル申込 〜4/26(月))

6/19(土) 会場開催

技術書典 #11(サークル申込 〜5/23(日))

7/10(土)から16日間
7/11(日)は会場開催

終わりに

2020年登壇の夏で得た知見を PyCon mini Hiroshima 2020 でアウトプットしたところ、

嬉しいフィードバックをいただきました!

今年は抱えているものが多いので、カンファレンスで1回でも登壇することがチャレンジングだと認識しています。
ただ、小さいアウトプットをブログ記事に積み重ねてネタは蓄積できそうなので、2022以降に向けて力を蓄える方針でやっていこうかなと思っています。


  1. PyCon JP 2021 座長としての活動もあり、昨年と同様の登壇量は現実的でないと思っています。もしかするとこの記事自体が代償行動なのかもしれません

  2. すべてを網羅したい方には https://www.python.org/events/python-events がPyConを洗い出す手がかりになると思います

  3. pyhack Slack の #pycon-overseas に情報が集まるのでオススメです。ref: https://ftnext.github.io/2020_slides/pyconhiro_Oct_connect_global/slide.html#/7/1

Pythonで備える2021春アニメ

f:id:nikkie-ftnext:20210407214953p:plain

はじめに

四月と言ったら「君の嘘」。nikkieです。
気づけば桜🌸が咲き(そして散り)、アニメファンとしてはウキウキの新クールです。

クールの頭には、アニメイトタイムズさんの一覧でざっと眺め、「0話切り」をしています。
今回も眺めていたところ、「パースして手元で見て、放送開始日順に並び替えられるのでは?」と思い付き、Pythonでやってみました1

目次

動作環境

HTMLのパースには以下を使います:

beautifulsoup4    4.9.3

なお、対象のHTMLはブラウザの機能でダウンロードして、パースの実装を試行錯誤しています。
試行錯誤の際にサーバに不要なリクエストが飛ぶのは望まないので、ローカルにダウンロードしました。

Pythonで0話切り

対象のHTML

開発者ツールで覗くと、sectionタグとasideタグによる2カラム構成です。
sectionタグの中には、大まかには以下の構造でアニメの情報が詰まっています(今回興味あるところだけ抜き出しました)。

<h2 id="1">アニメ1</h2>
<table>
<tr>
<td>放送<br>スケジュール</td>
<th>2021年4月X日</th>
</tr>
<tr>
...
</tr>
</table>
...

<h2 id="2">アニメ2</h2>
<table>
<tr>
<td>放送<br>スケジュール</td>
<th>2021年4月Y日</th>
</tr>
<tr>
...
</tr>
</table>
...

パース戦略

h2タグとtableタグがセットになって、春クールのアニメ分並んでいます。
h2タグはアニメのタイトル以外にも使われているのですが、アニメのタイトルで使う場合id属性が指定されているという特徴がありました2
この作りを利用して、sectionタグの中身から以下を抜き出しました:

  • id属性が指定されたh2タグ
  • tableタグ

これらの数が一致することを確認しました!
あとは、tableタグの中の「放送スケジュール」の行の日付をdatetime.dateに変換して、放送開始日順に並び替えます。

スクリプトはこちら:

取り組んで知った技術的なトピック

beautifulsoup4でHTMLタグのid属性を扱う

soup.find_all("タグ") で見つかった1個1個のタグ(Tag)について、タグの属性(attribute)3を扱えました!

h2タグについて

  • id属性を持つか判定:has_attr("id")4
  • id属性の値:get_attribute_list("id")5リストで返ります)

refindallfinditerの違い

matches = re.finditer(r"(\d{4})年(\d{1,2})月(\d{1,2})日", schedule)
for m in matches:
    ...

正規表現を使い、放送日を表す文字列 schedule から finditer全てのマッチオブジェクトを取り出します6
今クールに再放送するために、本放送日と合わせて複数の日付が載っているケースがありました(例:ニジガク)。

https://docs.python.org/ja/3/library/re.html#finding-all-adverbs-and-their-positions

パターンの全てのマッチについて、マッチしたテキスト以上の情報が必要なら、文字列ではなく マッチオブジェクト を返す finditer() が便利です。

個々のマッチオブジェクト m

  • m.group(0)正規表現にマッチした文字列全体
  • m.group(1), m.group(2), ...がキャプチャの()に対応

します7

感想

手元でタイトル眺め、気になるものは詳細を確認して、今期の0話切りは終了です。
気になってた漫画タイトルのアニメ化が多く、楽しみです🤩

今クールは全部で80作品ほどあり、「こんなにあるのか」と驚きました。
続き物や深夜帯でない枠は含んでいないので、1クール100本くらいのアニメが流れているんですね!