普段は C# 使いの私が PyCon JP 2021 に参加してみた

# はじめに

2021年10月15日・16日に開かれた [PyCon JP 2021](https://2021.pycon.jp/) に、[スタッフとして参加](https://2021.pycon.jp/staff)してきました。

実は、私は業務では C# や ASP.NET 、 Microsoft SQL Server を使用しており、 Python とは無縁の仕事をしておりますが、様々なつながりがあって2017年からスタッフを続けています。

スタッフとしてどんなことをしたかはどこかで後日書くことにするとして、ここではスタッフ活動の傍ら聞くことができたセッションの感想を紹介します。

なお、期間が開いてしまい、記憶があやふやになりながら書いていますが、新たな発見をしたら随時追記していきたいと思います。

# 聞くことができたセッションの感想

さて、ここからは聞くことができたセッションの感想を書いていきたいと思います。

## [1日目キーノート: 谷合 廣紀氏](https://2021.pycon.jp/time-table/?id=290208)

最近母が「観る将」にハマっている近頃ですが、プロ棋士でAI開発者という谷合さんの発表は十分聞き応えがありました。

とりわけ、以下の話はすごいなと思いました。

- 自分でAIを作ってみた話
- プロ棋士が盤面のどこを注目しているかがAIの力でわかってしまった話
- プロ棋士の傾向がデータ分析で可視化された話

気がつけば質問も取り上げられるなど、なかなかよいお話だったと思います。

## [ASGIアプリケーション入門 - こわくないasyncio基礎と非同期IO - FastAPIを例に](https://2021.pycon.jp/time-table/?id=273766)

Python で非同期I/Oを実現する、 asyncio についての発表です。

非同期ノンブロッキングI/O は Node.js などで採りあげられているのですが、この非同期I/Oのしくみをちゃんと理解するのによいセッションだったと思います。
とりわけ、イベントループをワンオペのレストランに例えることで、なかなかよく理解できる話になったと思います。

また、 `async` と `await` に関しては C# でよく聞く単語なのですが、よく似た記法を採用することによって理解しやすいなと思います。

## [Webアプリを並行開発する際のマイグレーション戦略](https://2021.pycon.jp/time-table/?id=273396)

Webアプリを開発するときにはだいたいO/Rマッパーという、オブジェクト指向のプログラミング言語のモデルとデータベースのスキーマの仲立ちをしてくれるツールを使うのですが、O/Rマッパーにはマイグレーションという、DBのスキーマをプログラミング言語で変更する機能があります。
このマイグレーションのコードはけっこう衝突するので、その問題をなんとかするにはどうしたらよいか、という話でした。

実のところ、私は Entity Framework を使っているのですが、マイグレーション機能を使用したことがありません。
なのでまだまだピンとこない話も多いところですが、スキーマ変更を先行リリースして旧スキーマと新スキーマを並行運用するという考え方については使える戦略だと思います。

機会があれば、 Python や C# でマイグレーション機能を使ってみたいと思います。

## [Python x DDD!! - Python で学ぶ実践的なドメイン駆動設計とレイヤード・アーキテクチャ](https://2021.pycon.jp/time-table/?id=272415)

Python でドメイン駆動設計とレイヤード・アーキテクチャを行ってみたという発表です。
現職ではドメイン知識の習熟度やコミュニケーションに苦手意識のあるメンバーに配慮して Biz と Dev 、 Ops の意思疎通を意図的に遮断しているところがあるようですが、個人的にはドメイン知識は Biz ・ Dev ・ Ops のメンバーが認識を共有した方がよいと考えています。それによって、設計の見通しもよくなるなと思っています。
そのためには明確な設計指針と共通認識、ちゃんとしたコミュニケーションがしっかりしていることが大事だと思います。

また、レイヤード・アーキテクチャ用いて責務を分離するというのも共感ができるものでした。
インターフェースを定義して実装を分離するというのも、インターフェースというしくみが既にある C# なのだから、ちゃんと使う必要があるなと思っています。

実に、今後の参考になるよい発表でした。

## [2日目キーノート: Mr. Brandt Bucher](https://2021.pycon.jp/time-table/?id=290209)

Python 3.10 で使われるようになったパターンマッチに関するお話でした。

実のところ、パターンマッチングというのはピンとこなかったのですが、これを使うことによってすごくコードがわかりやすくなると思います。

## [他人が書いたコードのリファレンスをSphinxで作る方法](https://2021.pycon.jp/time-table/?id=271453)

[Sphinx](https://www.sphinx-doc.org/ja/master/index.html)  というドキュメンテーションツールを使って、既に書かれてしまったコードにドキュメントをつけるというセッションでした。
この Sphinx は私も Web サイト作成のドキュメンテーションで使っていたのですが、 C# での開発がメインになってからはうまく使えていない状態です。
とりわけ、いまの開発プロジェクトに入ってからはたまにドキュメントを書くのを後回しにしてしまっているので、実に背筋が凍るセッションでした。

正直に言うと、ついつい、ドキュメントを書き忘れることがあるんですよね……。
それが積もり積もって自分に降りかかってくるのですが、そんなときにExcel方眼紙だったりするとけっこう泣きたくなります。
docstring をちゃんと書くことで、後でコードを使う人が幸せになれると感じました。
しかも、いい感じに書けばいい感じのドキュメントができあがるわけです。
Sphinx、使えたら使いたいものです。

なお、 C# には XML コメントをドキュメントにしてくれるツールとして [DocFx](https://dotnet.github.io/docfx/) なるものがあるのですが、 PDF を作るのには一手間かかるので、できれば Sphinx と連携させたいですね……。

## [Pythonのバリデーション定義からフロントエンドTypeScriptのコード生成](https://2021.pycon.jp/time-table/?id=273602)

[Marshmallow](https://marshmallow.readthedocs.io/en/stable/) というバリデーション・シリアライゼーションライブラリを使って TypeScript のコードを生成しようという取り組みについての発表です。

個人的には同様の試みとして、 OpenAPI ドキュメントから TypeScript のコードを生成する [openapi2aspida](https://github.com/aspida/openapi2aspida) というツールを知っていましたが、 Marshmallow を使う場合は Python サイドの型を柔軟に TypeScript の型に変換できるというメリットがあるのかなと思いました。

そして、セッションを聞いたときにはすっかり忘れていたのですが、 gRPC という手段もあったな、と。この gRPC については C# 、とりわけ Unity 界隈では [MagicOnion](https://github.com/Cysharp/MagicOnion) なる、 C# 専用ながら gRPC をまるっとラップしてしまうリアルタイム通信用ライブラリもあるらしいです。

個人的には、インターフェースの型を保証する際の問題は相当厄介なのですが、こういうレイヤーをうまくつないでくれるライブラリに強く期待しています。あと、個人的には Flutter や Kotlin 、 Swift や C# のような、 TypeScript 以外の言語にも変換できるとうれしいです。

## [ラズパイとDashで環境ダッシュボードを作ろう](https://2021.pycon.jp/time-table/?id=273836)

[Raspberry Pi](https://jp.rs-online.com/web/generalDisplay.html?id=raspberrypi) というシングルボードコンピューターを使って、室内の環境変化を見るためのダッシュボードを作るというセッションでした。
この Raspberry Pi は1万円行かない値段でいろいろできちゃうコンピューターなのですが、「なければ作る」という Maker 魂を持つ者にとっては必需品とも言えるものです。

「なければ作る」という Maker 魂、大事にしていきたいと思います。

# セッション以外の感想

## [JX通信社さんのミニゲーム](https://github.com/pentla/pyconjp2021-game)

PyCon JP 2021 には[各スポンサー](https://2021.pycon.jp/sponsors) のスポンサーブースがありましたが、その中でも [JX通信社](https://jxpress.net/) さんは[ミニゲームを用意して](https://tech.jxpress.net/entry/2021/10/20/170942)くれました。

Pythonに 関するクイズなのですが……普段 C# を使ってて Python の挙動を忘れかけている私にとって、実によい難易度でした。
もう問題と答えが公開されているので、私がやってしまった「遠回りな方法」の解答と共に紹介します。

### 各問題の解答

さて、ここからは各問題とそれに対する私の解答を書いてみたいと思います。

#### [1問目](https://github.com/pentla/pyconjp2021-game#1%E5%95%8F%E7%9B%AE)

> 【問題】次のうち、PythonのAPIフレームワークでないものはどれか。
1： FastAPI 2： Flask 3： SymPy 4： Tornado

これはすぐに `3` とわかったのですが、解答方法がRESTでしか投げられないというところでちょっと苦労しました。
結局、解答は `curl` を使って投げることにしました。

#### [2問目](https://github.com/pentla/pyconjp2021-game#2%E5%95%8F%E7%9B%AE)

> datetimeパッケージで、datetime型を「x年x月x日x時x分x秒」(例: 2021年10月13日12時01分23秒)というフォーマットで出力させたいです。
この場合、strftime関数に入力する文字列はどのようになりますか？
月、日、時、分、秒はそれぞれ2桁の0埋め、時刻は24時間表記になります。
引数の文字列の中身を回答してください。

と、この問題は標準ライブラリの挙動を忘れかけている私にとって十分手応えのある問題でした。

なんとか、 `"%Y年%m月%d日%H時%M分%S秒"` という答えにたどり着けました。

#### [3問目](https://github.com/pentla/pyconjp2021-game#3%E5%95%8F%E7%9B%AE)

> 【問題】二つの文字を1文字ずつ結合させた文章を作成してください。「りんご」と「ぱいそん」なら、正解は「りぱんいごそん」になります。
> 
> 以下の二つの文章を組み合わせた場合、どのような単語になるでしょうか？
> 「Python(パイソン) は1990年代初頭ごろから公開されているプログラミング言語」
> 「汎用的なプログラミング言語で、いろいろなアプリケーション開発や、システム管理ツールとして幅広く使われています」

この問題はあっさり引っかかりました。
本来であれば、 `itertool` の `zip_longest` 関数を使わないとこの解答が求められないのですが、やはり最初は `zip` 関数を使うことに目が向いてしまい、何度やっても解答が求まらないということで相当苦戦しました。

``` python:間違えたコード.py
>>> str1 = "Python(パイソン) は1990年代初頭ごろから公開されているプログラミング言語"
>>> str2 = "汎用的なプログラミング言語で、いろいろなアプリケーション開発や、システム管理ツールとして幅広く使われています"
>>> print("".join([''.join(pair) for pair in zip(str1, str2)]))
P汎y用t的hなoプnロ(グパライミソンング)言 語はで1、9い9ろ0い年ろ代な初ア頭プごリろケかーらシ公ョ開ンさ開れ発てやい、るシ
プスロテグムラ管ミ理ンツグー言ル語と
```

本来なら、こう解くのが正解だったと思います。

``` python:正解.py
>>> import itertools
>>> str1 = "Python(パイソン) は1990年代初頭ごろから公開されているプログラミング言語"
>>> str2 = "汎用的なプログラミング言語で、いろいろなアプリケーション開発や、システム管理ツールとして幅広く使われています"
>>> print("".join([''.join(pair) for pair in itertools.zip_longest(str1, str2, fillvalue="")]))
P汎y用t的hなoプnロ(グパライミソンング)言 語はで1、9い9ろ0い年ろ代な初ア頭プごリろケかーらシ公ョ開ンさ開れ発てやい、るシ
プスロテグムラ管ミ理ンツグー言ル語として幅広く使われています
```

#### [4問目](https://github.com/pentla/pyconjp2021-game#4%E5%95%8F%E7%9B%AE)

> 【問題】\u3071\u3044\u3053\u3093\u3058\u3047\u30fc\u3074\u30fc\u3078\u3088\u3046\u3053\u305d というメッセージが記載されていました。これはどのような意味でしょうか？

初見でUTF-8ということはわかったのですが、まさか `print` で一発で解けるとは思わず……。

なので、こんな風にして解きました。

``` python:ここまで書かなくてもよかった.py
>>> print(b"\\u3071\\u3044\\u3053\\u3093\\u3058\\u3047\\u30fc\\u3074\\u30fc\\u3078\\u3088\\u3046\\u3053\\u305d".decode('unicode-escape'))
ぱいこんじぇーぴーへようこそ
```

解答を知って愕然としました。まさか、そのまま `print` 関数でいけたとは……。

#### [5問目](https://github.com/pentla/pyconjp2021-game#5%E5%95%8F%E7%9B%AE)

> 【問題】以下の文章を解読してください。
     例: Uryyb Jbeyq!! -> Hello World!!
     Gunax lbh sbe ivfvgvat gur WK obbgu!

実は、この問題はPythonに `rot13` という暗号があると言うことを **全く** 知りませんでした。
ただ、シーザー暗号ということはわかったので「[古代の暗号をpythonで実装する](https://qiita.com/twrcd1227/items/7540141050181b8cb7c2)」という記事を参考にブルート・フォース・アタックで解読しました。

``` python:ブルート・フォース・アタック.py
# ブルート・フォース・アタックで解読する
def decrypt(cipher_text):  
    for shift_num in range(26):
        answer = ""  # 鍵shift_numで復号したときの結果
        for char in cipher_text:
            # 英語以外のとき
                if not(65 <= ord(char) <= 90 or 97 <= ord(char) <= 122):
                    answer += char
                # 大文字かつシフトした際Aより小さくなるとき 
                elif ord(char) - shift_num < 65 : 
                    answer += chr(ord(char) - shift_num + 26)
                # 小文字かつシフトした際aより小さくなるとき 
                elif ord(char) - shift_num < 97 and ord(char) >=97:
                    answer += chr(ord(char) - shift_num + 26)
                # その他の場合 
                else:                                   
                    answer += chr(ord(char) - shift_num)
        print("鍵" + str(shift_num) + "で復号 → " + answer)


# 暗号文
cipher  = "Gunax lbh sbe ivfvgvat gur WK obbgu!"

# 解読
decrypt(cipher) 
```

``` python:出力
鍵0で復号 → Gunax lbh sbe ivfvgvat gur WK obbgu!
鍵1で復号 → Ftmzw kag rad hueufuzs ftq VJ naaft!
鍵2で復号 → Eslyv jzf qzc gtdtetyr esp UI mzzes!
鍵3で復号 → Drkxu iye pyb fscsdsxq dro TH lyydr!
鍵4で復号 → Cqjwt hxd oxa erbrcrwp cqn SG kxxcq!
鍵5で復号 → Bpivs gwc nwz dqaqbqvo bpm RF jwwbp!
鍵6で復号 → Aohur fvb mvy cpzpapun aol QE ivvao!
鍵7で復号 → Zngtq eua lux boyozotm znk PD huuzn!
鍵8で復号 → Ymfsp dtz ktw anxnynsl ymj OC gttym!
鍵9で復号 → Xlero csy jsv zmwmxmrk xli NB fssxl!
鍵10で復号 → Wkdqn brx iru ylvlwlqj wkh MA errwk!
鍵11で復号 → Vjcpm aqw hqt xkukvkpi vjg LZ dqqvj!
鍵12で復号 → Uibol zpv gps wjtjujoh uif KY cppui!
鍵13で復号 → Thank you for visiting the JX booth!
鍵14で復号 → Sgzmj xnt enq uhrhshmf sgd IW annsg!
鍵15で復号 → Rfyli wms dmp tgqgrgle rfc HV zmmrf!
鍵16で復号 → Qexkh vlr clo sfpfqfkd qeb GU yllqe!
鍵17で復号 → Pdwjg ukq bkn reoepejc pda FT xkkpd!
鍵18で復号 → Ocvif tjp ajm qdndodib ocz ES wjjoc!
鍵19で復号 → Nbuhe sio zil pcmcncha nby DR viinb!
鍵20で復号 → Matgd rhn yhk oblbmbgz max CQ uhhma!
鍵21で復号 → Lzsfc qgm xgj nakalafy lzw BP tgglz!
鍵22で復号 → Kyreb pfl wfi mzjzkzex kyv AO sffky!
鍵23で復号 → Jxqda oek veh lyiyjydw jxu ZN reejx!
鍵24で復号 → Iwpcz ndj udg kxhxixcv iwt YM qddiw!
鍵25で復号 → Hvoby mci tcf jwgwhwbu hvs XL pcchv!
```

13文字ずらすシーザー暗号のことをROT13ということを知っていればもっと簡単に解けたのに、と思いました。

### 結局どれぐらいの時間がかかった？

だいたい50分ぐらいかかりました。
我ながら、まだまだPythonの標準ライブラリの中身を知らないと痛感しました。
なんだかんだいって、お昼休みの大半をこの問題を解くのに使ってしまった感じがします。

## `Optional[T]` と書くべきか、 `T | None` と書くべきかの問題

クロージング前のスポンサーLTで、こんな話題がありました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/pyconjp?src=hash&amp;ref_src=twsrc%5Etfw">#pyconjp</a> の参加者に質問です。 3.10 で nullable の型ヒント書くならどっちで書きたい？ (このあとの LT のネタですｗ)</p>&mdash; 小笠原みつき / JX通信社 / 69.6㌕ (@YAMITZKY) <a href="https://twitter.com/YAMITZKY/status/1449285622837886976?ref_src=twsrc%5Etfw">October 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これに関しては、私はこう思います。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/pyconjp?src=hash&amp;ref_src=twsrc%5Etfw">#pyconjp</a> のLTででてきた nullable の型ヒント問題、個人的にはすごく迷う問題。<br><br>「X | None」の方が書くの楽だとは思うけど、意味的にはちゃんと「Optional[X]」と明示したい気分でもある……。<br><br>……でも、「X | None」とついつい描いてしまうのではないかと思う。 <a href="https://t.co/e7QDnvhqCu">https://t.co/e7QDnvhqCu</a></p>&mdash; ヨーシャ（Iosif Takakura） (@huideyeren) <a href="https://twitter.com/huideyeren/status/1449300366474891264?ref_src=twsrc%5Etfw">October 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

楽、したくなるのはわかるんですけどね……。

なお、 C# の場合は [null 許容値型](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/builtin-types/nullable-value-types) というのがあり、以下のように型指定して変数を定義するときに `null` を許容するか指定できます。

``` csharp:null許容値のC#での書き方.cs
int m2 = 10;
int? m = m2;
``` 

個人的には Python でも `a: T?` のように書ければ最高なのですが……。

# おわりに

2021年も楽しくイベントに参加することができました。
2022年も皆さんと楽しめればよいと思っています。また来年！！