ITと哲学と

IT系エンジニアによる技術と哲学のお話。

コロナ禍に中国長期出張に行った話 鄭州での生活編

コロナ禍のこの時期に、中国長期出張に行ってきたので思い出をまとめておこうと思います。

長期の海外生活自体も初めてでしたしコロナ禍のこの時期の海外渡航履歴ということで結構珍しい体験だったと思うので、未来の自分が思い出して懐かしむためにメモを残しておこうという魂胆です。

期間は2021年の11月5日から2022年1月30日までの87日間で、中国の上海と河南省鄭州市というところに行ってきました。

鄭州市での生活

鄭州市では市内にあるHilton Hotelに宿泊しました。 隔離ホテルに比べてだいぶ豪華で、綺麗なホテルだったのでテンションが上がりました。

鄭州のHitonには小さいですがジムがついており、ランニングマシンやダンベル、ベンチなどがありました。 ジムにはタオルやペットボトルの水が備え付けてあり、軽く汗を流すのには大変良い空間でした。

コロナ禍ということもあり(?)ほとんど人がいなかったのでだいぶ快適でした。

朝ご飯のビュッフェ付きで、生野菜も食べられるので大変ありがたかったです。

f:id:masamasah:20220402102108p:plain
朝ご飯ビュッフェの様子。かなり豪華。シェフが左手で調理してくれており、熱々のご飯がいただける

隔離が終了した日は、出張メンバーみんなで日本食の居酒屋に行きました。 その時点で一ヶ月日本食から離れていたのもあり、すごく美味しいご飯になりました。 なお、居酒屋はかなり日本感が強く居心地が良かったです。

f:id:masamasah:20220402101813p:plain
日本風居酒屋の店内の様子。まさか海街のポスターを中国で見るとは

街の様子

街の様子は道が広いですが車が多く、混雑している車列を逆走して追い抜いていく車がかなり多かったです。タクシーで通勤していましたが、車間距離がつめつめでかなりヒヤヒヤしながらの通勤でした。 全員が日本で言う煽り運転のような状態なので、観光できた日本人は和を見出して危険なので運転をしないことをお勧めします。

職場の近くの公園ではジムのような運動器具や卓球台があり賑わっていました。

f:id:masamasah:20220402102549p:plain
職場の近くの公園のジム。無料で利用できる。綺麗に整備されている印象を受けた

f:id:masamasah:20220402102629p:plain
公園の卓球台。自由に卓球できる。出張者メンバーで行なった卓球大会において見事優勝した

鄭州グルメ

おすすめの鄭州グルメはマーラータン。鄭州発祥というわけではないと思いますが、野菜がたくさん摂取でき、味付けも自分で好みのものにできるので。 張亮マーラータンというチェーン店で、日本にもいくつか店舗があるようです。また食べたいなぁ。

f:id:masamasah:20220402103405p:plain
きのこ系の出汁のマーラータン。無料トッピングのニンニクとパクチーをこれでもかと入れて食べるのがお勧め。

支払いはalipayでの支払いがほぼ全てでした。現金は中国の法律で断ってはいけないそうですが、現金支払いしている人は見たことがなかったです。キャッシュレスが進んでるのは大変便利でした。

また、Uber的なサービスも発展しており、吉野家すき家など日本食も注文することができるので便利でした。なお、中国で日本と同じ味が食べたければすき家がお勧めです。日本と全く同じ味に感じました。

観光スポット

観光では1/1のお正月に黄河に行ってきました。乾季だったようですが、川が向こうが見えないような広さで広がっておりスケールの違いを見せつけられました。

f:id:masamasah:20220402105651p:plain
黄河。黄色くはない

名前は忘れましたが鄭州の観光スポットとして有名なとうもろこしタワーというものがあり、お正月や旧正月など特別な日にライトアップされます。ライトアップされたとうもろこしタワーも綺麗でした。

f:id:masamasah:20220402103758p:plain
水面に映える特別なライティングがされたとうもろこしタワー

コロナ対策

出張期間の最後の方では、コロナが近隣で流行り始めており、全住民を対象とした無料PCR検査の強制受験が始まりました。

中国ではコロナ対策として、どこの商業施設や電車に乗る際にも健康コードの提出が求められます。

健康コードとは、その人個人にコロナ感染リスクがあるかどうかを管理するためのQRコードです。感染のリスクが低ければQRコード自体が緑色、濃厚接触者などリスクが高くなると黄色、コロナ感染者だと赤色に変わります。

商業施設や電車はこの健康コードが緑色でないと利用することができません。

全住民を対象とした無料PCR検査では、この検査を受けないと翌日健康コードが黄色になってしまい、商業施設の利用などができなくなり生活が大変不便になります。 これを避けるために市内の住民の全てがPCR検査を受けるわけです。こういう仕組みができるもの中国の強みみたいなものを感じました。

PCR検査は密を避けるために屋外で行われるのですが、この時期は雪が降り始めたりしていてとても寒い時期で大変でした。最高気温がマイナスな日もザラで、そんな状況で屋外でPCR検査を受けるために一時間くらい並ぶのは心が折れそうでした。

f:id:masamasah:20220402105253p:plain
PCR検査場の待機列。クッソ寒い。

検査は徹底的に行われ、結局一週間くらい毎日ぶっ続けで土日とか関係なく行われました。しかも前日の21時ごろに明日も検査するから受けてね!と連絡が来るのでいつまでこれが続くんや。。という恐怖感がすごいです。 最後の方は検査する側も手慣れてきてオペレーションが向上し、待ち時間が半減したのは素直にすごい国だなと感心しました。

上海での生活編に続く

コロナ禍に中国長期出張に行った話 中編

コロナ禍のこの時期に、中国長期出張に行ってきたので思い出をまとめておこうと思います。

長期の海外生活自体も初めてでしたしコロナ禍のこの時期の海外渡航履歴ということで結構珍しい体験だったと思うので、未来の自分が思い出して懐かしむためにメモを残しておこうという魂胆です。

期間は2021年の11月5日から2022年1月30日までの87日間で、中国の上海と河南省鄭州市というところに行ってきました。

私が長期出張に行ったタイミングでは、まず中国上海に到着後2週間の隔離を受け、その後目的地である河南省鄭州市に到着してからさらに2週間の隔離を受けなくてはなりません。

つまり、のべ1ヶ月の隔離生活が始まったわけです。

隔離生活 @上海

生活に必要な物資については、ホテルに着いた段階で最低限用意されています。

1ダースくらいのペットボトルの飲み水やゴミ袋が備え付けでありました。 2週間で1ダースの飲み水では足りないため、水など必要な物資は自分で注文することができます(後述しますがホテルにより状況は異なる)。

上海の隔離ホテルでは、購入可能な物資のリストが用意されており、ここから必要なものをAlipayもしくはWechatで注文することができます。 なお、アルコールは隔離中は購入できません。禁酒です。辛い。

f:id:masamasah:20220321154101p:plain
調達可能なものリストの一部

Wechatでの支払いは中国国内の銀行口座が必要なので口座がない人はAlipay Tour Passという中国人ではなくても利用できるキャッシュレスの支払い手段を使う必要があります。少なくとも隔離される前にはAlipay Tour Passで支払いができる状態を作ることを強くお勧めします。

私は隔離されてから知ったので、Alipay Tour Passの登録を行なったのですが、慣れない作業でミスしたり試行錯誤していたところ、不審な利用者と判定されAlipay Tour Passのアカウントがフリーズされるという事故がありました。 Alipay側に連絡すると電話で直接喋って問い合わせしないと解除できないと言われ、慣れない英語で会話して凍結解除の申請をしました。申請してもすぐに解放されるわけではなく、支払いができるようになるまでにかなりの時間を要しました。

幸いチームメンバーも同じホテルで隔離だったのでうまく支払いができているメンバーに立て替えてもらって水を買い、なんとか生き延びましたが。。

部屋自体は日本のビジネスホテルとは違いかなり広く、快適でした。 壁一面窓だったので、隔離という言葉から想像される閉塞感みたいなものはかなり少なかったです。

f:id:masamasah:20220321155614p:plain
上海の隔離ホテル。日光が入ってくるので快適。右奥に一人がけのソファーがあり、読書なんかしてると大変良い。

ただ、これも運次第のようで、チームメンバーの部屋はめっちゃ暑くてしんどいとかあったようです。 他の渡航者の話を聞くと窓がない部屋だったというようなケースも聞きました。

心配していたご飯も初日以降はかなりバリエーションが豊かで、大変ありがたかったです。

f:id:masamasah:20220321155315p:plain
とある日の晩御飯

この頃は比較的仕事的にも余裕があったので、息抜きにリングフィットアドベンチャーやフィットボクシングをやって体を動かしていました。

辛かったのは、隔離期間はリネン類の交換がないという点です。 シーツやタオルなど2週間交換がないため、ファブリーズを駆使してなんとか凌ぎました。 渡航され隔離を過ごされる方はファブリーズ必須です。

それと、洗濯も手洗いになります。 色々試しましたが、大きめの袋に服と洗剤と水を入れつけ置きし、シャワーのタイミングで洗う方法に落ち着きました。 吸盤でつけられるタイプの洗濯干し紐がかなり役に立ちました。

比較的穏やかに、2週間の隔離生活が終わりました。

隔離生活 @鄭州

上海での隔離が終わった後、タクシーで上海空港に向かいます。 久しぶりの娑婆です。天気も良く晴れ晴れとした気持ちで最終目的地の鄭州へと向かいました。

鄭州に飛行機がついたら外国人向けの手続きを済ませます。これもかなり待たされますが屋内だったので割と気は楽でした。

手続きが終わると、この乗り物に乗って、次の隔離ホテルへ移動します。

f:id:masamasah:20220321160631p:plain
隔離ホテルへ向かう謎の乗り物

これ、実は救急車です。 空港から隔離ホテルまで、救急車で1時間くらい走ります。 高速道路でいったのですが、だいぶ車内揺れました。 海外で救急車に乗る日が来るとは思いもしませんでした。大変貴重な経験ができました。

鄭州の隔離ホテルはこんな感じ。

f:id:masamasah:20220321160944p:plain
鄭州の隔離ホテル

ポイントはベッドがシングル2つになっています。 日替わりでベッドを変えることでリネン変えてくれない問題に対応することができます。

上海のホテルよりは解放感がなく、少し残念ではありましたが、それでも日本のビジネスホテルと比べるとだいぶマシです。

ここのホテルは飲料水用の蛇口があるため水を買わなくても生活ができます。 上海のホテルとは異なり調達可能リストはなく、普通にネット通販頼んだら届くとのことでした。 なおアルコールはNGとのことです。

ご飯はとても美味しいのですが、毎食量が大変多く、申し訳ないですが全部食べることはできませんでした。

f:id:masamasah:20220321161341p:plain
とある日の昼ごはん。マーラータンがうまい

ここでも上海同様に部屋の外に小机があり、そこに毎日配給がおかれ、部屋がノックされるシステムです。

上海では毎日白づくめの職員が訪問してきて、熱を測ったりコミュニケーションをとるのですが、鄭州ではWechat上でのコミュニケーションとなります。 自分で熱を測り、Wechatで報告する。これを日に2回行います。

私は中国語ができないのですが、Wechatはチャットを翻訳する機能がありだいぶお世話になりました。

一緒に行った出張メンバーに中国人がいたのですが、彼女が職員さんと会話している中で「彼らは日本人だけど配給は口に合っているか?」と心配してくれていたようです。こんな大変な状況で気遣ってもらって大変ありがたいなと思いました。ご飯は大変口に合いました。隔離中は禁酒なのに太りました。

そんなこんなで鄭州での隔離生活も無事終了しました。 後編に続く。

コロナ禍に中国長期出張に行った話 前編

コロナ禍のこの時期に、中国長期出張に行ってきたので思い出をまとめておこうと思います。

長期の海外生活自体も初めてでしたしコロナ禍のこの時期の海外渡航履歴ということで結構珍しい体験だったと思うので、未来の自分が思い出して懐かしむためにメモを残しておこうという魂胆です。

期間は2021年の11月5日から2022年1月30日までの87日間で、中国の上海と河南省鄭州市というところに行ってきました。

出張行くまでの話

コロナ禍が始まる前から仕事の都合で中国に長期出張する予定だったのですが、コロナ禍の影響を受けてずっと叶わずにいました。 国境が開いたらすぐ行けるように準備はしており、何回かチャンスらしきものはありましたがチャレンジしかけては行けずという状況が続いていました。

仕事で外国に行く場合は大抵ビザが必要になると思いますが、中国渡航の場合でも同様に必要でした。 コロナの状況によって取得のハードルは変わってくるようですが、私がビザを取った時は中国にある企業からの招聘状の他に省政府からの招聘状というものが必要でした。なんとか現地の皆さんにご協力いただき、各招聘状を取得することができました。

それらの書類を持って代理店にビザ取得の手続きをしてもらい、大阪心斎橋にあるビザセンターに出向いて指紋採取などを行なって、その後一週間くらいで受領できました。 すでに出張開始期日が近づいていたので、ビザが手元に来るまでは気が休まらない日々を過ごしていました。

渡航前日

今はどうなっているかわかりませんが、当時はいくつか必要な事前手続きがありました。 まず、Health Declaration Certificateの健康コードというものがあります。 これは日本を出国するために必要な書類で、搭乗の前日に申請する必要があります。これを提出するにあたり、 (記憶が定かではないが確か)2日以内のPCR検査陰性証明が必要になります。さらにPCR検査陰性証明は中国の指定するフォーマットのものが必要で、どこでも受けられるというものではありません。 私が渡航した時は羽田空港で中国指定のフォーマットでPCR検査が受けられたため、そちらで前日に受診しました。

次に、中国に入国するために必要な中国税出入国健康申告というものもあります。 これは中国に入国する時刻の24時間前から飛行機乗る前までに申請する必要がありました。

これらの各種タイミングは一個ミスするとリカバリーできない可能性があるので、申請作業を行う時間をカレンダーに登録し、漏れのないように対応をしました。

なお、空港ではスーツを着たおじさんがここら辺の手続きができていなかったらしく職員の人と手元のスマホでポチポチ作業をしていました。あのおじさん間に合ったんだろうか。。。

渡航当日

海浦東空港に到着しました。CAさんは感染症対策で白づくめです。空港スタッフの方々も同様です。 この時点で「あ、なんかすごいことになってる」感が漂ってきます。

f:id:masamasah:20220321145329p:plain

渡航者は目的地別にまとめられてバスで隔離先ホテルまで護送されるのですが、人が十分に集まってから輸送される関係でめっちゃ待たされました。バスターミナルみたいなところで待つことになるので防寒対策は必須です。それと途中でトイレに行けないので、飛行機から降りる前に飛行機内でトイレ行っておくことをお勧めします。私は飛行機の中で近くに座った人たちがそんな会話をしていたのを耳に挟んだのでトイレに行っておくことができました。

バスを待っている間に、パスポートを職員の人に渡してなにやら処理をしてもらいますが、この時点ではパスポートは帰って来ません。

護送中の移動はこんな感じです。

f:id:masamasah:20220321145533p:plain ペルソナのベルベットルームかな?という驚きの青さでした。 この状態で30分から45分くらい移動します。

外は真っ暗、パスポートは預けた状態、行き先・移動時間が告げられていない外国のバスはちょっと怖かったのを覚えています。 ただ、一緒にバスに乗っている人たちは日本人が多いので心強さはありました。

程なくバスは停車し、さらに30分ほど待たされたのちにパスポートが返却されホテルについたことがわかりました。

降りたらこんな感じのいい感じのホテルでした。 後から調べたところ、上海のディスニーランドにかなり近いところだったようです。 f:id:masamasah:20220321150359p:plain

ホテルに入って、既に0時を超えており疲労困憊ではありましたが「やっと休める。。」と力を抜くことができました。同時に感染対策のため日本の空港からずっと何も食べていないことに気がついてお腹が減って来ました。

もう0時超えてるし夕飯は出ないかもなと思っていた矢先、部屋の扉がノックされました。 扉を開けてみると、扉の外にはこんなお弁当が。

f:id:masamasah:20220321151550p:plain

水餃子です。中国きたんだなぁという思いが一気に強まったわけですが、もしこれから当面3食これだったら超辛い。。と軽く絶望を覚えました。味は普通に美味しいんですが、水餃子のみという食事内容では飽きてしまいます。お弁当のケース3セクションに分けられてるんだから別のものを入れて欲しい

隔離ホテルでは感染対策のため、白づくめの職員さんがお弁当や配給などを部屋のすぐ外にある小机に置いて受け渡しをしてくれます。地べたに置かないで小机を用意してくれるところに温もりを感じました。 隔離ホテルは2ヶ所お世話になりましたが2ヶ所とも同じシステムだったので決まった方式なんだろうと思います。

ここから2週間の隔離生活が始まりました。長くなったので続く。

Hello Python3.10

Python3.10が2021/10/4に正式リリースされる予定です。

Python3.10で新たに入る機能はすでにアナウンスされていますが、この中でいくつか気になったものがあるので、紹介しようと思います。

なお、本情報は2021/8/15現在の情報です。

スケジュール

Python3.10のリリーススケジュールは以下のPEPの通りです。

www.python.org

現在は3.10.0 candidate 1がリリースされています。

動作サンプル

この記事のコードはこちら。

github.com

Python3.10rc1で動作します。

本記事で紹介する新機能

個人的なお気に入りは以下の3つなので、それぞれ紹介します。

  • ErrorMessageのエンハンス
  • PEP 604, Allow writing union types as X | Y
  • PEP 634, PEP 635, PEP 636, Structural Pattern Matching

ErrorMessageのエンハンス

コード書くとき、よく触れるエラーメッセージですが、Python3.10からはちょっと気の利いたメッセージの出し方に変わります。 例を見てみましょう。

items = {
    "x":1,
    "y":2    #,がない
    "x":3,
}

python3.9では、これを実行しようとすると、以下のようなエラーメッセージが表示されます。

root@d0b73014baa3:/src# python sample.py 
  File "/src/sample.py", line 5
    "x":3,
    ^
SyntaxError: invalid syntax

これが、3.10では以下のようにユーザフレンドリーなエラーメッセージの表示に変わります。

root@3ffc6908fe04:/src# python sample.py 
  File "/src/sample.py", line 4
    "y":2 
        ^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?

該当行をちゃんと指定した上で、comma忘れてね?と教えてくれるわけです。超便利。 長時間作業して集中力落ちてきた時にハマって絶望する人類が減るので大変良いです。

さらに、タイポした変数を検知して修正を提案してくれたりもします。僕は普段タイポの修正に70%ほどの生産性を費やしているので、これがAIに仕事を奪われるということか、と時代の流れを感じています。

ultimate_answer = 42 
print(ultimat_answer) # typoしてる

python3.9では以下の通りで、エラーメッセージ見てもよくわからないですよね。

root@d0b73014baa3:/src# python sample.py 
Traceback (most recent call last):
  File "/src/sample.py", line 2, in <module>
    print(ultimat_answer) 
NameError: name 'ultimat_answer' is not defined

お酒飲みながら作業してたりすると見逃して、はまってしまいますよね。

これ、python3.10ではこんな感じになります。

root@3ffc6908fe04:/src# python sample.py 
Traceback (most recent call last):
  File "/src/sample.py", line 11, in <module>
    print(ultimat_answer)     
NameError: name 'ultimat_answer' is not defined. Did you mean: 'ultimate_answer'?

ピャ------!!賢い!Python3.10タン賢い! 積極的にタイポしてPython3.10タンの優しさに包まれたい!!! と、なりますよね。

UnionType

型の表現の際に、"or"を表現するには、Python3.9までは以下のようにUnion型を使って表現していました。

def is_dog_or_cat(animal: Union[Dog, Cat]):
    pass

これが、Pyhthon3.10からは"|"を使って以下のように表現できます。他の言語でもよくみるような記法ですよね。

def can_pet(animal: Dog | Cat):
    pass

この記法ができることになったことで、後述のパターンマッチングがより綺麗に書けるようになります。

パターンマッチング

初歩

ここからが真打のパターンマッチングの紹介です。

これまでのpythonでは以下のように書いていたものを

if isinstance(x, tuple) and len(x) == 2: 
    host, port = x 
    mode = "http" 
elif isinstance(x, tuple) and len(x) == 3: 
    host, port, mode = x 
# Etc.

パターンマッチングを使うと以下のように記載できます。

match x: 
    case host, port: 
        mode = "http" 
    case host, port, mode: 
        pass 
    # Etc.

一般化して記載するとこんな感じです。

match 式: 
    case パターン1: 
        … 
    case パターン2: 
        …

式の値を評価して、合致するパターンの文に飛ばすといった機能です。 この時、パターンは上からチェックされ、一番初めに合致した条件に飛ばします。

パターンのバリエーション

パターンの書き方が色々とあり、かなり細かく表現することができます。

数値リテラルのパターン

まずは基本的なパターンである、数値でのパターンの記載です。

def http_error(status):
    match status:
        case 400:
            print("Bad request")
        case 404:
            print("Not found")
        case 418:
            print("I'm a teapot")

http_error(400) #->Bad request

この例だと、status=400なので、case 400のパターンに合致し、それに続く文が実行されます。 caseに合致するパターンが存在しない場合は、何も実行されません。

defaultのパターン

caseに特筆すべきパターンはないが、デフォルトでなんらかのパターンにマッチさせたいような場合は、以下の通りに記載します。

def http_error(status):
    match status:
        case 400:
            print("Bad request")
        case 404:
            print("Not found")
        case 418:
            print("I'm a teapot")
        case 200 | 201:
            print("OK")
        case _:
            print("something worng")

http_error(405) # ->something wrong

この、"_"がワイルドカードになっており、全てのパターンに合致するため、デフォルトでこれが実行されます。 なお、デフォルトパターンは全てのパターンが合致するため、その下にパターンをおいても到達できないコードになりますので、この場合は実行時に以下の通りエラーが出ます。

def http_error(status):
    match status:
        case 400:
            print("Bad request")
        case _: #->ここにおくと、ここ以下のパターンが到達不可能になる
            print("something worng")
        case 404:
            print("Not found")
        case 418:
            print("I'm a teapot")
        case 200 | 201:
            print("OK")

エラーメッセージは以下の通りです。

root@3ffc6908fe04:/src# python main.py lesson_3
  File "/src/main.py", line 46
    case _:
         ^
SyntaxError: wildcard makes remaining patterns unreachable

自作型のパターン

数値リテラルだけではなく、dataclassで作成した自作型を使ったパターンも記載できます。

以下の例では、引数に与えられた動物(animal)が、Dogか否かを判定します。

@dataclass 
class Dog:
    name:str
    breed:str

def is_dog(animal):
        match animal:
            case Dog():
                return True
            case _:
                return False

orの表現

次に、引数に与えられた動物(animal)がDogかCatの場合はペットにできると判定し、それ以外はペットにできないと判定するような関数を考えます。

UnionTypeの新しい記法を使うと、こんなふうに記載することが可能です。

def is_pet(animal):
    match animal:
        case Dog() | Cat():
            return True
        case _:
            return False

dog = Dog("pochi", "Chihuahua")
cat = Cat("tama", "white")
crow = Crow("car")

print(is_pet(dog))  #-> True
print(is_pet(cat))  #-> True
print(is_pet(crow)) #-> False

ここでUnion[Dog, Cat]とせずに、Dog|Catと書けるのは気持ちがいいですね。

メンバ変数でのパターン

さらに細かく、型のメンバ変数の値を評価するようなパターンを記載することも可能です。

引数に与えられた動物(animal)が、自分のペットか否かを判定する関数を書きます。 なお、自分のペットは名前がpochiであり、犬種がチワワであるとします。

この場合は、型だけでなく、メンバ変数の値をみて判定する必要がありますよね。そんな場合はこう記載できます。

def is_mypet(animal):
    match animal:
        case Dog(name="pochi", breed="Chihuahua"):
            return True
        case _:
            return False

mypet = Dog("pochi", "Chihuahua")
anotherDog = Dog("hanako", "Shiba")
crow = Crow("car")

print(is_mypet(mypet))  #->True
print(is_mypet(anotherDog))  #->False
print(is_mypet(crow)) #->False

メンバ変数パターンでのワイルドカード

さらに、メンバ変数パターンでワイルドカードを使うこともできます。 例えば、引数に与えられた動物(animal)がチワワかどうかを返す関数においては、犬の名前はどうでもよくて、breed=Chihuahuaかどうかがポイントです。

def is_Chihuahua(animal):
    match animal:
        case Dog(name=_, breed="Chihuahua"):
            return True
        case _:
            return False

chihuahua_1 = Dog("pochi", "Chihuahua")
shiba = Dog("hanako", "Shiba")
chihuahua_2 = Dog("taro", "Chihuahua")
crow = Crow("car")

print(is_Chihuahua(chihuahua_1)) #->True
print(is_Chihuahua(shiba)) #->False
print(is_Chihuahua(chihuahua_2)) #->True    
print(is_Chihuahua(crow)) #->False

こんな形で、さまざまにパターンを書いていくことができます。

バインディング

パターンマッチングのさらに強力な機能、バインディングを紹介します。 パターンに合致した値を、名前にバインディングするという機能です。 言葉で説明しても意味がわからないので、例をみてみましょう。

def build_message(animal):
    match animal:
        case Dog("pochi", "Chihuahua"):
            return f"he is my pet!"
        case Dog(name = _ as dog_name, breed="Chihuahua"): # dog_nameという名前にバインディングしている
                return f"I love Chihuahua ! come on {dog_name}!"
        case Dog(_, "Shiba"):
            return f"Shiba is not so bad."
        case _:
            return "..."

chihuahua_2 = Dog("taro", "Chihuahua")

print(build_message(chihuahua_2)) #->I love Chihuahua ! come on taro!

ポイントは、case Dog(name = _ as dog_name, breed="Chihuahua"):の行です。 このas nameで、Dogのメンバ変数nameの値をdog_nameという名前にバインディングしています。 バインディグされた名前は、caseの中で参照可能で、returnする文字列として組み込まれています。

大きな注意点として、バインディングと代入は異なります。 バインディングはあくまでcaseコンテキストの中で値を名前に一時的にくっつけるだけのものであり、caseコンテキストの外からは参照できませんし、影響を及ぼしません。

上記の意味がわかる例を下に示します。

def build_message(animal):
    name="X" # nameという名前の変数を宣言する
    match animal:
        case Dog("pochi", "Chihuahua"):
            val= f"he is my pet!"
        case Dog(_ as name, "Chihuahua"): # nameを上書きしているようにみえるが?
            val= f"I love Chihuahua ! come on {name}!"
        case Dog(_, "Shiba"):
            val= f"Shiba is not so bad."
        case _:
            val= "..."
    print(name) # ここではXが出力される。名前がかぶっていても、もとのnameが予期せぬ上書きをされない
    return val

anotherDog = Dog("hanako", "Chihuahua")

print(build_message(anotherDog)) #->I love Chihuahua ! come on hanako!

caseの中で行われるバインディングは、あくまでcaseコンテキストの中での話であり、その外の世界には影響を及ぼさないことが見て取れると思います。

なお、無理矢理外の世界に影響を与えようとすると、実行時エラーが発生します。

def build_message(animal):
    hoge=[0]
    match animal:
        case Dog("pochi", "Chihuahua"):
            return f"he is my pet!"
        case Dog(_ as hoge[0], "Chihuahua"): # hogeの第一引数に代入しようとしているがNG
            return f"I love Chihuahua ! come on {name}!"
        case Dog(_, "Shiba"):
            return f"Shiba is not so bad."
        case _:
            return "..."

実行時のエラー

root@3ffc6908fe04:/src# python main.py lesson_7
  File "/src/main.py", line 155
    case Dog(_ as hoge[0], "Chihuahua"): # hogeの第一引数に代入しようとしているがNG
                      ^
SyntaxError: invalid syntax

さらにさらに、listに対して、こんな書き方ができます。 先頭と末尾の要素をfirstlastとして取り出して、それ以外の要素はmiddleに入れるといった書き方です。

def lesson_9():
    l = [1,2,3,4,5]
    match l:
        case [first, *middle, last]:
            print(f"first is {first}, last is {last},")
            print(f"size of middle is {len(middle)}")

関数型フロントエンド言語のElmの勉強をしていたときに、このような形でリストを綺麗に扱うことができる仕組みを学び、感動してElmが好きになったのですが、Pythonでもついにこれができるようになるということで、とても嬉しいです。

注意点

Python3.10の時点では、caseの細かい精的なチェックは行われません。 ワイルドカードを末尾以外に持っていった場合の到達不能コードについてはチェックしてくれますが、それ以外の方法で到達不能になるコードのチェックはしてくれないので、エラーは起きません。

以下の例では、colorはColorのEnumであり、case 1に到達することはないですが、これをチェックしてくれたりはしませんし、Color.BLUEの処理を記載していない件についてエラーで教えてくれたりもしません。

ここら辺が静的にチェックできるようになるともっと良いなと思います。

from enum import Enum 
class Color(Enum): 
    RED = 0 
    GREEN = 1 
    BLUE = 2 
def which_color(color: Color): 
    match color: 
        case Color.RED: 
            print("I see red!") 
        case Color.GREEN: 
            print("Grass is green") 
        case 1: 
            print("!!!") 
which_color(1)

予期せぬバグを仕込まないように、注意しなくてはいけませんね。

おわりに

Python3.10のリリース、とても待ち遠しいですね。 みなさんPython3.10使っていきましょう。

ストーリーとしての競争戦略を読んだ

職場で話題になっていたので、ストーリーとしての競争戦略を読んだ。

読書後の感想

共感できたところについては、至極真っ当なことを言っているというか、当たり前だよねーと思う部分が多かった。

一方で、冗長な部分が多いと感じた。 話が長いことにも意味があるとしているが、共感はできなかった。

読みやすさへの工夫は感じなかった。もっとリッチに図解するとか箇条書きでポイント示すなどあってもよいのでは。 初めの方は全体像が示されないでストーリーについての主張が始まるので、??という感じだった。

かなり前提条件の上で成り立つよねこれ?という感じで、途中で説明が出てくるまでは素直に読めなかった。

各打ち手が有機的に繋がって、各打ち手がストーリーとして動画的に成り立つものでないといけないという主張で、これ自体は納得感が強い。

が、タイトルが無意味にポップでキャッチーに思う。 内容理解の助けにはならないので、有機的に各項目が繋がって相互作用を起こしながら持続可能な利益を産む構造を作りましょうっていう普通の説明で良いと思った。

勝手に受け取った印象として、ストーリーという言葉は煌びやかな感じがしてて。ストーリーが大事だ!という言葉の奥にある有機的な項目の繋がりって本質が、見えにくくなると思った。

読書メモ

第一章

論理化とは事例を抽象化する行為である。 論理は抽象化されたものなので、自分たちのビジネスに取り込むには、自分たちのコンテキストに合わせて調整してあげる必要がある。 これはすごく真っ当で、ここが一番この本で良い点だと感じた。

テンプレートや既存の道具立ての否定的な表現が続くが、それはあくまで使い方の問題であり、道具がもつ本質的な問題ではないと感じた。 問題ってそこなんだっけ?となってしまった。

日本企業にとってストーリーで戦略を語るのは大切という話は理解できた。 ただ、これは日本の終身雇用の雇用形態が関わっており、今後もこの論理が通じるかは不透明に思う。

ストーリーを語ることは「意思表示」であって、未来予測ではない。 意思表示という点は共感する。

第二章

大前提として競争戦略と全社戦略は別物。

どこで戦うべきか?を考えるのは全社戦略。戦う場所が決まっていて、競合も見えている状況から考えるのが競争戦略。 ここを混同して扱うと変なことになるので注意が必要。

基本的にはシュンペーター型の競争環境において、ポジショニングもケイパビリティーも大事だよね。というお話。まあそうだよねそれは知ってたって感じ。 なので、競争環境によって、この議論が通用するかしないかは違うはず。 (page 138)でそれっぽいことが言われている。OCはSPの持続性に懐疑的な立場をとるというくだり

ストーリーの最終目標が持続可能な長期的利益と言っているのがまずややこしい。 持続可能な長期的な利益とか、シュンペータ型の競争環境においては目指すべきものではなくて、その瞬間瞬間で判断して、細かい勝利を繰り返していく必要がある競争環境であるはずである。 この本で言いたい持続可能な長期的利益というのはそういうレイヤーの話ではなくて、変化に対応していく能力自体を獲得しましょうとかそういうメタな話を含むものだと思う。

気合を「大切にする」と「依存する」は大きく意味が異なる。(page 108) これはほんとその通りで、いいこと言ったと思う。

第三章

ストーリーは業界の競争構造、ポジショニング、組織能力に続く、4つ目のもの。 やっぱりこういう位置付けでのお話だよな。 この話が最初にあればもう少し飲み込みやすかった。

ストーリは因果関係の強さや、因果関係の多さ、発展性などが大事。

あくまで事業の最初からストーリができている必要はなくて、活動の中で組み上がっていくものである。 それはそうだと思うけど、じゃあ実務的にどうしたらいいんや。この本から何を学びとれば良いのか?即物的なものを求めすぎているとは思うが、投げっぱなしもよくないと思うけどなぁ。。

ストーリーのゴールは長期的な利益とあるが、それってほんまに? 全社戦略レベルであればそうかもしれないけど、ここの事業レベルでこれが成り立つかは不明。 社会貢献活動とかもあるやんという感想。

第四章

単にモノを売っているわけではなくて、ほんとのところ、誰に何を売っているのか?が大切。 これをすると、誰がなぜ喜ぶのか?という視点。 これはほんとその通りだと思う。ジョブ理論で言ってることにも近しいかな。

(page 248)なぜ?がストーリーにとって一番大切。 わかりにくいけど、これが一番大事なのではこの本で。

第五章

クリティカルコア:ストーリーの一貫性の基盤となる、持続的な利益の源となる中核的な要素。 他の要素とたくさんの繋がりを持ち、一見して非合理に見えるもの。らしい。

非合理な要素なので、競合他社がこの部分だけを真似しても、効率が落ちて自滅していくような類のもの。 非合理を組み込んで、いかに全体としては合理的なストーリに仕立て上げるか?がポイント。

うーん。。。そんなものがあればいいんだけどなぁ。。それはどうやって見つけたらいいの?言ってることはそうなんだろうけど、示唆がない。 それできたら苦労しないよね感。

具体的な事例研究

についてはもう読み流すでいいかな。

スタバの例とか上がってたけど、最近のスタバには当てはまらないこともあった。 忙しい人にはスタバは嫌われる選択をして、それが全体的には合理的なんだみたいな発想なんだけど、スタバ、新大阪の駅構内にあるし、そのお店はテイクアウトが主流。 3rdPlaceとは?ってなるかな。

【機械学習のトピックス】TrainingLossよりValidationLossが小さくなることってたまにあるけどなんで?というお話

モデルの学習をしていて、TrainingLossよりValidationLossが小さくなることが稀に良くある。 これをどう説明解釈すれば良いか?という点についてちょっと悩んだ際に見つけたAurélien Geron氏のツイートをメモっておく。

はじめに

最近の実務の中でよく感じているが、モデルの学習(というか機械学習関連のコーディング全般に言えるが)について、アプリ作ったりする普通のプログラミングにはない難しさがある。 どういうことかというと、厳密には間違っててもなんとなくそれっぽく動いちゃうことが多いように感じる。

例えばTrainVal間でデータの漏洩があったり、データ前処理で意図していない動作になっていたりしても、コードは最後まで動く。 普通のプログラミングの文脈では、コンパイラが強力にサポートしてくれるので、大変助けられているが、その安心感が機械学習の際のコーディングの際には得られない。

そのため、限りあるデータから不具合の兆候を早期に掴むことはプロジェクトの成否に関わる問題で、神経を使うなぁと。。と感じている。

モデルの学習の際に起こる典型的な不具合として、過学習という問題がある。 これは、Trainingデータに強く適合することで、未知のデータに対する精度が劣化してしまうということであり、モデルを実世界で運用していく際に思ったような精度が出なくなるという問題を引き起こす。

この過学習を検知するために、モデルの学習に使うデータをTrainingデータとValidationデータという形で分割し、Validationデータはモデル学習には全く使わないようにした上で、定期的にモデルの性能をValidationデータを使って評価するといったことを行う。 もしもTrainingデータに対する性能は良いがValidationデータに対する性能が大きく劣化しているなどあれば、これは未知のデータに対する精度が劣化していることを意味し、過学習が起きていることを示す。

一般的に、モデルの学習においてはValidationの精度はTrainingの精度を超えることはない。 モデルはTrainingのデータに対して最適な推論結果を出すように学習するため、未知のデータに対する推論結果はこれを超えないと考えられるからだ。

つまり、過学習が起こっていない良い学習が行われたモデルでは、ValidationLossがTrainingLossに伴走するような挙動を見せる。

ここで、表題にあるように、ValidationLossがTrainingLossより良い精度を見せることが稀に良くある。

これをどう解釈していいのか?これはどっかに不具合があるのか?それとも正常だけどこんなことが起こるのか?について悩んだりしていた。

本題

色々調べたりしていたら、最終的に以下の一連のツイートに行きあたった。 詳しくは以下のツイートをたどって欲しいが、いくつか可能性として考えられるものがあるので、まとめる。

正則化手法による影響

正則化を目的としてDropoutなどを行っている場合、表題のような現象が起こることがあり得る。

Trainingの際には正則化を目的として、あえてネットワークのノードを確率的にDropoutして全体としてのロバスト性を高めることを狙う。この結果としてTrainingLossは劣化する。 Validation時には正則化は不要なため、Dropoutせずにネットワークの全力を持って推論を行う。 この結果としてValidationLossがTrainingLossより良いという結果を産む可能性がある。

あえてValidationLossの計算時にもDropoutを入れることで、TrainingLossとValidationLossが同じような値になるといったケースがあるようだ。

各Lossを計算するタイミングの差による影響

TrainingLossはEpochの途中で計算されるが、ValidationLossはEpochの終了時点で計算される。 当たり前のことだがEpochの中でモデルは成長するので、TrainingLoss計算時点とValidationLoss計算時点ではモデルの学習進捗が異なる。 この影響によってValidationLossが先行して精度が上がっているように見えることがある。

この影響を補正することでValidationLossがTrainingLossと同じような値になるといったケースもあるようだ。

データの取扱における不具合

TrainingとValidationのデータ分割の際の不具合によって表題の現象が起こることがある。 例えばTraininingに比べてValidationの方が簡単に推論ができるようなデータセットになっているなど。

また、Trainingデータの一部がValidationデータに流出している場合などでも同じような問題が発生する。

データ分割の際には本質的にTrainingとValidationが同じデータ群から抽出され、データセット間でこのような差異がないようにする必要があるが、これが達成できていないケース。 このままでは過学習が起きたとしてもそれに気がつけないので、これは是正する必要がある。

まとめ

ここまで見てきたように、表題の現象はさまざまな要因によって発生しうる。 場合によっては複雑な事情が組み合わさり、TrainingLossとValidationLossがそれぞれ想定通りのいい感じに見えていたとしても、過学習が起きてしまっているようなことも起こりうる。

データの流出はないか?TrainingとValidationの計算タイミングのズレによる影響は?正則化によってTrainingLossが見かけより劣化してみえる事による影響は?など気をつけて評価していく必要がありそうだ。

なぜ「やる気」は長続きしないのか

読んだきっかけ

物事を継続して続けて、成功するってことにはもちろん興味があって、何度もトライはしているけどなかなか続かない。 やる気って物が長続きしない。

感想

意志力に頼った「やる気」がなぜ長続きしないのか?ということと、では自制心を発揮するためにはどうしたらいいか?という内容について、様々な実験結果を交えて教えてくれる本だった。

筋トレやら読書やら、英語学習やら資格勉強やら、色々とチャレンジしては挫折してを繰り返しているので、じゃあどうしたら継続できるんだろうという興味で読み進めたので、楽しめた。

多かれ少なかれ誰でも目標立てて挫折した経験なんてあるだろうし、もしもその際に「意志力」を使ってなんとか継続しようとしていたとしたら誰にでも刺さる内容なんじゃないかなと思う。

飛ばし読みしたので理論的に全てが繋がっているのかは謎なところもあるが、何よりここで言われている通りだったら嬉しいなと感じている。

読書メモ

ポイントとしては、理性で自制心を無理やり発揮しようとしても、最初はうまくいったとしても破綻する可能性の方が高いので、もっと視点を変えて自制心を発揮できるようにしようという感じ。

特に将来のために自制心を発揮しようとすると、人は将来得られる価値を低く見積もるので、遠い将来であればあるほど今得られる快楽に価値が及ばず、挫折しやすい。

これに対して特定の感情を抱くと、その時点での価値観が未来志向に変わるため、将来得られる価値を低く見積もる傾向を緩和することができ、自制心を発揮しやすくなる。

この特定の感情は「感謝」「思いやり」「誇り」の3つで、これらは進化の過程で人間が得た社会性を成り立たせるための感情である。

アクションプラン

マインドフルネス瞑想の練習は最近アプリを使って初めたので、継続したい。

Meditopiaというアプリを使っている。 https://apps.apple.com/jp/app/meditopia-%E7%9E%91%E6%83%B3-%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%89%E3%83%95%E3%83%AB%E3%83%8D%E3%82%B9-%E7%9D%A1%E7%9C%A0/id1190294015

それと誇りを高めるために、自分が目標に対して前進していることを把握することが効くらしいので、ちょっと前まで続けていた個人日報も復活させたい。