2013-03-19 11 views
9

一部の関数では、パラメータ化されない '定数'値(後で再定義するようには設計されていない)が必要です。デフォルトの引数はeach functionの場合stored only onceですが、いくつかはパラメータとして置くことはあまり意味がありません(つまり、signatureの一部である)。 (非常に有用ではない)は、例えば:Pythonでは、関数の '定数'を一度だけ格納する方法はありますか?

def foo(bar): 
    my_map = {"rab": barType, "oof": fooType} 
    return my_map.get(bar,defaultType)() 

これは各呼び出しのために再定義するような一定のCPU時間とRAMスペースを無駄。他の方法としては、モジュールレベルのグローバルなどの定数を格納する方法や、関数を呼び出し可能なクラスにする方法などがあります。

モジュールレベルがグローバル道をやって、私は接頭辞私と定数変数(と意味)「_」それは誰の利益のためにそこにないであることを示します。

_my_map = {"rab": barType, "oof": fooType} 
def foo(bar): 
    return _my_map.get(bar,defaultType)() 

それともクラス道にそれを変換:それでも私はすべてshame of using何かas discouraged as globalsの話をしない、モジュールの名前空間はわずか「汚染」を感じます。私はインスタンスを作成する必要性を回避するために、__call__classmethodます

class foo: 
    my_map = {"rab": barType, "oof": fooType} 
    @classmethod 
    def __call__(cls,bar): 
     return cls.my_map.get(bar,defaultType)() 

は十分ニシキヘビこれらの解決策はありますか?

他の方法がありますか?

このような「定数」を使用することは習慣としても大丈夫ですか?

は私の例では、これらのオブジェクトは、必ずしも実際の定数ではなく、その目的によりそのまま使用(と考えることができます)。機能上の属性として

+0

これらの回答の1つで言及したように(私も同意します)、グローバル変数であることを具体的に説明するコメントを入れたいと思っています。 Pythonをよく理解しているより洗練されたソリューションにも私は興味があります。 – PascalVKooten

+0

グローバル定数は問題ありません。問題を引き起こすのはグローバル*状態*です。 – user2357112

答えて

10

セットを:

def foo(bar): 
    return foo.my_map.get(bar, defaultType)() 
foo.my_map = {"rab": barType, "oof": fooType} 

 

呼び出し可能なクラスやクロージャはIMO十分に簡単ではありません。あなたはまた、クロージャを使用することができ

+0

*クラス定義*内でこれを行うことができるかどうかを知ることができますか?インスタンス、クラス、または静的メソッドのいずれかを試してみると、AttributeErrorまたはNameErrorが返されます。可能ならば、関数の属性を(ファイル内の行に関して)関数定義に「近づけて」おくことができるのかどうかも明らかではありません。 – n611x007

+0

これらは両方とも動作します:https://gist.github.com/anossov/5411655クラスレベルの定数より優れているかどうかはわかりません。 –

+0

私は間違っていますが、私は実際にインスタンスメソッドでそれらをテストしていませんでした。(私は '@ staticmethod'や' classmethod'でこれをやろうとしましたが、場合によっては* "AttributeError:instancemethodオブジェクトに私の本当の問題は* @ classmethod *と* @ staticmethod *デコレータを使っているようです。 https://gist.github.com/naxa/5411709 – n611x007

2

def make_foo(): 
    my_map = {"rab": barType, "oof": fooType} 
    def foo(bar): 
     return my_map.get(bar,defaultType)() 
    return foo 
foo = make_foo() 
+0

'make_foo()'の名前を 'foo()'に変更することもお勧めしますが、 'foo'が多すぎるかもしれません;-)。 – martineau

3

私見を、モジュールレベルの定数と間違って何もありません。 PEP8によると、定数はこのように、すべて大文字でなければなりません

注:

_MY_MAP = {"rab": barType, "oof": fooType} 
def foo(bar): 
    return _MY_MAP.get(bar,defaultType)() 

標準ライブラリの正規表現モジュールは、このスタイルを使用し、多くの確立されたサードパーティ製のライブラリが同様に行います。自己完結型できるだけ何かを作るために

egrep "^_?[A-Z]+ =" * 
+0

モジュールレベルのグローバルが外部に対して意味があるなら、私はまた、Pythonでは有用であるとも思っています。しかし、このような関数ヘルパーは、その名前だけが所属する場所とその目的を示すため、このようにあまりよく構成されていません。 – n611x007

+0

私はあなたのポイントを見ることができます。私は、プライベートモジュールのレベル定数は比較的一般的で、おそらくPythonではアンチパターンとは考えられないと指摘したいと思います。それは味の問題だと思います。 –

2

:あなたが確信していない場合は、ちょうどあなたのsite-packagesディレクトリとgrepに行きます。あなたはfunction object(別名ファンクタ)クラスを作成し、それを__call__()方法またはclassmethod(おそらく両方ではない)を得ることができます:

class bazType(object): pass 
class barType(object): pass 
class fooType(object): pass 

class Foo(object): 
    _DEFAULT_TYPE = bazType 
    _MY_MAP = {"rab": barType, "oof": fooType} 

    def __call__(self, bar): 
     return self._MY_MAP.get(bar, self._DEFAULT_TYPE)() 

    @classmethod 
    def foo(cls, bar): 
     return cls._MY_MAP.get(bar, cls._DEFAULT_TYPE)() 

# using classmethod 
print Foo.foo("rab") 

# using __call__ method 
foo = Foo() 
print foo("baz") 

# alternative way to use classmethod 
foo = Foo.foo 
print foo("oof") 

をさらに別の代替は、私が勝った、staticmethodを定義することですそれは他の2つにとても似ているので説明していますが、あなたは私が望むアイデアを得ることができます。

関連する問題