Masonite Pythonフレームワーク知識シリーズ第1部-依存性自動注入の自動解決の理解



導入


Masonite Pythonフレームワークは、現在の市場では何よりもPythonフレームワークへのより現代的なアプローチです.大胆な声明ですが、一旦Masoniteを使い始めると、他のPythonフレームワークが依存性注入IOCコンテナのようなものではない、いくつかの簡単なデザイン決定を使用するだけで、どれだけ強力であるかに驚くことでしょう.
Masoniteを学ぶとき、あなたはソフトウェア開発世界で支配的であるこれらのパターンの多くを学びます.
Masoniteがどのように働くかについて、背景知識を本当に与えるために、これらの記事のいくつかを書いています.より多くのあなたのツールを理解するには、それらを最大限に活用することができます.
シリーズのこの最初の部分で、Masoniteがどのようにそれを扱うかについて、深さに行きます
この記事を楽しんで、Masoniteでアプリケーションを書くのを楽しんでいるなら、スラックチャンネルに加わってください.http://slack.masoniteproject.com

何ですか。


したがって、依存性注入は$ 1定義のための10ドルの単語です.単にそれを置くだけで我々はそれが必要なオブジェクトに何かを渡すことを意味します.
この簡単な例を見てください.
from app import Model

def get_user_id(self, model):
    return model.find(1).id

user = get_user_id(Model)
この最も基本的な例では、モデルはこの関数の依存性であり、依存関係の注入を行っただけです.この関数オブジェクトにクラスを「注入」します.

一歩羽


もう一つのステップをさらに進めましょう.このデモの目的のために、我々は辞書(我々は容器を呼ぶつもり)を関数の上に加えたと言いましょう.この辞書は、我々のアプリケーションのために必要なすべてのクラスが含まれます.
注意:これを実装するのは悪い方法ですが、今のところだけに従ってください.
from static_assets import AmazonUpload

container = {'upload': AmazonUpload}

def upload_image(self, upload):
    return upload.store('some-file.png')
そこで、ここでは便利なパラメータを持っていることに注意してくださいupload と呼ばれる辞書キーupload . これは“自動解決”依存性注入の最も基本的な基礎です.
ここでのアイデアは、このコンテナを使用して、私たちが必要とするすべての依存関係を引っ張り、要件変更について心配する必要はありません.コンテナは、我々の具体的なコード実装とコンテナの流動性の間の調停者の一種として機能しています.
機能を変更する必要がある場合は、コンテナのクラスを交換します.

アナザーステップ


なぜ私は自分の要求をする必要があります私のオブジェクトとこれらのクラスの間にこのメディエータが必要ですか
Masoniteのコンテナの背後にあるアイデアは、あなたのアプリケーション(典型的には実装)をあなたの特徴に「ゆるく組み合わせる」ことです.
使用upload_image 上の機能は、上司があなたに来て、“私たちは、代わりにファイルシステムにすべてをアップロードを開始する必要があります、私たちの会社のためにあまりにも高価になっている”と述べた場合、何が起こるだろう..それでは何をするのですか.おそらくあなたのコードを見て、次のようにしてください.
from static_assets import AmazonUpload

def upload_image(self):
    return AmazonUpload.store('some-file.png')

def rename_image(self):
    return AmazonUpload.rename('some-file.png', 'another-file.png')

def delete_image(self):
    return AmazonUpload.delete('some-file.png')

def move_image(self):
    return AmazonUpload.move('some-file.png', 'another-location.png')

def copy_image(self):
    return AmazonUpload.copy('some-file.png', 'another-file.png')
現在、私はAmazonUpload依存性をコード化して、現在主要なリファクタを必要とする5つの具体的な実装があります5つの場所を持ちます.
別の見た目にしましょうが、パラメータ名が再び辞書キーにマッチするようにこっそりコンテナを入れましょう.
from static_assets import AmazonUpload

container = {'upload': AmazonUpload}

def upload_image(self, upload):
    return upload.store('some-file.png')

def rename_image(self, upload):
    return upload.rename('some-file.png', 'another-file.png')

def delete_image(self, upload):
    return upload.delete('some-file.png')

def move_image(self, upload):
    return upload.move('some-file.png', 'another-location.png')

def copy_image(self, upload):
    return upload.copy('some-file.png', 'another-file.png')

自動部品


今のところ、「このパラメータは辞書キーと同じ名前を持っています」という概念を理解しています.
Masoniteが依存注入を処理し、擬似コードを使用する方法の実際の機能を置き換えると、自動部分は次のようになります.
注意:これは擬似コードで、Pythonコードを働かない.
class Container

    providers = {'upload', AmazonUpload}

    def resolve(self, object_to_resolve):
        build_parameter_list = []

        # Get all of the objects parameters
        paramaters = inspect(object_to_resolve).parameters
        # returns ['upload']

        for paramater in paramaters:
            if paramater in self.providers:
                build_parameter_list.append(parameter)

        return object_to_resolve(*build_parameter_list)
それは本当にです.人間の用語で説明するために、我々は単にすべてのパラメタのリストを得るためにパイソン検査を使用しています.例えばupload_image 上記の関数は'upload' パラメータ名ですから.

依存性の自動注入


OK!それで、我々はそれを良いものにしました.我々の依存関係を解決している自動車を始めましょう!しましょうupload_image 上記の例
from container import Container

def upload_image(self, upload):
    return upload.store('some-file.png')

uploaded_image = Container().resolve(upload_image)
# Looks into the container for the 'upload' key and injects it into the class.
アップロード画像の具体的な実装を完全に削除しました.今では完全に「サービス不可知論」ですそれが重要でないならば、それは重要でありませんAmazonUpload クラスまたはAzureUpload クラスと依存関係は1位だけです.我々は今すぐに全体のアプリケーションを介して機能を交換することができます.

マスナイトイト特異性


コンテナがとても強力である理由は、我々の特徴と我々のアプリケーションの間に完全な調停者があります.これに加えて、すべての機能は非常にプラグイン可能なシステムを作成するので、他のすべての機能の不可知論者です.
Masoniteは、オブジェクトを解決するためのより高度な方法を使用します.
masoniteでは、このような機能を使用します.
class WelcomeController:

    def show(self, Request):
        Request.user().id
' request 'はコンテナのキーです.これは少し基本的なことですが、もう一度もう一つのステップを踏みましょう.また、Masoniteがどのように機能注釈を扱うかを示します.

Python関数の注釈


Pythonの注釈は、常に奇妙なソートされている.それは基本的にパラメータのインラインインラインです.変だ.Pythonにこれを追加すると、Pythonのコアにまったく目的を提供するとは思えませんでした.実際、それはpepでこれを言います:

The only way that annotations take on meaning is when they are interpreted by third-party libraries. These annotation consumers can do anything they want with a function's annotations.


それで、Masoniteがしたことは、パラメタリストを通してループして、依存関係を解決することに加えて、我々も注釈を通過して、彼らを解決するということでした.このように普通に注釈を付ける代わりに:
def upload_image(upload: "pass in the upload class"):
    pass
我々はさらに一歩を踏み出すことができ、クラス全体を通過することができます.
from static_files import AmazonUpload

def upload_image(upload: AmazonUpload):
    pass
私たちは本質的に文字列の代わりにクラスでパラメータを注釈します.この注釈型(特定のクラス)を使用してコンテナーを見つけることができます.これは以前の例の代わりに「辞書値で取得する」のです.
Masoniteでは、コントローラ、ドライバ、ミドルウェアのように自動解決されるアプリケーションのいくつかの部分があります.Masoniteの自動解決は次のようになります.
from masonite.view import View
from masonite.request import Request

class WelcomeController:
    ''' Controller For Welcoming The User '''

    def show(self, view: View, request: Request):
        ''' Show Welcome Template '''
        return view.render('welcome', {'request': request})

サブクラス(上級)


あなたが上記のすべてを理解したならば、我々はもう少し高度になることができます
クラスの取得に加えて、さらに強力なクラスのサブクラスも取得できます.コンテナーは、アプリケーションを緩く結合させる方法ですが、注釈を付けた場合は、コンテナからクラスをスワップできません.我々は現在、「具体的な」実装に「しっかり」結合されます.言い換えると、我々は1つのクラスだけを使用することができます.
次のようにします.
from masonite.drivers import UploadS3Driver

class UploadController:
    ''' Controller For Uploading Images '''

    def show(self, upload: UploadS3Driver):
        ''' Show Welcome Template '''
        return upload.store('some-file.png')
親クラスを追加することで、さらに一歩を踏み出すことができます.The UploadS3Driver バックエンドでこんな感じです.
...
from masonite.contracts import UploadContract
...

class UploadS3Driver(BaseDriver, UploadContract):
    ...
それで、私たちは同じクラスをUploadContract :
それを知るのは良いことだUploadContract コンテナに入っていません
from masonite.contracts import UploadContract

class UploadController:
    ''' Controller For Uploading Images '''

    def show(self, upload: UploadContract):
        ''' Show Welcome Template '''

        return upload.store('some-file.png')
        # returns an upload driver

ハウツーとスタイル


これは私を得るUploadS3Driver それが我々が探しているもののサブクラスであるので、クラス.Masoniteはこのロジックをバックエンドで処理します.
マサナイトが解決すべきことについての階層が少しあります.
その基本はクラス自体を探すことですが、それが見つからなければ(契約がコンテナにないので)、あなたが探しているもののサブクラスを解決するでしょう.コンテナにマッチがないならば、それは例外を投げます.

テスト


この構造の最も良い部分は、それが非常にテスト可能であるということです.今、我々はコントローラをインポートし、パラメータを模擬することができます.
以下に、このコントローラをどのように模擬するかについての例を示します.
from app.http.controllers.WelcomeController import WelcomeController
from masonite.request import Request
from masonite.testsuite.TestSuite import generate_wsgi

class MockView:

    def render(self, template, dictionary):
        pass

def test_welcome_controller():
    assert WelcomeController().show(MockView, Request(generate_wsgi()))
あなたのコントローラを短くして、あなたの依存関係の多くをコンテナに保つならば、あなたは簡単に簡単なテストとモック物を簡単に作成することができます.
私はあなたが記事を楽しんでほしい!あなたが興味があるならば、私はよりこのように出ています.あなたはそれを開始することができますGithub またはSlack チャンネル!