1

でチェーンの最上位ノードを取得しようとしていますgetTopParent()。を印刷するself.nameと、実際に親インスタンスの名前が印刷されます。ただし、戻るselfと、None が返されます。どうしてこれなの?

class A:
    def __init__( self, name ):
        self.name = name
        self.owner = None
    def setChild( self, l ):
        l.owner = self
    def getTopParent( self ):
        if( self.owner == None ): # None == top parent
            print( "Got top: %s" % self.name )
            return self
        else:
            print( "checking %s" % self.name )
            self.owner.getTopParent()

a = A( "parent" )
b = A( "child1" )
c = A( "child2" )
d = A( "child3" )
a.setChild( b )
b.setChild( c )
c.setChild( d )

print( d.getTopParent() )
>>> checking child3
    checking child2
    checking child1
    Got top: parent
    None
4

4 に答える 4

7

あなたは戻る self.owner.getTopParent()必要があります!

Python では、実際にreturnステートメントを使用して関数から何かを返す必要があります。そうでない場合Noneは返されます。

于 2012-09-04T22:43:52.763 に答える
3

returnで使用

else:
    print( "checking %s" % self.name )
    return self.owner.getTopParent()

デフォルトのNone戻り値である場合、次のように出力されます。

checking child3
checking child2
checking child1
Got top: parent
<__main__.A instance at 0xb77a628c>
于 2012-09-04T22:44:52.787 に答える
2

コードに若干の変更を加えました。

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受信とは関係ありません。Noneself.owner.getTopParent()

[3] 対話型インタープリターで直接入力した場合を除き、Python が戻り値を出力するので、それが何であったかを確認できます。また、こっそりと変数に保存する_ので、見た後に必要だと判断した場合は、それが何であったかを知ることができます。しかし、原則として、そして他のコンテキストでは、呼び出したものの戻り値で何もしないと、値が失われます。

于 2012-09-04T23:40:41.423 に答える
1

の側で戻るselfとうまくいきました。ただし、サイドの再帰呼び出しは何も返しません。代わりに使用してください。Trueifelsereturn self.owner.getTopParent()

于 2012-09-04T22:45:43.073 に答える