コードに若干の変更を加えました。
class A:
def __init__( self, name ):
self.name = name
self.owner = None
def setChild( self, l ):
l.owner = self
def getTopParent( self , depth=0):
if( self.owner == None ): # None == top parent
print( ' ' * depth + "Got top: %s" % self.name )
print( ' ' * depth + "Returning: %s" % self)
return self
else:
print( ' ' * depth + "checking %s" % self.name )
tmp = self.owner.getTopParent(depth=depth + 1)
print( ' ' * depth + "returned from call while checking %s" % self.name)
print( ' ' * depth + "returned value was: %s" % tmp)
a = A( "parent" )
b = A( "child1" )
c = A( "child2" )
d = A( "child3" )
a.setChild( b )
b.setChild( c )
c.setChild( d )
d_top_parent = d.getTopParent()
print('----------------')
print d_top_parent
これで、 を呼び出したときに何が起こっているかを確認できますd.getTopParent()
。出力は次のとおりです。
checking child3
checking child2
checking child1
Got top: parent
Returning: <__main__.A instance at 0x0000000002DE8DC8>
returned from call while checking child1
returned value was: <__main__.A instance at 0x0000000002DE8DC8>
returned from call while checking child2
returned value was: None
returned from call while checking child3
returned value was: None
----------------
None
真ん中に、最上位の親が見つかって返されたことがわかります。ただしreturn
、[1] からこの関数が呼び出された場所に戻ります。そのため、「checking child1」呼び出しに戻るだけです。
「checking child1」の呼び出しに戻るとself.owner.getTopParent()
、これは と呼ばれ、最上位の親が返されます。元のバージョンでは、その後にコードがなかったので、実行は関数の「最後にドロップオフ」しました。私のバージョンでは、返された値をself.owner.getTopParent()
変数に格納しtmp
て出力するので、それが何であったかを確認できます。しかし、それは関数の最後にも落ちます。
Python では、関数の最後に到達することは と同等であるためreturn None
、それが「child1 のチェック」の呼び出し元に返されます。そのため、「checking child2」呼び出しはNone
から返された値を取得しますself.owner.getTopParent()
。そして、関数の最後をドロップオフしてNone
、呼び出し元に戻ります。[2] 等々。
私のバージョンに追加return tmp
すると、ブランチでの印刷後に次のelse
出力が得られます。
checking child3
checking child2
checking child1
Got top: parent
Returning: <__main__.A instance at 0x0000000002E68DC8>
returned from call while checking child1
returned value was: <__main__.A instance at 0x0000000002E68DC8>
returned from call while checking child2
returned value was: <__main__.A instance at 0x0000000002E68DC8>
returned from call while checking child3
returned value was: <__main__.A instance at 0x0000000002E68DC8>
----------------
<__main__.A instance at 0x0000000002E68DC8
これで、各「checking childN」呼び出しは、呼び出しから値を受け取り、それを次に外側の呼び出し元にself.owner.getTopParent()
返します。
何かを呼び出して、その戻り値をどこかに移動させたい場合は、どこに移動するかを指定する必要があります。これは、代入ステートメントを使用してどこかに格納するか、引数として別の呼び出しに直接渡すか、直接返すことができます。この行のような裸の呼び出しがある場合:
self.owner.getTopParent()
その後、返された値はどこにも行かず、どのような目的にも使用できません[3]。
呼び出している関数がたまたま現在の関数と同じ名前であるという事実は関係ありません。再帰呼び出しは、あらゆる点で非再帰呼び出しとまったく同じように機能します。多くの人にとって再帰がいかに混乱を招くものであるかにはいつも驚かされますが、これはおそらく、再帰を学んでいたときのことを覚えていないからでしょう。:)
return
[1] 考えてみれば、このように動作する必要があります。他の関数が返されたときに、戻り値が最も外側の呼び出しにジャンプする (対話型インタープリターで実行している場合は、出力として表示される) 場合、他の関数を呼び出す関数をどのように作成できますか?
[2]への呼び出しからのNone
受信とは関係ありません。None
self.owner.getTopParent()
[3] 対話型インタープリターで直接入力した場合を除き、Python が戻り値を出力するので、それが何であったかを確認できます。また、こっそりと変数に保存する_
ので、見た後に必要だと判断した場合は、それが何であったかを知ることができます。しかし、原則として、そして他のコンテキストでは、呼び出したものの戻り値で何もしないと、値が失われます。