2024年4月

育児

3 歳 5 ヶ月になった。

  • 新しい園に初登園
    • 初日は割とすんなりいった
    • 3 日目はギャン泣き
    • 先生方のフォローもありなんとか最初の 1 週間は乗り切れた
  • 親戚(オレのいとこ)の家に遊びにいった
    • 2 歳の男の子と遊んだ
    • 2 人ともちゃんと会話して遊んでて感動した
      • もともと息子氏は誰かと遊ぶというより誰かの遊びを真似たりする派
    • 大好きなピザもあまり食べずに遊んでた
    • 帰りは特にイヤイヤもなくバイバイ(ずっとそう)
  • 隣の市の公園に桜を見に行った
  • 遊び場もあって砂遊びと滑り台を楽しむ
  • 今年も家族みんなで桜みれて良かった
  • YouTube 見れなくてギャン泣き
    • ほんとごめんパパママのせいだ。。
    • このままだとお互い依存しそうだからどうにかせねば
  • 汗をかくほど鼻水を垂らすほど集中してニューブロックで立体駐車場をつくる
    • ほんとすごいパパママは殆ど手を貸していない
    • その日の夜はすぐに寝た
  • おしっこ我慢できるようになってきた
    • ほとんどトイレでできるようになった
  • 初のママチャリで登降園
    • 初めはテンションあがってた
    • チャリで公園いったり踏切みたり旅したり
  • 初めて中古のおもちゃ買った
    • ニューブロック
    • 大事に使ってたんだなぁと感慨深い気持ちに
  • お友達に一緒に遊ぼうと言われて「いいよー!」と快諾
    • ケンカしてると「ケンカしないでー!」と言う
  • 初バスケ
    • 同僚に抱っこされてシュート決める
  • じゃがりこ好き
  • フルグラにハマる
  • 機嫌が悪いと「もうやだ!」「もうしらない!」「ふん!」
  • チャリで通園中に靴が脱げる
    • どうやったら脱げるんだ
    • 無事回収

4 月!新しい保育園での生活がスタートした。最初はイヤイヤだったけど最近は楽しんでそうでよかった。家から近くなったので車通園から自転車での通園に切り替えた。新しい園では、自分のことはなるべく自分でやるようにという方針っぽいので、お家でもできそうなことは「やってみる?」というように心がけた。トイトレも頑張ってるしお着替えも上手になってきた。偉い!

仕事

  • バックエンドのバリデーション設定たくさんした
    • field_validator と model_validator 便利
  • 本番環境の構築
    • 環境依存な処理を整理してリファクタしたり
  • 既存のクラスを Pydantic の BaseModel を継承するようにした
    • 今まで出ていなかった型エラーを検知できた

その他

  • TL で見かけた『他者と働く』を購入した
    • まだ読みかけだが、人間関係で起きる課題を "適応課題" と位置づけ、それをいくつかの種類に分類して説明されていてとてもわかりやすい

publishing.newspicks.com

Pydanticでバリデーションをスキップして任意のタイミングでバリデーションする

FastAPI で API を開発していて「リクエストを受けたタイミングではバリデーションはせずに別のタイミングでバリデーションをかけたい」といった要件があり、苦戦したので纏めておく。

前提

  • Python 3.11.3
  • Pydantic 2.6.4

SkipValidation

SkipValidation でバリデーションをスキップすることができるが、任意のタイミングでバリデーションを実行しても Warning は出力されるもののバリデーションエラーとはならずスキップされる。シンプルにバリデーションをしたくないケースにはマッチする。フィールド単位で指定する必要があるため、フィールド数が多かったりネストされたモデルの場合はコード量が増え見通しが悪くなりそう。

from pydantic import BaseModel, SkipValidation


class Item(BaseModel):
    name: SkipValidation[str]
    price: SkipValidation[float]

m1 = Item(name=1, price="foo")
print(m1)  # -> name=1 price='foo'

m1.model_validate(m1.model_dump())  # ->
# /path/to/pydantic/functional_validators.py:702: UserWarning: Pydantic serializer warnings:
#   Expected `str` but got `int` - serialized value may not be as expected
#   function=lambda v, h: h(v), schema=original_schema
# /path/to/pydantic/functional_validators.py:702: UserWarning: Pydantic serializer warnings:
#   Expected `float` but got `str` - serialized value may not be as expected
#   function=lambda v, h: h(v), schema=original_schema

docs.pydantic.dev

docs.pydantic.dev

model_construct

model_construct メソッドを利用することでやりたいことが実現できた。

from pydantic import BaseModel


class Item(BaseModel):
    name: str
    price: float


m1 = Item.model_construct(name=1, price="foo")
print(m1)  # -> name=1 price='foo'

m1.model_validate(m1.model_dump())  # -> ValidationError

デメリットとしては以下が挙げられる。ドキュメントに記載されている通り、バリデーション済みのデータ、信頼できるデータにのみ利用した方が良い。

  • フィールドを指定する際にエディタ補完が効かない
  • フィールドで定義していないものを指定できる
    • 例: Item.model_construct(name=1, price="foo", bar="bar")
  • バリデーションされていないデータのため後続で DB に INSERT するといった場合に型の不整合が発生する可能性がある
  • meta: MetaModel といったネストされたモデルがある場合はコード量が増え見通しが悪くなる
    • 例: Item.model_construct(name=1, price="foo", meta=Meta.model_construct(author=1))

docs.pydantic.dev

docs.pydantic.dev

おわりに

Pydanticでバリデーションをスキップして任意のタイミングでバリデーションする方法を紹介した。 この方法はあまり推奨されることではないため、プロダクトの要件に左右されると思うが本当にバリデーションをスキップする必要があるのかを考えたほうが健全。

2024年3月

育児

3 歳 4 ヶ月になった。

  • あかちゃんのことを「あかちゃま」という
  • 久々のなんでもイヤイヤ
    • バナナジュースで止んだ
  • 久々の胃腸炎でめちゃ吐いた
    • 泣くほど辛いとかではなさそうだけど医療センターで診てもらった
    • 下痢はなくて嘔吐だけ(むしろ便秘気味)
    • 朝ごはんのトーストが食べられなくて涙ポロリ
      • 一気に食べるとよくないので生食パン少しあげたら静かに泣いた
  • 友達家族が遊びに来た
    • 北米仕様っぽいランドクルーザープラドのおもちゃもらった
    • トーマスのおもちゃ貸して IKEA のリラブーぶつけられてギャン泣き
    • 皆でカレー食べた
  • 麻婆豆腐をご飯と一緒に食べると美味しいことに気づく
  • 会社の先輩に会いにいった
    • 持っていったさつまいもとサンドイッチとラスクを外で食べた
    • 先輩にもあげた
  • お別れ会に参加した
    • ママどうしの懇談会があってママたちは泣いていたらしい
    • オレもお別れ会で歌を歌っている皆を見て泣いてしまった
    • 息子氏含めみんな人前で立派に話してすごいと思った
      • 好きな食べ物はりんごらしい(初知り)
    • 大好きなお友達と写真とれた
    • 写真のスライドショーも見れた
  • 最後の登園
    • お迎えはパパママふたりでいった
    • 先生方のメッセージと写真が綴られたブックをもらった
      • 大事にしたい
  • ママがもらったお花をクンクン嗅ぐ

ついに卒園してしまった。。2 年間本当にお世話になりました。この園で息子氏はとても成長したと思うし、パパママもたくさん勉強させてもらった。 転園先も良い園だから楽しんでくれるといいな。元の園にはまた遊びにいきたい。

仕事

  • フロント/バックエンドのバリデーションを実装した
    • Pydantic のバリデーション楽
  • Pydantic のメジャーバージョンアップ(1 系 -> 2 系)した
    • ほとんど Migration script で更新できたのですんなりいった
    • Model の数が多くて差分が 5000 くらいあってレビュー大変だったと思う..
    • 特に大きな問題もなく進んでよかった
    • バージョンアップによってバグが発覚する副次的な効果もあった
  • 江の島でワーケーション
    • フリスビーもってって皆でやった楽しかった
  • タスクの文脈を読み違えてとんちんかんな変更をしてしまって手戻りが発生した
    • 「たぶんこうすればいいだろう」という曖昧な理解のまま実装を進めたのがよくなかった
    • 詳しいメンバーがいるので早いタイミングで相談しておけばよかった

その他

  • 「Effective Python 第2版」を購入した
    • ちまちま読んでいきたい

www.oreilly.co.jp

2024年2月

育児

3 歳 3 ヶ月になった。

  • 「あ、そうだ!おもいついた!」という
  • 雪に大興奮
  • 七五三の撮影でノリノリ
    • パパママは別部屋で待機
    • スタッフさんありがとうございます
    • めちゃくちゃ良い写真だった
  • 選挙で小学校いってついでに遊んだ
    • 同じマンションに住む家族と遊んだ
    • 息子氏うんていぼうに1人でのぼってぶら下がって落ちた
  • 歯医者さんノリノリ
    • お友達が隣でギャン泣きしてても気にしていなかったらしい
  • 寝室で就寝する時に足でパパにかかと落とししまくる
    • 辞めてといっても辞めなかったから何も言わず寝室でてリビングに行った
    • そしたらスンスンしながらママとリビングきた
    • 大丈夫だよって言いながら抱っこして寝室戻ってしばらくスンスンしてたけど寝た
  • ささいな傷で絆創膏はりたがる
    • お風呂で取ったらその痛さでギャン泣き
    • その痛さでまた絆創膏をはり。。の無限ループ
  • 転園先の保育園に面談にいった
    • 先生方よさそうで安心
    • ただ今の園の方が最高
    • 園長先生はママにしか話してない感じだった悲しみ
  • ロマンスカーミュージアムにいった

今の保育園もあと 1 ヶ月..楽しむぞい!

仕事

  • Amplify Authenticate と格闘した
    • Cognito と外部 IdP との連携設定など
  • 外部システムとの接続テストに励んだ
    • やはり curl コマンドは偉大
  • フロント関連のタスクを意識して対応した
    • デザイン修正やボタンの onClick から呼ばれる関数の作成/修正など
    • 詰まったときはメンバーにモブプロを申し込んだ
    • 不明点は踏み込んで質問した
  • バックエンドのリファクタやパフォーマンスチューニングすすめた

その他

  • しずかなインターネットはじめてみた
    • 『Web配信の技術―HTTPキャッシュ・リバースプロキシ・CDNを活用する』とても良い
    • 早速業務に活かせた
  • Python 関連の薄いエントリ書いた

sizu.me

enokawa.hatenablog.jp

enokawa.hatenablog.jp

【Python】filter関数入門

業務で filter 関数を使うことがあり、まだ理解が足りない点が多いのでアウトプットして知識を深めていく。

docs.python.org

filter 関数とは

Python の組み込み関数の 1 つで、import 文不要で動作する。構文は filter(関数, イテラブル) であり、イテラブルを関数に渡して真だった場合の要素からイテラブルを生成する。for 文を使わなくてもよい。

>>> def f(item):
...     return item == 1

>>> list(filter(f, l))
[1]

filter 関数の返り値の型は filter 型となる。以前書いた zip 関数とは違って遅延評価ではなく、変数に代入して処理することも可能のようだ。配列で返してほしい場合は list でラップするするとよさそう。

>>> value = filter(f, l)
>>> print(value)
<filter object at 0x1052eb1f0>
>>>
>>> type(value)
<class 'filter'>
>>>
>>> list(value)
[1]

enokawa.hatenablog.jp

filter 関数はジェネレータ式というものやリスト内包表記と同等の動きをするらしい。

>>> list((item for item in l if f(item)))
[1]
>>> 
>>> [item for item in l if f(item)]
[1]

なお、filter(function, iterable) は、関数が None でなければジェネレータ式 (item for item in iterable if function(item)) と同等で、関数が None なら (item for item in iterable if item) と同等です。

https://docs.python.org/ja/3/library/functions.html#filter

今関わっているプロジェクトは filter 関数の第 1 引数で指定する関数にラムダ式を用いていた。

>>> list(filter(lambda x: x == 1, l))
[1]

雑感

そろそろ Python 3 年生だが、list 関数や zip 関数、filter 関数やリスト内包表記はまだ読みづらいと感じる。頭がごちゃってしまう。ただこれは Pythonic 思考に反する気がしているので慣れが必要だとも思っている。どんどん書いていこう。ただ参考にした記事だと filter 関数よりもリスト内包表記やジェネレータ式を使った方が好ましいとの記載があったので、また調べてアウトプットしようと思う。

参考

note.nkmk.me

【Python】zip関数入門

業務で zip 関数を使うことがあり、まだ理解が足りない点が多いのでアウトプットして知識を深めていく。

docs.python.org

zip 関数とは

Python の組み込み関数の 1 つで、import 文不要で動作する。複数のイテラブルから tuple を生成する。

>>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
...     print(item)
...
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')

zip 関数の返り値の型は zip 型となる。また zip 関数は遅延評価のため、変数に代入して処理されることはないようだ。基本 for ループ内で処理したり list でラップする必要があると考えた方がよさそう。

>>> value = zip([1, 2, 3], ['sugar', 'spice', 'everything nice'])
>>> print(value)
<zip object at 0x104d2d7c0>

>>> type(value)
<class 'zip'>

>>> dict(value)
{}

zip() は遅延評価です: イテラブルが for ループに渡されたり、 list でラップされたりするなどして反復処理されるまで、要素が実際に処理されることはありません。

https://docs.python.org/ja/3/library/functions.html#zip

Key-Value な形に加工することもできそう。

>>> for k, v in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
...     print(k, v)
...
1 sugar
2 spice
3 everything nice

>>> dict(zip([1, 2, 3], ['sugar', 'spice', 'everything nice']))
{1: 'sugar', 2: 'spice', 3: 'everything nice'}

イテラブルってなんだっけ

以下の記事が参考になった。list や tuple を使うケースが多そう。

qiita.com

zip 関数で渡されたイテラブルの要素数が異なる場合の挙動

第 1 引数の要素数は 4, 第 2 引数の要素数が 3 の場合、第 1 引数の 4 番目の要素が無視される。

>>> for item in zip([1, 2, 3, 4], ['sugar', 'spice', 'everything nice']):
...     print(item)
...
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')

逆に第 1 引数の要素数を 3, 第 2 引数の要素数を 4 とした場合、第 2 引数の 4 番目の要素が無視される。

>>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice', 'bad']):
...     print(item)
...
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')

これはドキュメントに記載の通り。

デフォルトでは、 zip() は最も短いイテラブルが消費しきった時点で停止します。より繰り返し数の長いイテラブルの残りの要素は無視して、結果を最も短いイテラブルの長さに切り詰めます:

https://docs.python.org/ja/3/library/functions.html#zip

素数が異なる場合はエラーとさせたい場合は strict=True オプションを付与することで ValueError を 出すことができる。

>>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice', 'bad'], strict=True):
...     print(item)
...
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: zip() argument 2 is longer than argument 1

参考

note.nkmk.me

2024年1月

育児

3 歳 2 ヶ月になった。

  • 「違うか」と言う
  • 親戚の結婚式で沖縄に帰省した
  • 口臭いと言うと悲しむ
    • ごめんよ。。
  • パズルが上手
  • 従姉妹の結婚式で帰省した
    • 飛行機は全然余裕
    • ゆいレールに乗って楽しそうだった
    • 何も遊ぶものがなくメインプレイスでトミカ調達
    • 結婚式は服を着てくれず肌着で乗り込んだ
      • りんごジュースを飲ませて着せた
  • パンと一緒に親指を噛んでギャン泣き
  • 「はい」の返事が上手

仕事

  • Amplify と格闘した
    • 既存 Ampilfy をインポートするのに苦戦した
    • 複数 AWS アカウントにまたがって Amplify をコードで管理するのに苦戦した

その他

  • Findy さん主催の t-wada さんのイベントに参加したとてもよかった
    • 生々しい話が聞けたしレガシーコードをどう改善していくのかのプロセスが参考になった
    • t-wada さんの引き出しの広さがすごい(語彙力)
  • HTTP を完全理解したいので『Web配信の技術―HTTPキャッシュ・リバースプロキシ・CDNを活用する』を購入した

findy.connpass.com

gihyo.jp