歩いたら休め

なんでこんな模様をしているのですか?

numpyの型ヒントをnptypingで付けよう

stackoverflowのNumpy type hints in Python (PEP 484)という記事で nptyping というライブラリが紹介されていました。

import numpy as np
from nptyping import Array

def foo(array: Array[np.float64]) -> str:
    ...

また、shapeも含めて指定できるようです。ただし、現時点でmypyなどでshapeも含めてチェックすることはできず、あくまで実行時にisinstanceでチェックする、もしくは可読性のための記述するために用いるようです。

arr = np.array([[1.0, 2.0],
                [3.0, 4.0],
                [5.0, 6.0]])
isinstance(arr, Array[np.float64, 3, 2])  # True

具体的な記述方法については、同様の調査を行っている記事が既にありました。

qiita.com

結論からいうと、mypyを用いたnumpy.ndarrayの型ヒントチェックはnumpy-stubsを用いれば可能。

ただし、現(2020年1月)時点ではndarrayのdtype, shapeを指定してのmypyチェックはできない。

一方、dtype, shapeを含めた型ヒントを可読性のためのアノテーションとしてつけたいというのであれば、nptypingを用いるという選択肢がよさそう。

関連記事

【Python】バリデーションを行うライブラリのpydanticが便利だった

同僚からFastAPIを薦めてもらって、バリデーションの機構が便利(そして早い)ということを教えてもらいました。

その中でjsonリクエストのアノテーションに使われているライブラリがpydanticで、FastAPI以外でも、辞書オブジェクトのバリデーションやキャスト、またSQLAlchemyのORMとの組み合わせなどもできるようです。

pydantic-docs.helpmanual.io

これについて記事にまとめようと思ったのですが、今の所特に詰まりどころもなく、日本語の記事ならこちらに素晴らしいものがありました。ですのでこちらを読んでください。

qiita.com

まあ良いライブラリを教えてもらったってことでw

【Python】継承という機能はmix-inだけで十分なんじゃないか説

最近、Pythonでコードを書いていて、薄々「継承で使うのはmix-inクラスだけでいいんじゃないか」と感じています。ここでいうmix-inクラスというのは、以下の記事で述べられているような「インスタンス変数を含まず、メソッドのみを持つ多重継承用のクラス」のことです。

www.atmarkit.co.jp

あるいは、「インスタンス変数を含むクラスを継承するのは1つだけ」とするルールを自らに課す方法もある。その場合、追加で継承できるのは「メソッドのみを含んだクラス」となる。そうすることで、インスタンス変数の共有によって生じる問題を回避できるようになる。

これに反論のある方は少ないと思います。また、「親クラスでインスタンス変数を定義する処理(ほぼ __init__ だと思います)を共通化する必要性がなければ、通常の親クラスを使わずにmix-inクラスだけで表現できるのではないか?」さらに「 __init__ などの処理を共通化して得られるコストメリットは少ないのではないか?」と感じています。その理由は以下の通りです。

  • Rustなどの言語では「インスタンス変数を含まない多重継承用のクラス」にあたるtraitと実装用の構造体の機能がはっきり分かれている(詳しくないので間違ってたら教えてください)
  • インスタンス変数を利用する処理を複数の子クラスで共通化する」ことにメリットがあるコードに出くわしたことがないように感じている
  • 他に自分が感じている感想として、単一継承でも継承関係が深くなると、インスタンス変数がどこで定義されているものか分からなくなる。そもそもリスコフの置換原則を満たしていないクラスに継承を使っているようなコードだったのが問題かもしれませんが…

この話を友人にしたところ、「多重継承したい場合に『インスタンス変数を含むクラスを継承するのは1つだけ』とするルールが必要なのは異論ない」「ただ、 __init__ の処理を共通化するメリットがある場面もあるのではないか?(極端な例だが子クラスが100個あって全部で同じ初期化処理がある場合)」というような意見を貰いました。

というわけで、「mix-inだけでいいんじゃないか説」の完全な証明にはならないものの、「子クラスが100個あって全部で同じ初期化処理がある場合」に、「インスタンス変数を含まない多重継承用のクラス」しかない言語ではどう解決しているのか(それとも __init__ を共通化するより楽な設計はあるのか)を調べてみようと思います。

と思ったのですが、サクッと調べた程度では全然結論が出なかったので一旦諦めました。

様々な記事

teratail.com

medium.com

class Dog
 include Runnable
end

class Cat
 include Runnable
end

module Rannable
 def run
 end
end

Dog.new.run

こちらも「Dogは走れるものの一種(Dog is a Runable)」と解釈できるんじゃないかと思ってしまいます。

riptutorial.com

TODO:: Rustのtraitが導入されるまでの議論を追う

www.buildinsider.net

kiito.hatenablog.com

TODO:: 「inheritance is not subtyping」問題

【Python】抽象基底クラス(abc)のメリット

Pythonはドキュメントが整備された言語ですが、専門的な用語も多く「結局この機能をどう使えば良いんだ」と思ってしまうことがあります。

この間同僚と abc モジュールの話になり、「結局何のメリットがあんのや」という話になりました。私は abc.ABC を使うことが多いのですが、改めて考えるとメリットを説明できなかったので調べてみます。

docs.python.org

このモジュールは Python に PEP 3119 で概要が示された 抽象基底クラス (ABC) を定義する基盤を提供します。なぜこれが Python に付け加えられたかについてはその PEP を参照してください。 (ABC に基づいた数の型階層を扱った PEP 3141 と numbers モジュールも参照してください。)

そして抽象基底クラスの説明はこちらです。これはきつい😅

(抽象基底クラス) 抽象基底クラスは duck-typing を補完するもので、 hasattr() などの別のテクニックでは不恰好であったり微妙に誤る (例えば magic methods の場合) 場合にインタフェースを定義する方法を提供します。ABC は仮想 (virtual) サブクラスを導入します。これは親クラスから継承しませんが、それでも isinstance() や issubclass() に認識されます; abc モジュールのドキュメントを参照してください。Python には、多くの組み込み ABC が同梱されています。その対象は、(collections.abc モジュールで) データ構造、(numbers モジュールで) 数、(io モジュールで) ストリーム、(importlib.abc モジュールで) インポートファインダ及びローダーです。 abc モジュールを利用して独自の ABC を作成できます。

abcの提案理由

上の例にあるPEP3119を追ってみます。翻訳を引用していきますが、必要に応じて原文も当たります。

www.python.org

mft.la.coocan.jp

一方で、古典的 OOP 理論家による覗き込み批判の一つは形式化の欠如であり、 何が覗き込まれるかについての場当たり的な性質です。 Python のような言語、つまりオブジェクトのほとんど全ての部分を外部コードが覗き込み、直接アクセスできるような言語においては、オブジェクトが特定のプロトコルに適合しているかどうかを調べるいくつもの異なった方法があります。 たとえば「このオブジェクトは変更可能なシーケンスのコンテナですか?」 という問には、’list’ が基底クラスにあるかどうか探す、’__getitem__’ という名のメソッドを探すといった解答方法が思いつきます。 しかし間違えてはいけないのは、これらのテストが当たり前に見えるとしても、 どちらも正しくないということです。 一方は間違って否定することがあり、もう一方は間違って肯定することがあります。

「呼び出し」は「オブジェクトにメソッド呼び出しを通して働きかけること」で「覗き込み」は「外部のコード(オブジェクトのメソッド以外のもの)が、型やオブジェクトのプロパティを調べたり、その情報に基づいてそのオブジェクトをどのように扱うか決める」ことだと説明されています。原文には'invocation' and 'inspection'とあります。

一方で、古典的 OOP 理論家による覗き込み批判の一つは形式化の欠如であり、 何が覗き込まれるかについての場当たり的な性質です。 Python のような言語、つまりオブジェクトのほとんど全ての部分を外部コードが覗き込み、直接アクセスできるような言語においては、オブジェクトが特定のプロトコルに適合しているかどうかを調べるいくつもの異なった方法があります。 たとえば「このオブジェクトは変更可能なシーケンスのコンテナですか?」 という問には、’list’ が基底クラスにあるかどうか探す、’__getitem__’ という名のメソッドを探すといった解答方法が思いつきます。 しかし間違えてはいけないのは、これらのテストが当たり前に見えるとしても、 どちらも正しくないということです。 一方は間違って否定することがあり、もう一方は間違って肯定することがあります。

abc導入の目的は、「そのオブジェクトに特定のメソッドが存在することを保証すること」のようです。

この PEP はこうしたテストの組織化戦略、抽象基底クラス (Abstract Base Class, ABC) として知られるものを提案します。 抽象基底クラスは単純な Python クラスでオブジェクトの継承ツリーに加えられ、 外部からの覗き込みに対してそのオブジェクトの特定の特性を伝えるものです。 テスト自体は isinstance() を使って行われ、 特定の ABC の存在はそれの定めるテストを通ったことを意味します。

それに加えて、ABC はある型の特徴的な振る舞いを確立する最小メソッド集合を定義します。 ABC に基づいてオブジェクトを判別するコードは、 それらのメソッドの存在を信じることができます。 これらのメソッドのそれぞれは一般化された抽象的な意味の定義を ABC の文書中に見つけることができます。 これら標準的な意味定義は強制力はありませんが、 従うことが強く推奨されます。

具体的な機能

仕様は概要で列挙されたカテゴリーの順番に従います:

  • isinstance() および issubclass() の多重定義(オーバーロード)方法。
  • “ABC フレームワーク” として使う abc 新モジュール。 このモジュールでは ABC と共に使うメタクラスと抽象メソッドを定義するのに使うデコレータを定義します。
  • コンテナとイテレータに特化した ABC が collections モジュールに追加されます。

3つめは collections.abcの話です。

具体的には「isinstance/issubclassでの判定を正確にすること」「 abstractmethod などのデコレータで、子クラスにメソッドの実装を強制できること」が具体的な機能として挙げられています。

ichitcltk.hustle.ne.jp

後で調べたい点: typingモジュールとの関連

ここは私自身まだ混乱してます。この間の記事でも調べた構造的部分型も、「メソッドが存在することを保証する」ことが目的なのでどういう関連なのか気になっています。typingモジュールでは構造的部分型もサポートされています。

www.slideshare.net

こちらでも「そのオブジェクトに特定のメソッドが存在することを保証すること」は保証できるはずなので、どう使い分けるのか調べてみたいです。

【Python】@classmethodと@staticmethodの使いどころ

今日は @classmethod@staticmethod の使い分け方が話題になりました。私はなんとなく「コンストラクタが複数ある場合は @classmethod を使う」ようにしています。ただ、他の使い道も自分が知らないだけであるんじゃないかと思い、少し調べてみました。

複数の初期化処理を切り分ける(Factory Methodパターン)

こちらの記事にある通りです。

blog.pyq.jp

よく使われる例としては、そのクラスを作るメソッドを書くことです。 以下の例ではクラス Item と、Itemの情報をあるAPIから取得して返す retrieve_from_api というクラスメソッドを実装しています。

class Item:
    def __init__(self, id, name):
        self.id = id
        self.name = name

    @classmethod
    def retrieve_from_api(cls, id):
        res = requests.get(f"https://api.example.com/items/{id}")
        data = res.json()
        return cls(id, data["name"])

www.programiz.com

これはFactory Methodパターンと呼ばれるデザインパターンです。

pydp.info

インスタンス間で共通の変数を保持する

elicon.blog57.fc2.com

やや古い記事なので、Python2系の xrange が使われていて少し懐かしいですね。

class Shape:
    collection = set()
    def __init__(self,x, y):
        self.x = x
        self.y = y

    def update(self):
        self.x += 1
        self.y += 1

    @classmethod
    def add_new_shape(cls, (x, y)):
        shape = Shape(x, y)
        Shape.collection.add(shape)

    @classmethod
    def update_all(cls):
        for shape in Shape.collection:
            shape.update()

def main():
    for p in xrange(10):
        Shape.add_new_shape((p, p))

    q = 0
    while q < 60:
        Shape.update_all()
        q += 1

if __name__ == "__main__":
    main()

(おまけ)@staticmethodの使いどころ

elicon.blog57.fc2.com

また、 @staticmethod は「関数をまとめたクラスオブジェクト(モジュール)を作る場合」に使っています。ただ、Pythonだとファイル単位でモジュールができるので、個人的にはあまり必要性を感じたことがないです。

あとはインスタンス変数やインスタンスメソッドにアクセスしないときにも @staticmethod を使いますが、個人的な経験では、結局後で他のメソッドを呼ぶことになって self を書き足すことが多かったのであまりメリットは感じません。

atsuoishimoto.hatenablog.com

こちらの例は鮮やかですが、なかなかこういう機会はなさそう。

【SageMaker】SageMakerのサンプルをローカル実行してget_execution_role関数がエラーを起こす場合の対処

休みの時間を利用して、こちらのSageMakerのサンプルを試していました。

aws.amazon.com

問題

ただ、ローカルのPC(Mac Book)から利用する場合、下のStackOverflowにある通り、エラーが出て get_execution_role 関数が使えません。

stackoverflow.com

def trained_estimator_from_hyperparams(s3_train_data, hyperparams, output_path, s3_test_data=None):
    # 中略
    knn = sagemaker.estimator.Estimator(containers[boto3.Session().region_name],
        get_execution_role(),
        train_instance_count=1,
        train_instance_type='ml.m5.2xlarge',
        output_path=output_path,
        sagemaker_session=sagemaker.Session())
    knn.set_hyperparameters(**hyperparams)
    # 後略

そもそも、ドキュメントには次のように書かれています。

次の Python コードをコピーして、ノートブックの最初のセルに貼り付けます。「Amazon SageMaker をセットアップします」で作成した S3 バケットの名前を追加し、コードを実行します。get_execution_role 関数は、ノートブックインスタンスの作成時に作成した IAM ロールを取得します。

SageMakerの利用し始めには多少混乱すると思いますが、「ノートブックインスタンス」と「トレーニンインスタンス」が別に存在して、 get_execution_role は「ノートブックインスタンスから自分のroleを取得する」ための関数です。

対処

aws.amazon.com

「オンプレミス環境から Amazon SageMaker を利用する」の記事にもある通り、単純に自前で文字列で指定すればいいだけです。

ひとまず私は、SageMakerとS3(モデルやデータの読み込みに必要)を読み込むロールを付けて直接文字列で指定しました。

def trained_estimator_from_hyperparams(s3_train_data, hyperparams, output_path, s3_test_data=None):
    # 中略
    knn = sagemaker.estimator.Estimator(containers[boto3.Session().region_name],
        "arn:aws:iam::***********:role/sagemaker-execution",
        train_instance_count=1,
        train_instance_type='ml.m5.2xlarge',
        output_path=output_path,
        sagemaker_session=sagemaker.Session())
    knn.set_hyperparameters(**hyperparams)
    # 後略

【Django】『現場で使える Django の教科書』を読んでいきます

PythonのWEBフレームワーク、Djangoのチュートリアルはひととおり通したものの、実際にプロダクトを作るには不安な状態で、これからどう学ぶべきか悩んでいました。

そんな中、『現場で使える Django の教科書』という本がなかなか良さそうだったのでこれを参考にしつつ勉強を進めていこうと思います。

現場で使える Django の教科書《基礎編》

現場で使える Django の教科書《基礎編》

Djangoが主張しているMTVってMVCとどう違うの?(実際にはViewの役割がTとVに分かれただけ)」とか「それぞれのモジュールでどういう処理を書いていけばいいの?」みたいなことがわかりやすく図解されているので、チュートリアルで学んだことの整理に役立ちそうです。

気になった方は、詳しい内容は著者のブログで!

akiyoko.hatenablog.jp

akiyoko.hatenablog.jp

とりあえずGAEでWEBアプリケーションを作って公開するところまでは趣味でもやりたいです。何を作ろうかな。