Pythonのインターフェースに基づいてプログラミングする方法

この記事を読むのに約2分かかります。

ソフトウェア業界では、唯一の定数は変化です。製品マネージャーが変更され、製品要件が変更され、コードも変更されます。コードの設計と変更が異なれば、ワークロードも異なります。変更によっては、ほとんどリファクタリングが必要なものもあれば、構成ファイルを変更するか、クラスにコード行を追加するだけでよいものもあります。もちろん、優れたコード設計は、優れたスケーラビリティ、高い凝集性、および低い結合を備えているため、保守が容易です。優れたコードデザインが必要な場合は、デザインパターンを学ぶ必要があります。今日は、Pythonのインターフェースに基づいてプログラミングする方法を紹介します。

1994 2015年のGoFの「DesignPatterns」ブックには、実装プログラミングではなくインターフェイスに基づく重要な原則があります。元の英語のテキストは「実装ではなくインターフェイスへのプログラム」です。ここで説明するインターフェイスは特定のプログラミング言語ではありません。言語に依存しないのインターフェイスは、開発者がユーザーに提供する機能のリストを参照します。これを理解することは非常に重要です。インターフェイスは、Java言語のキーワードinterfaceによって実装されます。Javaはクラスの複数の継承をサポートしていませんが、インターフェイスの複数の継承をサポートしています。Java開発者はインターフェイスに精通しています。PythonはJava設計をまったく必要としませんが、インターフェイスの利点から学ぶことができます。

**最初に例を使用して、インターフェイスが解決する問題を理解しましょう。 **

たとえば、画像のアップロード機能を実装していて、現在QiniuCloudをストレージに使用しているとします。クラスは次のようになります。

classQnyImageStore(object):

 def getToken():
  pass

 def upload_qny(self,image):print("Qny upload.")
  # do something

 def download_qny(self,image):print("Qny download.")
  # do something

実際の開発では、多くのコード行と3つ以上の関数があり、数百または数千の場所で呼び出され、数百のファイルに散在しています。しばらくして、同社は独自のプライベートクラウドを構築し、Qiniu Cloudを使用できなくなり、独自の[Cloud Storage](https://cloud.tencent.com/product/cos?from=10680)に変更する必要があるため、クラスを書き直す必要があります。

classOwnImageStore(object):

 def upload_own(self,image):print("Qny upload.")
  # do something

 def download_own(self,image):print("Qny download.")
  # do something

次に、Qiniuを使用するすべての場所を置き換え、関数の名前も置き換える必要があります。最後に、人生のどの部分も考慮していない場所で複数回テストする必要があり、エラーが発生します。ついに変更されました。ある日突然、需要が再び変化しました。クラウドサービスに問題が発生することが多かったため、AlibabaCloudに切り替える必要がありました。前回の辛いトスの後、今度は変わるのを見て、直接血を吐きました。

実際、問題は、作成するコードが十分に一般的でなく、名前が十分に抽象的でないことです。クラスの関数名がアップロードとダウンロードを使用している場合、変更するコードの量が半分に減る可能性があります。クラス名を置き換えるだけです。実際、インターフェイスを使用してコードの変更量を減らすことができます。インターフェイスと実装を分離することで、不安定な実装をカプセル化し、安定したインターフェイスを公開します。アップストリームシステムとダウンストリームシステムが当社が開発した関数を使用する場合、インターフェイスで宣言された関数リストを使用するだけでよいため、実装が変更された場合でも、カップリングを減らしてスケーラビリティを向上させるために、アップストリームシステムのコードを基本的に変更する必要はありません。 。以下に、この問題に関するインターフェイスベースのコード実装方法を示します。

インターフェイスを定義する

from abc import ABCMeta, abstractmethod

classImageStore(metaclass = ABCMeta):

 @ abstractmethod
 def upload(self,image): 
  pass
  # raise NotImplementedError

 @ abstractmethod
 def download(self,image): 
  pass
  # raise NotImplementedError

インターフェイスを定義した後、インターフェイスを継承するクラスは、正しく使用するためにアップロードメソッドとダウンロードメソッドを書き直す必要があります。そうしないと、例外がスローされます。ここでは、インターフェイスで例外をスローする必要はありません。標準ライブラリabcはすでに存在します。これらのタスクを実行しました。

クラスを定義し、インターフェースを継承します

目的は、実際には制約を適用することです。つまり、プログラムの堅牢性を確保するために、コンパイル時にアップロードおよびダウンロードメソッドを実装およびチェックする必要があります。

classOwnImageStore2(ImageStore):

 def upload(self,image):print("Own upload.")
  # do something

 def download(self,image):print("Own download.")
  # do something

classQnyImageStore2(ImageStore):

 def getToken():
  pass

 def upload(self,image):print("Qny upload.")

 def download(self,image):print("Qny download.")
  # do something

次に、タイプに応じて対応するオブジェクトを呼び出すメソッドを自動的に選択できるインターフェイスを定義します。

classUsedStore(object):

 def __init__(self, store):if not isinstance(store, ImageStore): raise Exception('Bad interface')
  self._store = store

 def upload(self):
  self._store.upload('image')

 def download(self):
  self._store.download('image')

最後に、構成ファイルで、使用している特定のインターフェースを指定できます。

# 他のファイルでは、このように呼び出す必要があります
img =QnyImageStore2()
# img =OwnImageStore2()これらを構成ファイルに入れてください。置き換える必要があるのは構成ファイルを更新するだけです。
store =UsedStore(img)
store.upload()
store.download()

このように、後で新しいイメージストレージを追加するには、対応するクラスを追加し、インターフェイスを継承し、構成ファイルを変更するだけで、多くのコード変更作業を減らすことができます。

Python抽象基本クラスの概要(PEP3119)

python標準ライブラリabc、フルネームはAbstract Base Classesで、次の関数を提供します。

基本

オブジェクト指向プログラミングの分野では、オブジェクトと相互作用する設計パターンは、「呼び出し」と「チェック」という2つの基本的なカテゴリに分類できます。

呼び出しとは、オブジェクトのメソッドを呼び出すことによってオブジェクトと対話することを指します。通常、これは多態性と組み合わされるため、特定のメソッドを呼び出すと、オブジェクトのタイプに応じて異なるコードが実行される場合があります。

検査とは、(オブジェクトのメソッドの外部にある)外部コードがオブジェクトのタイプまたはプロパティを検査し、この情報に基づいてオブジェクトを処理する方法を決定する機能を指します。

どちらの使用モードも同じ汎用目的を果たします。つまり、多様で新しい可能性のあるオブジェクトの処理を統一された方法でサポートできますが、同時に、異なるタイプのオブジェクトごとにカスタマイズされた処理決定を行うことができます。

古典的なOOP理論では、呼び出しが好ましい設計パターンであり、検査は以前のスタイルの手続き型プログラミングの製品と見なされるため、検査は推奨されません。ただし、実際には、このビューは独断的で厳格すぎるため、Pythonなどの言語の動的な性質とは大きく異なる特定の設計の厳格さにつながります。

特に、オブジェクトクラスの作成者が予測できない方法でオブジェクトを処理する必要がある場合がよくあります。そのオブジェクトのすべての可能なユーザーニーズを満たすすべてのオブジェクトメソッドに組み込まれていることが、常に最良のソリューションであるとは限りません。さらに、ルールやパターンマッチング駆動型ロジックなど、オブジェクトに厳密にカプセル化されている従来のOOP動作要件とは対照的な、強力なスケジューリング哲学が数多くあります。

一方、古典的なOOP理論家による検査に対する批判の1つは、形式主義の欠如と検査されたコンテンツの特殊な性質です。 Pythonなどの言語では、オブジェクトのほぼすべての側面を反映し、外部コードを介して直接アクセスできます。オブジェクトが特定のプロトコルに準拠しているかどうかをテストするには、さまざまな方法があります。たとえば、「このオブジェクトは可変シーケンスコンテナですか?」と尋ねると、「list」の基本クラスを検索したり、「、__ getitem__」という名前のメソッドを検索したりできます。ただし、これらのテストは明白に見えるかもしれませんが、一方が偽陰性を生成し、もう一方が偽陽性を生成するため、正しくないことに注意してください。

一般的に合意されている救済策は、テストを標準化し、正式な形式にグループ化することです。これを行うには、継承メカニズムまたはその他の方法で、標準のテスト可能なプロパティのセットを各クラスに関連付けるのが最も簡単です。各テストには一連のPromiseが付属しています。これには、クラスの一般的な動作に関するPromiseと、他の使用可能なクラスメソッドに関するPromiseが含まれています。

PEPは、Abstract Base Class(ABC)と呼ばれる、これらのテストを編成するための特別な戦略を提案します。 ABCは、オブジェクトの特定の機能を外部の検査官に送信するためにオブジェクトの継承ツリーに追加されるPythonクラスです。 isinstance()を使用してテストを完了します。特定のABCが存在する場合は、テストに合格したことを意味します。

さらに、ABCは、このタイプの特徴的な動作を確立するためのメソッドの最小セットを定義します。 ABCタイプに基づいてオブジェクトを区別するコードは、これらのメソッドが常に存在することを信頼できます。これらの各メソッドには、ABCドキュメントで説明されている一般化された抽象的なセマンティック定義が付属しています。これらの標準の意味上の定義は必須ではありませんが、強くお勧めします。

Pythonの他のすべてと同様に、これらの約束は紳士協定の性質のものです。この場合、これは、言語がABCで行われた約束の一部を実装しているにもかかわらず、具体的なクラスの実装者が次を続けます。

上記の説明を読むと、ABCが基本クラスであることが簡単に理解できます。これを継承すると、javaに似たインターフェイスを作成できます。インターフェイスのメソッドは常に存在し、自信を持って使用でき、調査する必要はありません。

PEP3119には、理解できるサンプルコードも用意されています。

from abc import ABCMeta, abstractmethod

classA(metaclass=ABCMeta):
 @ abstractmethod
 def foo(self): pass

A()  # raises TypeError

classB(A):
 pass

B()  # raises TypeError

classC(A):
 def foo(self):print(42)C()  # works

それについては話したくありません。ABCを正しく使用できることを願っています。同時に、Pythonを学ぶことを強くお勧めします。公式のPythonドキュメントとPEP提案をご覧ください。これが最も信頼できる説明です。

また、設定モードも非常に重要なプログラミング手法であり、プログラミングの方法であり、基本的なスキルです。基本的なスキルが足りない場合は、戦闘機を目の前に置いた場合の鑑賞方法や味わい方がわかりません。

デザインパターンをマスターして他の人のコードを見ると、ファイタージェットであり、トラクターである黄金の目が見えます。これは、自分の学習と改善にも非常に役立ちます。作成したコードは、より保守しやすく、読みやすくなります。スケーラビリティ、柔軟性。

デザインパターンに興味のある方は、一緒に勉強してみてください。下の写真からデザインパターンを購入したクラスメートは、友達(somenzz)を追加して12元をキャッシュバックし、大きなグループに参加してPythonテクノロジーを交換します。一人で学んだり、友達がいなかったり、無知であったりしないでください。

デザインパターンの美しさ-王鄭

Recommended Posts

Pythonのインターフェースに基づいてプログラミングする方法
告白プログラムをpythonで書く方法
pythonプログラムを保存する方法
Pythonで括弧を省略する方法
CentOS8にPython3.8をインストールする方法
Ubuntu18.04にPython3.8をインストールする方法
pythonでクラスを書く方法
pythonで数値をフィルタリングする方法
PythonでExcelを読む方法
CentOS8にPythonをインストールする方法
pythonでエラーを表示する方法
pythonでreturnを書く方法
Pythonで変数を理解する方法
pythonで変数をクリアする方法
PythonでSQLiteを使用する方法
およびおよびまたはPythonでの使用方法
pythonでキャッシュファイルを削除する方法
pythonでnull値を表す方法
pythonでテキストファイルを保存する方法
pythonでwinプログラムを書く方法
pythonでid関数を実行する方法
Pythonでサードパーティモジュールをインストールする方法
pythonでエラーをカスタムキャッチする方法
pythonでtryステートメントを書く方法
Pythonでプライベート属性を定義する方法
R&D:CentOS7にPython3をインストールする方法
Pythonでカスタムモジュールを追加する方法
Pythonでグローバル変数を理解する方法
インストールされているモジュールをpythonで表示する方法
Ubuntu20.04 ubuntu / focal64にPython2をインストールする方法
reprを使用してpythonプログラムをデバッグする方法
さまざまなシステムでのPythonopenメソッド
pythonで辞書を並べ替える方法
pythonで背景音楽を追加する方法
pythonで相対パスを表す方法
Ubuntu18.04ですべてのPythonライブラリをアップグレードする方法
pythonでround関数を使用する方法
Pythonでzip関数を使用する方法
ubuntuサーバー環境にpythonをインストールする方法
Pythonゲームで重力をシミュレートする方法
pythonでformat関数を使用する方法
UbuntuでPython3を楽しくプレイする方法
pythonでアシスタントを実行するコードを使用する方法
pythonでコード自動プロンプトを設定する方法
[練習] Ubuntuシステムにpython3.6をインストールする方法
pythonでゲームを書く方法を教えてください
pythonでファイルとディレクトリを削除する方法
ダウンロードしたモジュールをpythonでインストールする方法
pythonで連続乗算計算を実行する方法
Ubuntu18.04にスタンドアロンモードでHadoopをインストールする方法
Ubuntu18.04に基づいて固定IPを構成する方法
Pythonでのパッケージの導入を理解する方法
pythonで番号のリストを理解する方法
pythonで写真を自動的にダウンロードする方法の例
IEを添付ファイルとしてPythonで保存する方法
Ubuntu14.04でPython仮想環境を作成する方法
Ubuntu16.04に基づいて固定IPを設定する方法
pythonコードにコメントする方法
pythonをすばやく学ぶ方法
pythonプラグインをアンインストールする方法
pythonオブジェクトを理解する方法