2012-08-08 34 views
11

は完全にオブジェクト指向行かなくても(例えば、最適化の目的のために)状態を維持するために、そこpythonic方法はありますか?より良い私の質問を説明するためにクラスなしでPythonで状態を維持する方法は?

は、ここで私はJavaScriptで頻繁に使用するパターンの例です:

var someFunc = (function() { 
    var foo = some_expensive_initialization_operation(); 
    return someFunc (bar) { 
     // do something with foo and bar 
    } 
}()); 

外部これは、オブジェクトを初期化する必要があるか、そのようなものがないと、他のどのようなだけの機能です、しかし、クロージャを使うと計算値を1回だけ使用でき、それを本質的に定数として使用できます。

この例は、正規表現を最適化するときです。re.compileを使用すると便利で、matchsearch操作のコンパイル済みバージョンが保存されます。 Pythonでこれを行うには私の知っている

唯一の方法は、モジュールのスコープ内の変数を設定することにより、以下のとおりです。

compiled_regex = compile_my_regex() 

def try_match(m): # In reality I wouldn't wrap it as pointlessly as this 
    return compiled_regex.match(m) 

やクラスを作成することによって:

class MatcherContainer(object): 
    def __init__(self): 
     self.compiled_regex = compile_my_regex() 
    def try_match(self, m): 
     self.compiled_regex.match(m) 

my_matcher = MatcherContainer() 

前者のアプローチが広告であります-hocであり、その上に宣言されている関数と変数が互いに関連していることはあまり明確ではありません。また、モジュールの名前空間を少し汚染してしまいます。これはあまり幸せではありません。

後者のアプローチは、定型的に冗長で少し重いようです。

私はこれに対処するための考えることができる唯一の他の方法は、すべてのクリーンなように、別のファイル(モジュール)には、このような任意の機能を考慮し、関数だけをインポートすることです。

これに対処する方法の詳細経験豊富なPythonersからの任意のアドバイスはありますか?それとも心配しなくても、問題を解決することができますか?

+1

私は個人的にあなたのクラスの作成に問題は見ません。冗長性は良いです。 "明示的なものは暗黙的なものよりも優れています。" " – tMC

+0

少なくともそのクラスの使用をより控え目にする方法の1つは、' try_match'の名前を '__call__'に変更することです。しかし、@ glglglの答えのように、あなたのjavascriptコードは実際に直接Pythonに変換されます。 – lvc

+0

あなたの最初の例でsomeFuncが正しく呼び出されましたか?それとも関数定義であるべきですか? – soulcheck

答えて

10

また、デフォルトの引数を指定してこれを達成することができます:

def try_match(m, re_match=re.compile(r'sldkjlsdjf').match): 
    return re_match(m) 

デフォルト引数のみモジュールのインポート時に、一度だけ評価されているため。

それとももっと簡単:

try_match = lambda m, re_match=re.compile(r'sldkjlsdjf').match: re_match(m) 

か、まだ最も簡単:

try_match = re.compile(r'sldkjlsdjf').match 

を。これは、(実際にはとにかくreモジュールで内部的にキャッシュされている)の再コンパイル時間がないだけを節約するだけでなく、 'match'メソッドのルックアップ。ビジーな機能やタイトなループでは、それらの '。'決議が追加される可能性があります。

+0

答えをありがとう。私はモジュールキャッシングについて知っていますが、タイトなループでは単一の正規表現を使用するスクリプトでも、組み込みキャッシングに頼るのではなく、re.compileを使用することで大幅なパフォーマンス向上を得ています。 – Cera

5

def create_matcher(re): 
    compiled_regex = compile_my_regex() 
    def try_match(m): 
     return compiled_regex.match(m) 
    return try_match 

matcher = create_matcher(r'(.*)-(.*)') 
print matcher("1-2") 

については何?

しかし、クラスは、ほとんどの場合、より良く、きれいです。

+1

+1 "しかし、ほとんどの場合、クラスはより良く、よりクリーンです。" – tMC

12

あなたはJavaScriptでクロージャを定義するのと同じ方法で、Pythonでクロージャを定義することができます。

def get_matcher(): 
    compiled_regex = compile_my_regex() 

    def try_match(m) 
     return compiled_regex.match(m) 

    return try_match 

しかし、Pythonの2.xの閉鎖に読み取り専用されている(上記の例では、関数呼び出し内compiled_regexに再割り当てすることはできません)。クロージャ変数が変更可能なデータ構造(例えばlist,dict,set)であれば、関数呼び出し内でクロージャ変数を変更することができます。

def get_matcher(): 
    compiled_regex = compile_my_regex() 
    match_cache = {} 

    def try_match(m): 
     if m not in match_cache: 
      match_cache[m] = compiled_regex.match(m) 

     return match_cache[m] 

    return try_match 

は、Python 3.xのでは、関数呼び出しで閉鎖変数に再割り当てする nonlocalキーワードを使用することができます。 (PEP-3104)

また、Pythonでクロージャに以下の質問を参照してください。

+1

ちょうど追加する:Python 3は、クローズオーバー変数への明示的な書き込みアクセスを与えるために使用できる '非ローカル 'を導入しています。 [(PEP 3104)](http://www.python.org/dev/peps/pep-3104/) – rwos

+1

は答えを – Imran

+0

で更新しました。これは少し混乱しています。これが実行されるたびに 'get_matcher()'の本体全体が評価されないのはなぜですか?あるいは、 'try_match = get_matcher()'のようなことをする目的はありますか? – Cera

1

アン頻繁に使用される規則は示すために下線でプライベートモジュールレベルのグローバルの前にありますそれらはモジュールのエクスポートされたAPIの一部ではありません:

# mymodule.py 

_MATCHER = compile_my_regex() 

def try_match(m): 
    return _MATCHER.match(m) 

これを行うことはお勧めできません。関数クロージャーの隠し変数にすることをお勧めします。

2

任意の機能で属性を隠すことができます。関数名はグローバルなので、他の関数で検索することができます。たとえば、次のように

def memorize(t): 
    memorize.value = t 

def get(): 
    return memorize.value 

memorize(5) 
print get() 

出力:

5 
あなたは、単一の機能の状態を保存するためにそれを使用することができます

def memory(t = None): 
    if t: 
     memory.value = t 
    return memory.value 

print memory(5) 
print memory() 
print memory() 
print memory(7) 
print memory() 
print memory() 

出力:

5 
5 
5 
7 
7 
7 

確かにその有用性制限されています。私はthis questionのSOだけで使用しました。

関連する問題