2016-05-20 7 views
1

私はPythonでクラスを持っていますが、これはサーバーへのリモート接続を実行します。状況(パフォーマンスの問題など)に応じて使用できる同じデータにアクセスするためのいくつかのプロトコル(TCP/IP、HTTP)があるので、クラスをカプセル化するさまざまな機能のデコレータとして使用したいと思います実装。クラスとアクセスクラスインスタンスを持つPythonデコレート関数

私のクラスには、次のようになります。

class RemoteConnection(object): 
     def __init__(self, function): 
     self.function = function 
     self.results = None 

     def __call__(self, *args): 
     self.function(self, *args) 

     def setResults(*args): 
     self.results = args 


@RemoteConnection 
def performTCPConnection(instance, username, password): 
     #...perform connection 
     instance.setResults(results) #set the results of the connection (a query) 
     return instance 

@RemoteConnection 
def performHTTPConnection(instance, username, password): 
     #...perform connection 
     #and so on 

    if __name__ == '__main__': 
     performTCPConnection("admin", "admin") #OR 
     #performHTTPConnection("admin, "admin") 

パラメータ(ユーザ名とパスワードよりも、これらは参考用のみです)後で​​または何か他のものを使用してプログラムの開発に与えられなければなりません。

私がこのようなプログラムを呼び出すと、__init__()メソッドがデコレータのために2回呼び出されます。また、performTCPConnection -functionが呼び出され、__call__-methodが呼び出される前に呼び出されます。私が今したいのは、RemoteConnectionクラスのインスタンスが、performTCPConnection関数によってメイン関数の変数に返されるということです。

私は次のような何か場合:

foo = perfprmTCPConnection("admin","admin") 
print foo 

なしが標準出力に出力されませんが。

私はそのようなperformTCPConnection機能でインスタンスにアクセスしようとした場合:

@RemoteConnection 
    def performTCPConnection(instance, username, password): 
    #...perform connection 
    instance.setResults(results) #set the results of the connection (a query) 
    print instance 
    return instance 

<__main__.ServerConnection object at 0x7f4803516fd0>のようなものがSTDOUTに書き込まれます。

私の考えは、Strategy-Patternの実装のように、Javaの世界から少し動いています。

残念ながら、私は今まで説明された動作の良い説明は見つかりませんでした。これは良い設計アプローチですか?

答えて

1

を、私はあなたが上エンジニアリング、これをしていると信じています。基本的には、デコレータを使用して、あなたの戦略は、厳密に相当します:

def performTCPConnection(username, password): 
    instance = RemoteConnection() 
    #...perform connection 
    instance.setResults(results) #set the results of the connection (a query) 
    return instance 

いますが、たい何を読んで、あなたはありませんが、まだ、まだです。パターン内でRemoteConnectionクラスの目的を理解している場合は、.function()メソッドを呼び出すときに一度に接続を延期することです。

だから何あなたがしたいと思うことは、実際にある:

def prepareTCPConnection(username, password): 
    rc = RemoteConnection() 
    def connection_handler(): 
     # perform the connection, and setup results 
     rc.setResults(results) 
    rc.function = connection_handler 
    return rc 

あなたは明らかに、適切RemoteConnectionを適応させる必要があるだろう。

ここでは、内部関数(およびクロージャ)を利用して、プログラムフローの後の便利なポイントで呼び出される関数を定義します。

しかし、正直に言うと、あなたは簡単なサブクラス化を使用しての方法より簡単な方法で同じことを達成することができます

class PerformConnection(): 
    def __init__(self, username, password): 
     self.username = username 
     self.password = password 

    def perform(self): 
     raise NotImplementedError 

class PerformConnectionTCP(PerformConnection): 
    def perform(self): 
     # do what you got to do here... 
     return results 

その後、メインにあなたが行うことができます:

if __name__ == "__main__": 
    instance = PerformConnectionTCP('admin', 'admin') 
    instance.perform() 
+0

アドバイスをいただきありがとうございます、これは現時点ではより良いアプローチかもしれません。また、自分の答えで述べたように私の最初のアプローチで間違いを見つけました。 – Supahupe

+0

また、@alexisの解決法は、実際に私が提案したより簡単なアプローチです。それは、あなたが本当にやっていることを明確にして、それをさらに明らかにするでしょう。当然のことながら、最適なソリューションは、アプリケーションのコンテキストと、実際にそのアプリケーションを使用する方法と、どのような柔軟性を活用する必要があるのか​​によっても異なります。 – zmo

0

()のメソッドで、装飾された関数の結果を返すのを忘れていました。これは、問題解決

:私はあなたが書いたものを、次のよ場合

class RemoteConnection(object): 
    def __init__(self, function): 
    self.function = function 
    self.results = None 

    def __call__(self, *args): 
    return self.function(self, *args) #here was the problem! 

    def setResults(*args): 
    self.results = args 
+1

あなたはまだ '__init__'をダブルコールしています – zmo

+0

はい、そうです。私があなたの答えにコメントしたように、あなたのアプローチはより良い方法です。私はちょうどデコレータがどのように働いているかに興味があり、これは良いアプローチかもしれないと思った。 – Supahupe

+1

原則として、最も簡単で読みやすい解決策を探すべきである。それはPEP8がpythonicと呼ぶものです;-) – zmo

2

私は間違いなく言うと思いますこれは良いデザインではありません。これは、継承メカニズムを使用せずに継承を効果的に取得する巧妙な方法ですが、これを直接行う方法がより多く存在するため、標準ではなく、直感的ではなく、不要です。

@zmoの答えは、派生クラスを正しく設定する方法を示しています。

class RemoteConnection(object): 
    def __init__(self, connector): 
     self.connection = connector 

その後、あなたは、単に右のコネクタを参照して、それをインスタンス化します:

クラス自体からコネクタオブジェクトを分離し、そしてこのようなあなたのクラスの署名を設定考えてみましょう。しかし、私もこれをしないだろう
conn = RemoteConnection(TCPConnector(user, password)) 

このようにして、RemoteConnectionはプロトコルに依存しない関数をカプセル化し、プロトコル依存の部分は独立した関数またはオブジェクト(必要に応じて共通クラスから派生する可能性があります)です。コネクションの存続中にコネクターが必要な場合は、後で呼び出せるようにコネクター・オブジェクトを保管しています。そうでない場合、TCPConnectionはあなたが現在持っているresultsの値を返します。

関連する問題