Pythonのimportの仕様を確かめる

お仕事中に話題になったもので。

mod1.py

def func1():
    print('mod1.func1 called')

print('mod1 imported')

main.py

from mod1 import func1 
from mod1 import func1 
func1()

結果

mod1 imported
mod1.func1 called

ですね。importを複数回行っても、最初の時にpycacheが作られて2回目はそれが使われますね。これはいいんですよ。

次に、以下のmod2.pyを足して、

mod2.py

def func1():
    print('mod2.func1 called')

print('mod2 imported')

main.py

from mod1 import func1 
from mod2 import func1
from mod1 import func1 
func1()

結果

mod1 imported
mod2 imported
mod1.func1 called

これが今回試したかったケースなんですが、まあ予想通りでしたね。読み込み直す時でもpycacheが使われる。まあ、そりゃそうですね。

そしてさらに、以下。

mod3.py

def func1():
    print('mod3.func1 called')

def func2():
    print('mod3.func2 called')

print('mod3 imported')

main.py

from mod3 import func1
from mod1 import func1 
from mod3 import func2 

func2()

結果

mod3 imported
mod1 imported
mod3.func2 called

まあ、別に代わり映えのしない結果になりました。面白くなくてすいません。つまり、from〜importで一部だけをimportしたつもりでも、ちゃんと全部丸ごと読み込まれていて、from〜importに書かなかった要素もpycacheから持ってくるしくみになっているよ、ということでした。

実際には、これがif文の中に書いてあったせいで、HTTPリクエストのたびに叩かれることになり、無駄に動的なimportがたくさん走るんじゃないの、それって大丈夫なの、みたいな話の流れでした。特に、そういう意味では問題はなさそうですね。ただまあ、必要もないのに関数の中でimportせんでくれよ。それでなくともわしゃ忙しいんじゃ。それではまた〜

みんなのキャッシュになったり検索基盤になったりプロキシになったりしています

プロジェクトリーダーという役割のことです。もう何ヶ月もコードを書かず、仕様も決めない、という状態が続いています。大切な役割だという自覚があっても、ずっとこの仕事ばっかりやるのはちょっといやかもな、いや、まあこれはこれで面白い部分もあるけどな〜みたいな気持ちになっています。

コーディングは協力会社、コードレビューもチームメンバーなのでソースコードをほとんど見ません。そしてプロダクトオーナーは別にいるので、仕様は決められません。本当に彼らが行う作業以外のことをする雑用係です。否定的なニュアンスはありません。雑所得みたいなものです(あれ?あんまり肯定的じゃない?)。膨大な情報を整理する係という感じでしょうか。プロジェクト自体もそうですし、社内の他のプロジェクトとの調整がめちゃくちゃ多いので、やることはあるんですよね。というか最近大変すぎます。何も生産的なことはしないまま、時間がどんどん溶けていくイメージでした。プロジェクトの最初の頃は。

しかし途中で考えが変わってきました。システム構成でいうと、わたしはキャッシュであり、検索基盤であり、プロキシなんだな、と。大規模システムには欠かせない存在です。実際やっていることはそうなんですよね。情報を集約して、ビジネス側からのロジックレベルの質問に答える。実装側からの業務や要件についての質問に答える(キャッシュヒットすれば)。スケジュールに限らず、業務情報の一覧を整理しておいて共有して、情報の流れをスムーズにする(Elasticsearchの気分)。ビジネス側からの提出仕様をチェックしてOKなものだけを実装側に渡す、実装側のトラブル報告からビジネス要件に関わる部分だけをフィルターして報告する(プロキシ、と言いつつ間違えて不適切情報をときどき通してしまうこともありますが)。もう少しプロジェクト全体が大きくなると、現在のわたし自身の役割も分割されることでしょう。というか普通はキャッシュサーバと検索基盤サーバとプロキシが単一の物理サーバにいるわけない。

以前から感じていてこのブログにも書いた気もしますが、ソフトウェアエンジニアとしてプログラミングを行うことと、マネージャとしてチームを機能させることは個人的には全然違うことだと思えないんですよね。少なくとも、わたしにとってやりがいがある部分は全く同じです。部品もしくは自律的な要素の、関係性をコントロールして目的を果たす、という点です。だから、どちらかがどちらかを毛嫌いするのは勿体ないなあと思うわけです。そして、プログラミング好きがマネージメント能力をつけたいときは今回のアナロジーが使えるのでは、とも考えます。逆に、ITについてよく知らない人にシステムを説明する場合は上記のような擬人化だと下手なたとえよりうまくいくはず。要するに、システム構成とエンジニアチームは本当によく似ていると思うんですけどね…わたしだけですかね?

「人に頼む技術」をだいぶ読んだ

ironoir.hatenablog.com

まだ読んでいるのか、と言われそうですが、まだ読んでいます。大部分を読んでみて、そして少し具体的なことなどと絡めて思うところなどを。

前も書いた気がしますが、ソフトウェアエンジニアなんて、他人と協調するのが苦手な人間の方が大多数に決まっている、などとあえて暴言を吐いてみます。わたしなども例に漏れず。技術を自己顕示の手段にしようとしてしまうわけですね。もうすこし他のものを使えばいいものを、よりによってプログラミング周辺技術とかに興味を持ってしまったばっかりに、何かと恥の多い人生を送ってきました(急に太宰)。

さて、そんな私も歳を取り、ようやく考え方が変わってきたようには思っていたものの、最後に突破できないいくつかの壁がありました。そのひとつが役割分担の話。特に、自分が抱えている作業を自分の都合(それは実力不足を含みます)で他人に明け渡すことへの抵抗感。だからこそ、今回の「人に頼む技術」は噛み締めるようにゆっくり読んでいるのかもしれません。

こういうハウツー本は正直なところ、なんだか思っていた感じの内容を与えてくれないことが多い気がしていました。あまりにも単純化されすぎていたり一般化が過度なせいで誰にでも当てはまるけど毒にも薬にもならない内容だったりするか、書いている本人のエゴが強すぎたり独自の経験をただ語っているだけでこちらが活かせる部分が見当たらなかったり。その意味では、この本はずいぶんと珍しい読後感(まだ読み切っていませんが)です。つまり、普通に役に立ちそうです。

人に頼む時の具体的な方法が書いてあるんですが、妙に刺さります。個人に向かって直接頼むこと、そして助けてもらうと嬉しいと表明すること、相手にとって妥当な量の助けを求めること、そして最後に求めていたのと違う助けが来ても、それを拒まないこと。とにかく、徹底的に「助けを求められる側」の視点に立って、どのようにすれば助ける側が助けやすいか、ということがわかりやすく書いてあります。

これだけでもめちゃめちゃありがたいんですが、さらに「良くない頼み方」に関しても書いてあります。個人的にはあまりにも身に覚えがありすぎて震えたよ実際。書き写してみよう。「やたらと謝る」「言い訳をする」「その頼み事は些細なものだとアピールする」「借りがあることを思い出させる」…やばくないですか、このラインナップ。本当に普段、やってしまっています。しかも、自分の気まずさを打ち消すために。反対に自分がされたときには少しサムい気持ちになることも知っているはずなのに、自分の中の羞恥心が耐えられないわけですね。今はどうしても他人にものを急に頼む立場なので、さっそく上記のコツ、特に「よくない頼み方をしない」ということでがんばりました。

あともう少し、噛み締めながら読みます。

ソフトウェアエンジニアとお笑い芸人

最近はプログラミングスクールのCM動画をよく見かけます。業界の外の知り合いから話を聞かれることもたまにあります。でもわたしには、全然その界隈の知識もないし、調べようという気にもならないんですよね。すでに自分が長いこといる業界に新しい風が吹いている、と解釈すると、なんとなく、もうすこし興味を持った方がいいのかな、とも思うんですが、どうにも直感的には距離が遠く感じるわけです。誰かがTwitterでつぶやいていたような気もしますが、我々のようなひとたちは、教育機関で体系的に教えてもらえる機会は少なくて、現場で独学でやってきて生き残ってきた人たちなわけです。実際の現場でしかわからないことや、プログラミングやシステム開発を、お仕事としてやる場合に特有の事情や、業務知識なんかは余計にその傾向が強いです。

ただ、できる限り客観的に状況をみてみると、ついにこの業界がコモディティ化しようとしていることかもしれない、とも思える気もします(いや、心の底では信じていないし信じたくないんですが、わたしが信じているかどうかと実際の傾向は別の話なので)。プログラミングスクールみたいなものが整備されるのであれば、それは業界全体の技術力向上に寄与する可能性も、まあ、なくは、ないような、気がしないでも、ないですよね(弱気)。ただ、プログラミングって単純作業ではないので、そんな風に事業を行っているプログラミングスクールは本当にビジネスとしては旨味が少ないようにも感じますが、ビジネスの素人からはこれ以上言うことはありません。

いつも思い浮かべてしまうのが、お笑い業界なんですよね。業界全体ではないにせよ、業界最大手の吉本興業NSCというスクールを作ってもう長い歴史があり、そこから芸能界で活躍するお笑い芸人がとくもかくにもたくさん排出されているわけです。これは全くの想像ですが、NSCができた当初はもともといた芸人さんたちには抵抗があったんじゃないかな、と思うわけです。「芸事は師匠の背中を見て学ぶもんだ」みたいな感じですかね。プログラミングスクールの存在にまったく親近感を覚えないどころか一種の抵抗感があるのは、これに似ているのかもしれない、と思うわけです。

お笑い芸人の絶対数や業界慣習の違いはあるのであまりにも雑な比べ方だという自覚はありますが、抽象化するなら、方法論の俗人化排除がキーワードですかね。その志には共感するし、プログラミングスクール事業を行う各社にはぜひIT技術者の実践力底上げを図って欲しいとは思うものの、まだ本当に未知数ですね。何年か後にはブームも去って、その時点での状況がむしろ健全な状態なんだろうな、という予測は持っています。

あと、よく見かけるのは、技術好きじゃないやつに業界に入ってきてほしくない的なご意見でしょうか。この点ではあまり共感できないんですよ。私自身はめちゃくちゃ技術好きなやつですが、別に意識が高いわけでも志が立派なわけでもなく、単に好きなだけなんですよね。すでにこの業界には技術好き以外の人間はわんさか存在しているわけで、上記の発言を見ると、そういった方々と仕事をせずに済んでいるということならば羨ましい限りです。そうでないなら、今回のタイミングでの発言はマトを外していると言うか、単なる愚痴にしかならないと思います。

個人的には職業訓練コスパ面でもお勧めすることが多いんですが、まあ、時間と共にプログラミングスクールの功績や課題が炙り出されてくるでしょう。

Algebraic property graphの定義

ironoir.hatenablog.com

221日前、と聞くとずいぶん昔のようにも感じますが、Algebraic property graphについて書いています。とはいえ見直してみると具体的な中身にはあまり言及していないみたいなので、踏み込んでみます。

論文については上記の記事からもリンクを貼っていて誰でも見られるので参照いただければと思います。

f:id:ironoir:20210306124732p:plain

Algebraic property graphを端的にイメージするためには上の可換図式がよいかと思います。上記、それぞれの頂点は集合で、矢印は写像です。

• a set 𝐺(L), the members of which we call the labels of 𝐺; and,

• a set 𝐺(T), the members of which we call the types of 𝐺. Each type 𝑡 is a term in the grammar: 𝑡 ::= 0 | 1 | 𝑡1 + 𝑡2 | 𝑡1 × 𝑡2 | Prim 𝑝 (𝑝 ∈ P) | Lbl 𝑙 (𝑙 ∈ 𝐺 (L)) where we may omit writing Prim and Lbl when they are clear from the context; and,

• a set 𝐺 (E), the members of which we call the elements10 of 𝐺; and,

• a set 𝐺 (V), the members of which we call the (typed) values11 of 𝐺. Values are terms in the (typed) grammar: 𝑣:𝑡 ::= ():1|inl𝑡2(𝑣:𝑡1):𝑡1+𝑡2 |inr𝑡1(𝑣:𝑡2):𝑡1+𝑡2 | (𝑣1,𝑣2) :𝑡1 ×𝑡2 |Prim𝑣𝑡:𝑡 (𝑡∈P,𝑣∈V(𝑡)) |Elmt𝑒:𝐺(𝝀)(𝑒) (𝑒∈𝐺(E)) where we will omit type information, and Prim and Elmt, from values when they can be inferred from context; and,

論文の文面をうまく持ってくることができず申し訳ないですが、L、T、E、Vの4つの集合があり、それぞれLabel、Type、Element、Valueの集合です。ざっくりいうとLabelとTypeは「スキーマ」側です。一方でElementとValueは「インスタンス」側ですね。

LabelとTypeは何が違うのか。まずTypeは、元になる「プリミティブ」の集合と、あとは0と1という2つの型しか持っていません。その代わり、それらは代数的データ型を作ることができます。

f:id:ironoir:20210306130348p:plain

そしてLabelはそれを指し示す「型の名前」ですね。同じ1でも、それぞれ違うLabelをつけることができます。別の言い方をすると、structural typingではなくてnominal typingなわけですね。実際の例でも、他のプログラミング言語だとenumにあたるものを作るときにそれぞれの要素に別のLabelが与えられています。

ElementとValueの関係は、雑にいうと、変数と値だと思うと楽かもです。

定義には上記の4つの集合を結ぶ写像も定義されていますが、要するにそれらが可換であることが定義に含まれています。

𝐺(𝝉)◦𝐺(𝝊) =𝐺(𝝈)◦𝐺(𝝀)

ということで、これを使って多様なグラフ構造を型を付けた状態で表現できる、しかもそれらのグラフ同士の演算が定義でき、Algebraic property graph全体が圏とみなせるという話につながっていきますが、長くなりそうなのでいったんここまで。

型のことを知りたい

ironoir.hatenablog.com

昨日はこんな記事を書いたものの、全然知識がないなあ、もしくは忘れ去っているなあ、ということで関係しそうな本を探してみることにしました。

まず、ドンピシャ(死語)なやつがありました。

booth.pm

よく考えたら、分厚いわけでもないのに読んでいなかったので、目を通しました。これ、コンパクトにまとまっていていいですね。推論規則に目が慣れたのか、抵抗感なく読み進められたし、一回自分で作ろうとしたのでHaskellでの実装もずいぶん理解度が違いました。これはこれでそのまま何か作ってみたくなります(すぐにそうやって横に流れようとするのが悪いクセ)。

で、参考文献に挙げられていた、というか挙げられていなくても有名な本が次。

www.saiensu.co.jp

なぜかこの本、わたし同じものを2冊持っているんですよね(普通に間違えて買っただけです)。導出システムの説明から入っていってML的な言語に意味論を与えていく構成。実装に関しては特に書いてあるわけではありません。やはり訳書ではないのもあるし説明もわかりやすい。

というわけで触れないわけにもいかないので、TaPLです。あれ、表紙をよく見てみるとTAPLって書いてるなあ。なんとなくTaPLという表記で覚えてしまっているけど、まあいいか。

www.ohmsha.co.jp

最初に読んだのはいつだろう。。。ワクワクしながら3章まで読んで、そのあと急にわからなくなって(というか追うのがめんどくさくなって)一気に最後まで飛ばし読みしたのは覚えています。OOのクラスは関数だけで表せるんだよ、とか再帰的な型の話とか、そもそも型システムのラムダキューブ(ですよね確か)を初めて知ったのもこれだ。しかもこれ、インターネットじゃなくて本屋で全然違う本を探していて、「かっこいい表紙だな」と思って手に取ったのがきっかけだったんですが、今思うと我ながら素晴らしい嗅覚ですね(それ以前に情報を広く集めるべき)。同じパターンで後から名著だったと知った本には、SICPがあります。もともと専門外なので、それぐらい知らないんですよ、いくら界隈では有名でも。

あとは、形無しラムダ計算を自分で一回作ってみて、6章に出てくるde Bruijn indexも実装してみた記憶があります(もはやいつだっけ…)。めちゃめちゃ脳汁出たなあ。WebAssemblyの処理系ができたら上に乗せてみたいなあ。と、夢が膨らみます。

いまだに独学で不定期に勉強しているだけですが、それでも少しずつ、じわりじわりとわかることが増えていっているようです。引き続き、やります。

型変数をどう表現するか

ironoir.hatenablog.com

WebAssemblyのValidationを実装しています。初めてで拙いながらも実装方法を考えているところです。WebAssemblyの命令のうち、一部はpolymorphicなものがあって、value-polymorphicな命令とstack-polymorphicな命令があります。stack-polymorphicな命令に関しては以下でとりあげました。

ironoir.hatenablog.com

今回はもう一つのvalue-polymorphicな命令がテーマです。こちらは割と馴染みのある感じのpolymorphismという感じで、要するにジェネリクスですね。例えば、select命令では以下のようになっています。

f:id:ironoir:20210304125628p:plain

この場合、tに(全体がvalidになるように)任意の型が入ります。最初はもともとある型定義にAnyを付け足して、これで凌ごうと思ったんですが、これだと上記のselect命令だと、「tには同じ型が入るんですよ」という情報が抜け落ちてしまいます。

enum ValType {
    Any, // add
    I32,
    I64, 
    F32,
    F64,
}
// instr_tp!は今回型宣言を簡単に書くためのマクロです
instr_tp!(Any Any I32 -> Any)

// でもこれだと
// instr_tp!(I64 F32 I32 -> F64)
// とかでもOKになってしまう

せっかくなのでちゃんと作るとなるとどうなるんだろう、と考え始めました(一方で、polymorphicな命令は全体の中では少数なので、おしごとだったらアドホックなコードを書いて終わらせるやろな、とも思いつつ)。

enum ValType {
    I32, I64, F32, F64,
}

type ResultType = Vec<ValType>;

type FuncType = (ResultType, ResultType);

もともと、関数型FuncTypeの定義は上記のように作っていました。これはWebAssemblyの仕様書に忠実な実装だと思います。ここに型変数を導入する、ということですね。

うーん、ざっくり思いついたのだと、こんな感じですかね?

enum ValType {
    I32, I64, F32, F64,
    TypeVal(TypeValIdx),
}

type ResultType = Vec<ValType>;

type TypeValIdx = u32;
type FuncType = (Vec<TypeValIdx>, ResultType, ResultType);

関数単位でジェネリクスを持てればいい(select命令が例)ので、関数に型変数のVecを持って、それをValTypeの中に足す、ということでしょうか。インデックスはu32ですがなんでもいいです。実際にはここにstack-polymorphicな命令への考慮も必要になってくるので、ResultTypeにも変更が必要ですが、それは今回は省きます。これで一回書いてみましょう。