2011-12-08 13 views
3

のクラスと名前空間、私は次のシナリオを持っている:モジュール、Pythonの

私は抽象クラスABを持っている、とAは、いくつかのタスクを実行するためにBを使用しています。どちらのクラスでも、抽象クラスを継承する具象クラスによって設定されるいくつかの "定数"パラメータ(現在はクラス属性として実装されています)があり、一部のパラメータは共有されています(派生した "スイート"クラスSubAおよびSubB)。

私がここで直面している問題は、名前空間がPythonでどのように構成されているかです。理想的な解決方法は、Pythonが動的スコープを持っている場合は、それらのパラメータをモジュール変数として宣言することです。拡張クラスの新しいスイートを作成するときには、新しいモジュールで上書きできます。しかし(幸いなことに、ほとんどの場合、より安全で便利なので)Pythonはそれほど機能しません。 nbodyシミュレータのようなものを想像して、より具体的なコンテキスト(ではない私の実際の問題、そしてもちろん正確にも現実的ではない)でそれを置くために

ATTRACTION_CONSTANT = NotImplemented # could be G or a Ke for example 

class NbodyGroup(object): 
    def __init__(self): 
     self.bodies = [] 

    def step(self): 
     for a in self.bodies: 
      for b in self.bodies: 
       f = ATTRACTION_CONSTANT * a.var * b.var/distance(a, b)**2 
       ... 

class Body(object): 
    def calculate_field_at_surface(self): 
     return ATTRACTION_CONSTANT * self.var/self.r**2 

その後、他のモジュールがPlanetarySystem(NBodyGroup)を実装する可能性があり、 Planet(Body)ATTRACTION_CONSTANT6.67384E-11に設定し、他のモジュールはMolecularAggregate(NBodyGroup)Particle(Body)を実装し、ATTRACTION_CONSTANT8.987E9と設定できます。

概要:派生モジュール(最初のモジュールで定義された抽象クラスを実装するモジュール)で "上書き"できるモジュールレベルでグローバル定数をエミュレートする良い選択肢は何ですか?

+0

より多くのPRができますか?あなたの実際の問題についてecise? 1つのグローバルなATTRACTION_CONSTANT定義を派生クラスを含むモジュールに置き、2つのサブクラスの値をこのグローバル変数で「上書きする」問題は何ですか? – Simon

答えて

1

mixinの使用はどうですか?あなたは(あなたの例に基づいて)ATTRACTION_CONSTANTを保持して、これらのクラスを定義するためにclass PlanetarySystem(NBodyGroup, PlanetarySystemConstants)class MolecularAggregate(NBodyGroup, MolecularAggregateConstants)を使用PlanetarySystemConstantsMolecularAggregateConstantsのためのクラスを定義することができます。

+0

1これまでのところ、これはあります。ことができます**「多重継承:現在の状況が改善されますが、私は(!多重継承は悪である) – fortran

+1

へぇをmixingsから離れて滞在することを好むだろう唯一の答えは、私はより多くのようにそれを言うと思います同意する必要があると思います。。あなたはポップたら... xDさん – Glenn

+0

あなたは正しいですが、それはプリングルズのようなものだこと私はそれを好きではない、それは複製された定数やクロスクラス参照を削除したいからです。 – fortran

0

あなたは、この場合のproperty

などを使用する必要があります。ここで

class NbodyGroup(object): 
    @property 
    def ATTRACTION_CONSTANT(self): 
     return None 
    ... 
    def step(self): 
     for a in self.bodies: 
      for b in self.bodies: 
       f = self.ATTRACTION_CONSTANT * a.var * b.var/distance(a, b)**2 

class PlanetarySystem(NBodyGroup): 
    @property 
    def ATTRACTION_CONSTANT(self): 
     return 6.67384E-11 
+0

私はこれは私が原因で循環参照の最初のアプローチを却下なり、現在の状況 – fortran

1

私が提案する可能性がいくつかある:体は、その力を算出し、グループからの定数をアクセスするように、

  1. リンク各ボディのグループに。たとえば、次のように

    class NbodyGroup(object): 
        def __init__(self, constant): 
         self.bodies = [] 
         self.constant = constant 
    
        def step(self): 
         for a in self.bodies: 
          for b in self.bodies: 
           f = self.constant * a.var * b.var/distance(a, b)**2 
           ... 
    
    class Body(object): 
        def __init__(self, group): 
         self.group = group 
        def calculate_field_at_surface(self): 
         return self.group.constant * self.var/self.r**2 
    

    プロ:これは、自動的に同じグループ内の体は力の同じ種類を発揮すべきであるという事実を適用します。 Con:意味的には、体が存在するグループとは独立して身体が存在しなければならないと主張することができます。

  2. 力の種類を指定するパラメータを追加します。たとえば、列挙型の値にすることができます。それはあなたが一般的に、そのオブジェクト内の指定されたオブジェクト(とのみ)に関連付けるプロパティをカプセル化しているため

    class Force(object): 
        def __init__(self, constant): 
         self.constant = constant 
    GRAVITY = Force(6.67e-11) 
    ELECTRIC = Force(8.99e9) 
    
    class NbodyGroup(object): 
        def __init__(self, force): 
         self.bodies = [] 
         self.force = force 
    
        def step(self): 
         for a in self.bodies: 
          for b in self.bodies: 
           f = self.force.constant * a.charge(self.force) \ 
             * b.charge(self.force)/distance(a, b)**2 
           ... 
    
    class Body(object): 
        def __init__(self, charges, r): 
         # charges = {GRAVITY: mass_value, ELECTRIC: electric_charge_value} 
         self.charges = charges 
         ... 
        def charge(self, force): 
         return self.charges.get(force, 0) 
        def calculate_field_at_surface(self, force): 
         return force.constant * self.charge(force)/self.r**2 
    

    概念的に、私はこの方法を好むだろう。しかし、実行の速度が重要な目標である場合、これは最良の設計ではないかもしれません。

これを実際のアプリケーションに翻訳してください。

+0

を向上方法を見ていない...パラメータを追加することは良いオプションですが、それはすぐに非常に冗長に取得することができます:( – fortran

1

は、古いバージョン

あなたはメタクラスを作成するためにサブクラス化__new__を試すことができますを削除しました。そして、クラスの作成時に、あなたは、PythonのSTDのinspectモジュールと、前のフレームで見ることで、サブクラスモジュールを得ることができます、1つを見つけた場合は、ここであなたの新しい定数を取得し、派生クラスのクラス属性にパッチを適用します。

私はそれが私のために非自明であるので、一瞬の実装を投稿し、そして種類の危険はありません。

編集:追加実装A.py

B.py

import inspect 
MY_GLOBAL = 'base module' 
class BASE(object): 
    def __new__(cls, *args, **kwargs): 
     clsObj = super(BASE, cls).__new__(cls, *args, **kwargs) 
     clsObj.CLS_GLOBAL = inspect.stack()[-1][0].f_globals['MY_GLOBAL'] 
     return clsObj 

import A 
MY_GLOBAL = 'derived' 
print A.BASE().CLS_GLOBAL 

今あなたがあなた自身のスコープルールを楽しんでいることができます...

+0

私は現在やっているものです:**悪」あなたがそれらを使用している特定の、狭いな理由がある場合、彼らは目的を果たす – fortran

+0

いいえ、ATTRACTION_CONSTANT変数はクラスレベルiで定義されています私のバージョン。あなたの質問と私の答えをもう一度読んでください。 – Simon

+0

もう一度完全な質問のテキストを読んでください:*今はクラス属性として実装されています*;サンプルシナリオのコードは、Pythonが動的スコープをサポートしていれば私が望むものです。実際には – fortran