2011-03-06 44 views
3

私が初めてのPythonのまわりで私の頭を取得していますし、私はここで立ち往生しています:この時点でPythonの前方宣言の内部クラス

class A: 
    def __init__(self): 
     a = foo("baa") 

class B(A): 
    b = foo("boo") 

def foo(string): 
    return string 

は私が(classesという名前)上記のファイルをロードし、この問題が発生しました:

$ python 
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from classes import * 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "classes.py", line 5, in <module> 
    class B(A): 
    File "classes.py", line 6, in B 
    b = foo("boo") 
NameError: name 'foo' is not defined 

エラーがfoo__init__から直接ではなく呼ばれ、クラスB、であるかに注意してください。クラスBもまだインスタンス化していないことに注意してください。

最初の質問:

  • なぜそれがエラーを返すのですか?私はクラスをインスタンス化していません。

移動中です。 「問題」が数行の上foo()の定義を移動することによって解決される:

def foo(string): 
    return string 

class A: 
    def __init__(self): 
     a = foo("baa") 

class B(A): 
    b = foo("boo") 

今私は

>>> x = B() 
>>> x.b 
'boo' 

を行うことができますが、私は

>>> y = A() 
>>> y.a 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: A instance has no attribute 'a' 

さらに質問を行うことはできません:

  • これは何ですか約__init__を理解していない?

これはforward declarationと同じではないと私は考えています。したがって、この質問は重複しないことを願っています。

私はDSLを実装することを目指していますが、それは主にPythonを学ぶための言い訳です。

答えて

6

まず、クラスBでは、宣言される前に関数foo()が呼び出されます。 Aは、foo()が呼び出されるのは、関数fooが定義された後にクラスがインスタンス化されるときにのみ呼び出されるためです。

self.a = foo('stirng')と言っていないので、y.aは機能しません。 a = foo('stirng')は、変数aを__ init __のスコープ内に作成するだけです。

理想的な__ init __関数は、変数selfに変数を割り当てます。

+0

攪拌とは何ですか? :) – senderle

+2

これは本当に速いタイプの文字列です。 – Dimitry

+1

確かに:) - ところで+1。 – senderle

1

__init__について理解していないことは、クラスAをインスタンス化する(つまりインスタンスを作成する)ときのみ呼び出されるということです。あなたのコードのどこにも実際にこのクラスのインスタンスを作成していないので、あなたは初期化子を呼び出すことは決してないので、決して前方宣言に入りません。

一般的に、前方参照はPythonでは問題になりません。これは、参照が必要な関数を呼び出すときにのみ評価されるためです。ここでの問題は、クラス定義が定義時刻で実行されるであることです。

  • これは、すべてのコードを保持するための新しい名前空間(ローカル変数の辞書)を定義しています。より、具体的には、ここではPythonインタプリタがclass文を満たしたときに何が起こるかです。
  • クラス定義内でコードを実行します。
  • ローカルの名前空間に格納されているものをクラス__dict__に格納します。
  • 新しい名前空間を閉じ、新しいクラスをモジュール名前空間に追加します。

もちろん、クラスを定義するためにそれを知る必要はありません。クラス定義が最初に定義されたときにクラス定義内の何かが実行されることを覚えておく必要があります。 (これはめったに問題ではありません。クラスレベルの変数はあまり一般的ではなく、通常は定義時に動的に設定する必要はありません)。

この問題は関数定義でも表示されます:あなたは

def foo(x=bar()): pass 

を行うときにbarは時間fooで定義され、そして二度とれ、一度呼び出されます。 - 各Aは、独自の変数、およびFOO( "BAA")を有する

class A(): 
    def __init__(self): 
     self.a = foo() 

a = A() 

def foo(): 
    pass 
+0

コードは実行されません: 'NameError:グローバル名 'foo'が定義されていません。しかし、私はあなたが意味することを理解しています。 – lorenzog

+0

@lorenzog:はい、それはポイントです。あなたが実際にクラスを初期化しようとすると、同じことが起こります。なぜなら、まだ定義されていない名前を探しているからです。 – katrielalex

1
class A: 
    def __init__(self): 
     a = foo("baa") 

class B(A): 
    b = foo("boo") 

は、インスタンス属性である:それは、物事を明確にしている場合


次のコードを実行してみて見ますAオブジェクトの作成時にのみ評価されます。

bはクラス属性です。すべてのBオブジェクトは同じbのコピーを共有し、クラスが定義されるとfoo( "boo")が評価されます。あなたを評価する前に

一般的には、あなたがそう長くとして、彼らが定義されますまだ存在しない関数やクラスへの参照を行うことができます参照(つまり、あなたが実際に関数を呼び出してみてくださいする前に)。

関連する問題