C ++のバックグラウンドから来たPython初心者として、Python(3.4.x)のスライス演算子は私にはばかげているように見えます。「特別ルール」の背後にあるデザイン哲学がわからない。なぜ「特別」と言うのか説明させてください。
一方では、ここでのスタックオーバーフローの回答によると、スライスオペレーターは、リストまたはリストの一部、つまり新しいリストの(深い)コピーを作成します。リンクは古い可能性があります(python 3.4.xより前)が、Python3.4.2を使用した次の簡単な実験で動作を確認しました。
words = ['cat', 'window', 'defenestrate']
newList = words[:] # new objects are created; a.k.a. deep copy
newList[0] = 'dog'
print(words) # ['cat' ...
print(newList) # ['dog' ...
一方、ここの公式ドキュメントによると:
Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:
>>>
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters
[]
明らかに、スライス演算子[:]
はここでディープコピーを実行しません。
観察から、スライス演算子が代入演算子に対して左側/右側にある場合、異なる動作を生成することが示唆されているようです。演算子が同様の動作を生成できる言語を私は知りません。結局のところ、演算子は関数であり、構文的に特別な関数であり、関数の動作は自己完結型であり、純粋にそのすべての入力によって決定される必要があります。
では、Pythonの設計哲学におけるこの「特別なルール」を正当化できるものは何でしょうか。
PS私の結論が正しくない場合、実際には2つの可能性しかありません。
1、Pythonのスライシング '演算子'は実際には演算子ではないので、私の仮定は成り立たない---それではそれは何[:]
ですか( 'スライシング演算子' )?
2、行動の違いは、観察されていないいくつかの潜在的な要因によって引き起こされます。割り当て演算子に対するスライス演算子の位置(左側/右側)は、さまざまな動作の観察と誤って共存します。彼らは因果関係を持っていません---それでは、行動の違いを引き起こす潜在的な要因は何ですか?
Python演算子は、「魔法の」メソッドの構文糖衣構文と見なすのが最適です。たとえば、x + y
はとして評価されx.__add__(y)
ます。同じように:
foo = bar.baz
になりfoo = bar.__getattr__(baz)
ます; 一方、bar.baz = foo
になりbar.__setattr__(baz, foo)
ます;Pythonの「スライス演算子」 *a[b]
は次のいずれかとして評価されます。
a.__getitem__(b)
; またはa.__setitem__(b, ...)
; 割り当てのどちら側にあるかによって異なります。この2つはまったく同じではありません(Pythonリストスライスでの割り当てのしくみも参照してください)。したがって、「手書き」で書かれています。
>>> x = [1, 2, 3]
>>> x.__getitem__(slice(None)) # ... = x[:]
[1, 2, 3]
>>> x.__setitem__(slice(None), (4, 5, 6)) # x[:] = ...
>>> x
[4, 5, 6]
データモデルのマニュアルには詳細(例えば、これらの方法を説明します__getitem__
)、あなたは読むことができます上のドキュメントをslice
あまりにも、。
以下に示すように、スライスは深いコピーではなく、浅いコピーであることに注意してください。
>>> foo = [[], []]
>>> bar = foo[:]
>>> bar is foo
False # outer list is new object
>>> bar[0] is foo[0]
True # inner lists are same objects
>>> bar[0].append(1)
>>> foo
[[1], []]
*まあ、厳密には演算子ではありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加