delはいつPythonで役に立ちますか?


374

pythonがdelキーワードを必要とする理由を本当に考えることはできません(ほとんどの言語には同様のキーワードがないようです)。たとえば、変数を削除するのではなく、単に変数に割り当てることができNoneます。また、辞書から削除する場合、delメソッドを追加することができます。

delPythonで維持する理由はありますか、それともPythonのガベージコレクション前の痕跡ですか?


46
歴史的注記:Pythonには最初からガベージコレクションがありました。2.0より前のバージョンでは、Pythonのガベージコレクターは参照の循環を検出できませんでしたが、それはとは関係ありませんでしたdel
Steven Rumbalski、2011年

28
@Steven Rumbalksi、それはデルと関係があります。Delは参照サイクルを壊すために使用されました。
Winston Ewert、

6
ただし、del常に使用できるため、ガベージコレクション前の痕跡ではありませんused = None。特定の構文を使用することは常に理にかなっています。現在、サイクリックGCをご用意しておりますので、どちらも使いたいケースは少ないです。
Winston Ewert、

3
>そしてほとんどの言語には同様のキーワードがないようですほとんどのガベージコレクションされた言語にはありません(または変数を収集できることをGCに示唆するためにのみ使用します)。最も古い言語はそうでした:ERASECLEAR
-QuickBasic

回答:


499

まず、ローカル変数以外の他のものを削除できます

del list_item[4]
del dictionary["alpha"]

どちらも明らかに役立つはずです。第二delに、ローカル変数で使用すると、意図がより明確になります。比較:

del foo

foo = None

del foo変数をスコープから削除することが目的であることがわかっています。それがそれをしfoo = Noneていることは明らかではありません。誰かが割り当てたばかりなら、foo = Noneそれはデッドコードだったと思うかもしれません。しかし、コードdel fooを書いている人が何をしようとしていたのかがすぐにわかります。


51
+1、はい。何かを割り当てると、後でそれを使用する意図が伝わります。delメモリを大量に使用する計算で実際に使用されているのを見ただけですが、それを見るとすぐに、なぜそれが必要なのかがわかりました。
11

17
リストまたは辞書から削除するユースケースは、メソッドで簡単に置き換えることができます(質問で述べたように)。意図を示すためにを使用することに同意するかどうかはわかりませんがdel(コメントが言語に追加しなくても同じことができるため)、それが最良の答えだと思います。
Jason Baker

6
@JasonBaker、メソッドに付与されています。ただし、スライスなどを削除すると、メソッドを使用したほうが扱いにくくなります。はい、コメントを使用できます。しかし、私はステートメントの使用は、言語の一部としてのコメントよりも優れていると思います。
Winston Ewert

2
@JasonBaker:インテントだけではなく、これらの2つの構文は2つの非常に異なる機能を実行します。
PavelŠimerda2014

2
また、それぞれの辞書から削除することによっても処理されます。len()同じ方法で機能に異議を唱えることもできます。これが事実である場合、質問は意見ベースまたは味覚ベースとして閉じられた可能性があります。Pythonは、メソッドに依存するのではなく、基本的な操作にプリミティブを提供する傾向があります。
PavelŠimerda2014

161

delPython言語リファレンスから)何をするかのこの部分があります:

名前を削除すると、ローカルまたはグローバル名前空間からその名前のバインディングが削除されます

None名前に割り当てても、名前空間からの名前のバインディングは削除されません。

(名前のバインディングを削除することが実際に役立つかどうかについては、ある程度の議論があるかもしれませんが、それは別の質問です。)


22
-1ポスターはすでにこれを明確に理解しており、名前のバインディングを削除する理由を尋ねています。
Winston Ewert、

71
@Winston Ewert:代替としてdel割り当てることを提案したため、ポスターが名前のバインディングを削除することを理解したかどうかはわかりませんNone
Steven Rumbalski、2011年

8
@Steven、ポスターは、変数の削除(名前の削除)とNoneの割り当てを明確に対照しています。Noneを割り当てることができるのになぜ変数を削除する必要があるのか​​、彼にはわかりません。以前にその名前にバインドされていたものへの参照を解放するという点で同じ効果があります。
Winston Ewert、

19
@Winston Ewert:はっきりしません。おそらく、「以前にその名前にバインドされていたものへの参照を解放するという点で同じ効果がある」と述べていることは明らかです。しかし、それはの(明らかに?)ではないことが上げ削除した後、名前を使用しようとすることで全体の話NameError。グレッグ・ヒューギルはこれを非常に区別しています。そして、ポスターが「明確に」理解したことについてのあなたの主張を私に不明確にするのは、この区別です。
Steven Rumbalski、2011年

9
@Winston Ewert同意しません。しかし、十分に言った。私たちは両方とも私たちの訴訟を起こしました。
Steven Rumbalski、2011年

44

私がdel便利だと思った場所の1つは、forループ内の無関係な変数をクリーンアップすることです。

for x in some_list:
  do(x)
del x

これで、forループの外でxを使用すると、xが未定義になることが確実になります。


1
delここの行はインデントされているはずですか(ループの一部など)?
Sam

11
@サム、いいえ彼らは意図されていません。
user5319825

7
@サムいいえ、ここでの考え方は、ループの最後の反復の後(some_listの最後の要素でdo()を実行した後)、xはsome_listの最終値への参照のままになるということです。del xは、これがそのまま割り当てられたままにならないようにします。
マシュー

12
これはNameError: name 'x' is not defined、リストが空の場合に発生します。
WofWca

18

変数の削除は、Noneに設定することとは異なります

で変数名を削除するdelことは、めったに使用されないものですが、キーワードなしでは簡単には達成できません。を記述して変数名を作成できる場合a=1は、理論的にはaを削除して元に戻すことができると便利です。

削除された変数にアクセスしようとするとNameErrorが発生するため、場合によってはデバッグが容易になります。

クラスインスタンス属性を削除できます

Pythonでは、次のように記述できます。

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

属性をクラスインスタンスに動的に追加することを選択した場合は、次のように記述して、属性を元に戻せるようにしたいはずです。

del a.a

16

例外の検査にdel使用sys.exc_info()しているときに使用する必要がある具体的な例があります(他にもあるかもしれませんが、これについては私が知っています)。この関数は、タプル、発生した例外のタイプ、メッセージ、およびトレースバックを返します。

通常、最初の2つの値はエラーを診断して対処するのに十分ですが、3番目の値には、例外が発生した場所と例外がキャッチされた場所の間のコールスタック全体が含まれます。特に、次のような場合

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

トレースバックtbは、コールスタックのローカルで終わり、ガベージコレクションできない循環参照を作成します。したがって、次のことを行うことが重要です。

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

循環参照を解除します。sys.exc_info()メタクラスのマジックのように、を呼び出す必要がある多くの場合、トレースバック便利なので、例外ハンドラーを離れる前に、トレースバックをクリーンアップする必要があります。トレースバックが必要ない場合は、すぐに削除するか、次のようにしてください。

exc_type, exc_value = sys.exc_info()[:2]

それをすべて一緒に回避するため。


18
ガベージコレクターが収集しないというのは、もはや本当ではありません。ただし、このサイクルは収集を遅らせます。
Winston Ewert、

これはあまり関連性がなく、オペレーションの質問には答えません。
WhyNotHugo

15

ただ別の考え。

Djangoのようなフレームワークでhttpアプリケーションをデバッグするとき、特にそれが非常に長いリストである場合、以前に使用された無用で混乱した変数でいっぱいのコールスタックは、開発者にとって非常に苦痛になる可能性があります。したがって、この時点で、名前空間の制御が役立つ可能性があります。


12

"del"を明示的に使用することも、変数をNoneに割り当てるよりも良い方法です。存在しない変数を削除しようとすると、ランタイムエラーが発生しますが、存在しない変数をNoneに設定しようとすると、Pythonは自動的に新しい変数をNoneに設定し、変数をそのままにします。それがあった場所で削除したかった。だからデルはあなたがあなたの間違いを早く見つけるのを助けます


11

上記の回答にいくつかのポイントを追加するには: del x

の定義xr -> orオブジェクトを指す参照)を示しますoが、ではなくをdel x変更します。これは、に関連付けられたオブジェクトではなく、オブジェクトへの参照(ポインタ)に対する操作です。ここで重要なのは、とを区別することです。roxro

  • から削除しlocals()ます。
  • そこに属しているglobals()場合xは削除します。
  • スタックフレームから削除します(参照を物理的に削除しますが、オブジェクト自体はスタックフレームではなくオブジェクトプールに存在します)。
  • 現在のスコープから削除します。ローカル変数の定義のスパンを制限すると非常に便利です。そうしないと、問題が発生する可能性があります。
  • コンテンツの定義ではなく、名前の宣言についてです。
  • これは、xどこをx指すかではなく、どこに属するかに影響します。メモリの唯一の物理的な変化はこれです。たとえばx、が辞書またはリストにある場合、(参照として)そこから削除されます(オブジェクトプールから削除されるとは限りません)。この例では、その辞書はスタックフレーム(locals())であり、と重複していglobals()ます。

6

numpy.loadの使用後にファイルを強制的に閉じる:

ニッチな使用法かもしれませんが、を使用numpy.loadしてファイルを読み取るときに便利です。たまにファイルを更新し、同じ名前のファイルをディレクトリにコピーする必要があります。

以前delはファイルをリリースして、新しいファイルにコピーできるようにしていました。

withコマンドラインでプロットをいじっていて、タブをあまり押したくなかったので、コンテキストマネージャーを避けたいことに注意してください。

この質問を参照してください。


Python Image Library(PIL)で読み込まれた画像と似たようなものがあります。私は画像を開いて、それが特定の大きさを持っている場合、ファイルを削除したいと思いました。ただし、このファイルはPythonでまだ使用されていました。そのため、「del img」と言って、ファイルを削除できました。
フィジカル

2
これは時に保証するものではありません言語仕様として実装の詳細であることに注意してください__del__()ゴミオブジェクトのメソッドが呼び出されたかさえあれば、それはすべてで呼び出されます。したがって、__del__()メソッドがしばらくの間(オブジェクトがガベージになった直後に)呼び出されることを期待する以外に、リソースを解放する方法を提供しないAPI は、ある程度壊れています。
BlackJack

6

del__init__.pyファイルでよく見られます。__init__.pyファイルで定義されているグローバル変数は自動的に「エクスポート」されます(これはに含まれますfrom module import *)。これを回避する1つの方法はを定義する__all__ことですが、これは面倒になる可能性があり、誰もが使用するわけではありません。

たとえば、次の__init__.pyようなコードがある場合

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

次に、モジュールはsys名前をエクスポートします。代わりに書く必要があります

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys

4

何のdelために使用できるかの例として、私はこのような状況で便利だと思います:

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

これらの2つの機能は、異なるパッケージ/モジュールにすることができ、プログラマは、どのようなデフォルト値の引数知っている必要はありませんcf、実際に持っています。したがって、kwargsをdelと組み合わせて使用​​すると、「Cのデフォルト値が必要」と言うことができます。これをNoneに設定する(またはこの場合はそのままにします)。

あなたは次のようなもので同じことをすることができます:

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

ただし、前の例の方がより乾燥していてエレガントです。


3

delはいつPythonで役に立ちますか?

これを使用して、スライス構文の代わりに配列の単一の要素を削除できますx[i:i+1]=[]。これは、たとえばos.walkディレクトリにいる要素を削除したい場合に役立ちます。ただし、[].remove(index)メソッドを作成するだけでよいので(この.removeメソッドは実際には値の最初のインスタンスの検索と削除です)、このために役立つキーワードとは考えません。


7
[].pop(index)[].remove(item)"index"値について話すときに名前付きの変数を使用しないでください。混乱を招きます。
スキー

@Ski popはインデックスを使用します。これは有効な回答ですが、これらの回答の半分は、Delを使用した例であり、Noneでも機能します。Noneに設定されたリストオブジェクトはまだリストにありますが、delはアイテムを削除します。
user5389726598465

3

delNumpyで大きなデータを処理するときの疑似手動メモリ管理に役立つことがわかりました。例えば:

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

これは、Python GCが追いつけないときにシステムが狂ったようにスワップするときにスクリプトを粉砕停止状態にすることと、緩いメモリしきい値を下回って完全にスムーズに動作することの違いであり、マシンを使用して閲覧するための十分なヘッドルームを残しますそしてそれが働いている間コード。


2

delが独自の構文を持っている理由の1つは、バインディングまたは変数を操作し、それが参照する値を操作しない場合、関数に置き換えることが難しい場合があるためだと思います。したがって、delの関数バージョンを作成する場合、コンテキストを渡す必要があります。delfooはglobals()。remove( 'foo')またはlocals()。remove( 'foo')になる必要があり、乱雑になります。読みにくい。それでも私は、デルを取り除くことは、その一見珍しい使用を考えると良いだろうと言います。しかし、言語機能/欠陥を削除することは苦痛な場合があります。多分python 4はそれを削除します:)


2

受け入れられた答えについて詳しく説明して、変数をに設定Noneすることと、で削除することの間のニュアンスを強調しますdel

変数foo = 'bar'と次の関数定義が与えられます:

def test_var(var):
    if var:
        print('variable tested true')
    else:
        print('variable tested false')

最初に宣言されるtest_var(foo)variable tested true、期待どおりの結果になります。

今試してください:

foo = None
test_var(foo)

をもたらすvariable tested false

この動作を以下と比較してください。

del foo
test_var(foo)

これは今発生しNameError: name 'foo' is not definedます。


0

さらに別のニッチの使用:でpyroot ROOT5又はROOT6と、「デル」は無もはや既存のC ++オブジェクトと呼ばれるPythonオブジェクトを除去するのに有用であり得ます。これにより、pyrootの動的ルックアップで、同じ名前のC ++オブジェクトを見つけ、それをpython名にバインドできます。したがって、次のようなシナリオを持つことができます。

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

うまくいけば、このニッチはROOT7のより健全なオブジェクト管理で閉じられるでしょう。


0

「del」コマンドは、配列内のデータを制御するのに非常に役立ちます。次に例を示します。

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

出力:

['B'、 'C​​'、 'D']


-2

一度使用しなければならなかった:

del serial
serial = None

使用するのは:

serial = None

すぐに再び開くのに十分な速さでシリアルポートを解放しませんでした。そのレッスンから、私はdel本当に「これをGCして、完了するまで待つ」ということを意味することを学びました。これは、多くの状況で本当に役立ちます。もちろん、system.gc.del_this_and_wait_balbalbalba(obj)


5
うーん...それは本当に違いを生むべきではありませんでした。しかし、あなたの問題はそれが導入した余分な遅延によって修正されたのでしょうか?
Winston Ewert

3
どんなドキュメントでもこれをGCに戻すことはできないと思います。私はGCに依存してを呼び出すの__del__()はPythonでは常に間違っていると思います(ただし、この設計の理由はわかりませんwith)。コンテキストマネージャーAPI(ステートメント)を使用することをお勧めします。
PavelŠimerda14年

1
それはある種のブードゥープログラミングです。方法の説明や注意を参照してください)デル__(.__オブジェクトのドキュメント詳細については、のみ参照カウントとCPythons現在の実装について説明し、このことを覚えておいて。その他のPython実装(PyPy、Jython、IronPython、Brythonなど)または将来のCPython実装では、別のガベージコレクション方式が使用される可能性があります。Jythonは、オブジェクトをすぐに削除しないJVM GCを使用します。このserialモジュールはJythonでも機能するため、ハックはそこで機能しません。
BlackJack

ところで、gc.collectは明示的にリサイクルする方法です。ほとんどのPython実装でサポートされています。
tdihp 2015年

-2

delは、多くの言語で「未設定」に相当し、別の言語からpythonへの相互参照ポイントとして使用されます。人々は、最初の言語で使用していたのと同じことを行うコマンドを探す傾向があります...また、設定varを ""に設定しても、varをスコープから実際に削除することもありません。値を空にするだけです。var自体の名前はメモリに保存されますが、なぜですか?メモリを大量に消費するスクリプトで..ゴミをそのいやいや、とにかく...後ろに置いておく...すべての言語には、何らかの形の「unset / delete」var関数があります..なぜPythonではないのですか?


7
delはガベージコレクターをすぐに起動せず= None、長期的にはガベージを残しません。Pythonのガベージコレクションに骨を折ることができます。
SilverbackNet

-3

Pythonのすべてのオブジェクトには識別子、Type、参照カウントが関連付けられています。delを使用すると、参照カウントが減り、参照カウントがゼロになると、ガベージコレクションの候補になる可能性があります。これは、識別子をNoneに設定する場合と比較して、delを区別します。後者の場合、それは単にオブジェクトがワイルドアウトされていることを意味し(スコープから外れるまでカウントは減少します)、識別子は他のオブジェクト(メモリロケーション)を指します。


3
これの証拠を見たいのですが。Noneを割り当てると、参照カウントが減少します。
Jason Baker

3
これはナンセンスであり、ガベージコレクションの反対です(ガベージを置いたままにするという意味で)。
PavelŠimerda2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.