2011-08-12 5 views
2

オブジェクト間の変数のリンクに関する質問があります。私は自分でPythonプログラミングを学んでいるので、悪い習慣を持っているかもしれません...変数オブジェクトのようなPython共通変数をクラス間でリンクするには?

標準のconfigparserモジュールを自分で管理することで、多くの労力を節約できるモジュールをプログラミングしています。引数として渡すだけで、アプリケーションの変数のリストが表示され、すべてのジョブを自動的に実行できるようにするために "load()"と "save()"を伝える必要があります(新しい設定ファイルを作成し、変数、チェックアップデートなど)。 これはtkinter変数のような "真のオブジェクト"と完全に機能しますが、単純な数値または文字列値を含む変数の場合、オブジェクトの "アドレス"ではなく値のみがコピーされます。ここで

は一例ですが、それは問題の一部を中心に非常に簡略化されたスクリプトですが、私のモジュールのアーキテクチャを保持します:

class Sauce: 
    """Consider this class a Python standard module, so don't modify it.""" 
    def __init__(self, ingredient): 
     self.ingredient = ingredient 

    def set(self, result): 
     self.ingredient = result 

    def get(self): 
     return self.ingredient 

class Heater: 
    def __init__(self, ingredients_list): 
     self.ingredients_list = ingredients_list 

    def heat(self): 
     for item in self.ingredients_list: 
      if item['type'] == 'sauce': 
       item['ingredient'].set('caramel') 
      elif item['type'] == 'cereal': 
       item['ingredient'] = 'popcorn' 

class Cooking: 
    def __init__(self): 
     self.cereal = 'corn' 
     self.sauce = Sauce('sugarAndWater') 
     print('We will cook these ingredients: {0} and {1}'.format(self.cereal, self.sauce.get())) 
     print('After cooking we should theorically get "popcorn" and "caramel"') 

     self.heater = Heater([{'type':'cereal', 'ingredient':self.cereal}, {'type':'sauce', 'ingredient':self.sauce}]) 
     self.heater.heat() 

     print('But in reality we\'ve got:', self.cereal, self.sauce.get()) 

if __name__ == '__main__': 
    start = Cooking() 

が質問は今あります

  1. は、それが直接にOKですインスタンス化されたオブジェクト(self.heater)によって変更される引数(self.sauce)としてオブジェクトを転送しますか?
  2. 1の場合、共通変数(self.cereal)を期待どおりに機能させるための手口はありますか?
+1

で)、あなたは、オブジェクトを引数として渡すように多くのオブジェクトを「転送」し、その参照を変更していませんカウント。 self.heaterは自由に変更することができ、オブジェクトが変更可能な場合、変更は元のスコープに反映されます。共通変数を期待どおりに機能させたい場合は、intインスタンスを渡して関数内で変更し、その変更を元のスコープで確認することを意味しますか?もしそうなら、あなたはいくつかのオブジェクトの(im)変更可能性に関する問題に遭遇しており、本当に振舞いが必要な場合は、それを回避するためにラッパークラスを書くことを検討するかもしれません。 – BenTrofatter

+1

この関連する質問:http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-referenceかなり長い説明があります。 – Hoons

+0

@OlduvaiHand 申し訳ありませんが、私の考えをひどく翻訳しました。私は、«self.cerealのような変数の期待される結果を得る方法» Hoons、リンクありがとうございました –

答えて

0

数字や文字列は値によって渡されるため、他の関数/メソッドから変更することはできません。変更のために別の関数に値を渡す最も簡単な方法は、その値をコンテナ(リストまたは辞書)に入れ、代わりにそのコンテナを渡すことです。

+5

Pythonのすべてのオブジェクトは同じ方法、型はそれに入りません。しかし、数字と文字列は* immutable *です。つまり、呼び出された関数はオブジェクトを変更できないため、他の言語の呼び出しによる呼び出しと似ています。 –

0

私は本当にあなたのコードを見ていませんでしたが、これを達成する一般的な方法は、リスト(または別の変更可能なコンテナ)をラッパーとして使用することです。

>>> def a(n): 
...  n = 5 
... 
>>> def b(n): 
...  n[0] = 5 
... 
>>> k = 3 
>>> a(k) 
>>> k 
3 
>>> k = [3] 
>>> b(k) 
>>> k[0] 
5 
0

あなたが持っている問題は、引数が値として渡されることではありません。 Pythonでは、引数は参照渡しであるため、start.heater.ingredients_list[1]["ingredient"]start.sauceです。

item['ingredient'].set('caramel')start.sauceの値を変更していることが実際の問題です。そうでない場合は、文字列"caramel"のアドレスにstart.heater.ingredients_list[1]["ingredient"]を設定しています。

かいつまんで、あなたはそれが少し冗長です

a = ["sugarAndWater"] 
b = a 
b[0] = "sauce" 

を行うことです避けるが、機能はいくつかの側面として持つべきであることを覚えておくことは、この

a = "sugarAndWater" # Put "sugarAndWater" in memory and assign its address to a 
b = a    # Assign a to b, so b is the address of "sugarAndWater" 
b = "caramel"  # Put "caramel" in memory and assign its address to b, don't alter a 

古典構造をしています可能な限り効果があります。

この説明は既にインターネット上にあり、「ボックス」について話した素晴らしい記事で、これ以上のインスピレーションを受けました。それがあった場所...

編集誰かが覚えている場合:Here it isCode Like a Pythonista 1への答えで

+0

偉大な記事確かに、リンクのおかげで。 –

関連する問題