17

だから私はPythonで簡単な二分木を書いていて、出くわしました[...]

これがEllipsisオブジェクトに関連しているとは思わないが、それ以上に、無限ループと関係があるようだ(Pythonの浅いコピーのため?)。この無限ループの原因と、アクセス時に拡張中に拡張されない理由は、私が完全に失ってしまったものです。

>>> a
[[[[[], [], 8, 3], [[], [], 3, 2], 6, 3], [], 1, 4], [[], [], -4, 2], 0, 0]
>>> Keys(a)#With a+b
[0, 1, 6, 8, 3, -4]
>>> Keys(a)#With [a,b]
[8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]]
>>> Keys(a)[1]#??
[8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...], 8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]]

a+bを使用したバージョン

def Keys(x,y=[]):
    if len(x):y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)#Though it seems I was using y=y[:]+, this actually outputs an ugly mess
    return y

[a、b]を使用したバージョン

def Keys(x,y=[]):
    if len(x):y+=[x[2],Keys(x[0],y),Keys(x[1],y)]
    return y

では、[...]とは正確には何ですか?

4

9 に答える 9

25

リストがそれ自体を指している円形の構造の場合にも表示される可能性があります。このような:

>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>> 

Pythonは構造を出力できないため(無限ループになります)、省略記号を使用して構造に再帰があることを示します。


何が起こっているのか、それをどのように修正するのかはよくわかりませんが、上記の機能を修正してみます。

どちらの場合も、最初に2つの再帰呼び出しを行い、リストyにデータを追加してから、返されたデータをに再度追加しますy。これは、同じデータが結果に複数回存在することを意味します。

に追加せずにすべてのデータを収集するかy、次のようなものを使用します

return [x[2]]+keys(x[0])+keys(x[1])

または、次のようなものを使用して、呼び出しで追加を行うだけです

y += [x[2]]
keys(x[0], y) #Add left children to y...
keys(x[1], y) #Add right children to y...
return y

(もちろん、これらのスニペットは両方とも空のリストなどを処理する必要があります)

@Abganは、初期化子を本当に使用したくないとも述べy=[]ました。

于 2008-12-29T03:02:35.953 に答える
6

あなたの「木」にはそれ自体が含まれているため、サイクルが含まれていると思います。

このコードを試してください:

   a = [1,2,3,4]
   印刷する
   a.append(a)
   印刷する

最初の印刷出力:

  [1,2,3,4]

2番目の間:

  [1,2,3,4, [...]]
 

理由は使用中

デフォルトキー(x,y=[]):
 
これは間違っていて悪いことです。List は変更可能なオブジェクトであり、既定のパラメーターとして使用すると、関数呼び出し間で保持されます。したがって、各 y += "anything" 操作は同じリストに追加されます (すべての関数呼び出しで、関数は再帰的であるため...)


関数のデフォルト値として渡される可変オブジェクトの詳細については、EffbotまたはDevshedを参照してください。

于 2008-12-29T03:08:33.070 に答える
5

上記のコードは理解できませんが、[...] Python インタープリターが無限のデータ構造をスキップしていると思います。例えば:

>>> a = [0, 1]
>>> a[0] = a
>>> a
[[...], 1]

ツリー構造がループしているようです。

スライス オブジェクトに関する答えは的外れです。

于 2008-12-29T03:03:22.253 に答える
4

PrettyPrinter を使用した場合、出力は一目瞭然です。

>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
>>> pp = pprint.PrettyPrinter(indent = 4)
>>> pp.pprint(l)
[<Recursion on list with id=70327632>, 2, 3, 4]
>>> id(l)
70327632

言い換えれば、そのようなもの

ここに画像の説明を入力

于 2013-03-10T17:47:02.917 に答える
4

これが Ellipsis オブジェクトに関連しているとは思いませんが、無限ループと関係があるようです (Python の浅いコピーのため?)。この無限ループの原因と、アクセス時に展開中に展開されない理由は、私が完全に迷っているものです。

次のコードを見てください。

>>> a = [0]
>>> a.append(a)
>>> print a
[0, [...]]

Pythonはどのように印刷することになっていますか? これは、ゼロとそれ自体への参照を含むリストです。したがって、ゼロとリストへの参照を含むリストです

[0, [...]]

これには、ゼロとリストへの参照が含まれます

[0, [0, [...]]]

これには、ゼロとリストへの参照などが含まれ、再帰的に次のようになります。

[0, [0, [0, [...]]]]
[0, [0, [0, [0, [...]]]]]
[0, [0, [0, [0, [0, [...]]]]]]
...

再帰的なデータ構造自体には何の問題もありません。唯一の問題は、表示できないことです。これは、無限再帰を意味するためです。したがって、Pythonは最初の再帰ステップで停止し、以前の回答で指摘されたように、省略記号のみを出力する無限の問題に対処します。

于 2008-12-29T03:15:38.203 に答える
2

編集:上記のように、これはEllipsisオブジェクトではなく、ループされたリストの結果です。ここで銃をジャンプしました。Ellipsisオブジェクトについて知ることは、出力ではなく実際のコードでEllipsisを見つけた場合に、バックシェルフの知識として役立ちます。


PythonのEllipsisオブジェクトは、拡張スライス表記に使用されます。現在のPythonコアライブラリでは使用されていませんが、開発者は独自のライブラリで定義できます。たとえば、NumPy(またはSciPy)はこれを配列オブジェクトの一部として使用します。このオブジェクトでEllipsisがどのように動作するかを正確に知るには、tree()のドキュメントを参照する必要があります。

Pythonドキュメントから:

3.11.8省略記号オブジェクト

このオブジェクトは、拡張スライス表記で使用されます(Pythonリファレンスマニュアルを参照)。特別な操作はサポートしていません。Ellipsis(組み込み名)という名前の省略記号オブジェクトが1つだけあります。

省略記号と表記されます。

于 2008-12-29T02:56:36.480 に答える
1

わかりましたので、ポイントで:

  1. 無限のデータ構造を作成しています:

    def Keys(x,y=[])
    各呼び出しで同じ「y」を使用します。これは正しくありません。

  2. ただし、このステートメントは、無限のデータを出力するのではなく、自己参照を [...] (省略記号として知られている)printでマークするほど巧妙です。

  3. Python では、このような構造を正しくアドレス指定できるため、次のように記述できます。
    a.keys()[1][1][1]
    等々。なぜあなたはすべきではないのですか?
  4. このy = y[:]ステートメントは、リスト y を単純にコピーします。でより健全に行うことができますy = list(y)

次のコードを使用してみてください。

def キー (x、y = なし):
    y が None の場合:
        y = []
    len(x) の場合:
        y += [x[2]、キー(x[0]、y)、キー(x[1]、y)]
    y を返す

しかし、それでも私はそれがあなたを噛むことができると思います. 1 つの式の 3 か所で、同じ変数 y (同じオブジェクトを意味します) をまだ使用しています。

y += [x[2]、キー(x[0]、y)、キー(x[1]、y)]

それはあなたが本当に達成したいことですか?または、次のことを試してみてください。

def mKeys(x,y=なし):
    y が None の場合:
        y = []
    len(x) の場合:
       z = [x[2]、mKeys(x[0]、y)、mKeys(x[1]、y)]
       z を返す
   戻る []
于 2008-12-29T03:46:18.393 に答える
1

ファンクション キーの 2 つのバージョンの違いについては、次の違いに注意してください。

y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)

このステートメントの右側の値は、x[2]、および ELEMENTS OF Keys(x[0],y) と ELEMENTS OF Keys(x[1],y) を含むリストです。

y+=[x[2],Keys(x[0],y),Keys(x[1],y)]

このステートメントの右側の値は、x[2] に加えて LIST キー (x[2],y) と LIST キー (x[1],y) を含むリストです。

したがって、[a,b] を使用するバージョンでは、y がその要素として自身を含むようになります。

その他の注意事項:

  1. Python では、関数が定義されるときにデフォルト値オブジェクトが一度作成されるため、最初のバージョンは例のようには機能しません。いくつかのキーの複数のコピーが含まれます。簡単に説明するのは難しいですが、Keys の各呼び出しで x、y の値を出力することで、ある程度のアイデアを得ることができます。

    これは、python 2.5.2 を使用して私のマシンで関数を実行することで確認されています。

  2. また、デフォルト値は関数定義時に一度だけ定義されるため、最初の二分木のキーが y に残るため、関数が初めて正しく動作しても、別の a で呼び出した場合は動作しません。

    これは、Keys(a) を 2 回呼び出すか、2 つの異なるリストで呼び出すことで確認できます。

  3. この問題では、2 番目のパラメーターは必要ありません。関数は次のようになります。

    def Keys(a): if a = []: return [] else: return [a[2]]+Keys(a[0])+Keys(a[1])

    再帰関数の定義には、基本的に、サブ問題の解決と結果の結合の 2 つの部分が含まれます。あなたのコードでは、結合結果の部分が 2 回繰り返されます。

于 2008-12-29T06:20:54.913 に答える
1

この問題は、リスト要素の 1 つがリスト自体を参照しているためです。したがって、すべての要素を印刷しようとすると、決して終了しません。

図:

x = range(3)
x.append(x)
x[3][3][3][3][3][0] = 5
print x

出力:

[5, 1, 2, [...]]

x[3]自分自身への言及xです。についても同様ですx[3][3]

これはここでよりよく視覚化できます

于 2016-07-23T16:35:28.607 に答える