web-dev-qa-db-ja.com

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

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

delをpythonで保持する理由はありますか?それともPythonのガーベッジコレクション前の時代の名残ですか?

316
Jason Baker

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

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

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

del foo

foo = None

del fooの場合、その目的はスコープから変数を削除することです。 foo = Noneがそれを行っていることは明らかではありません。誰かがfoo = Noneを割り当てたばかりの場合、私はそれがデッドコードであると思うかもしれません。しかし、私は即座にdel fooをコード化している誰かがやろうとしていたことを知っています。

434
Winston Ewert

delが行うことのこの部分があります( Python言語リファレンス から):

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

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

(名前の束縛を取り除くことが実際に 役に立つ であるかどうかに関する議論があるかもしれませんが、それはまた別の質問です。)

143
Greg Hewgill

delが便利なことがわかった場所の1つは、forループ内の余分な変数を整理することです。

for x in some_list:
  do(x)
del x

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

35
Jason Baker

あなたが例外を検査するためにsys.exc_info()を使っているとき、あなたがdelを使うべきであるという具体的な例があります(他にもあるかもしれませんが、私はこれを手に入れています)。この関数は、Tuple、発生した例外の種類、メッセージ、およびトレースバックを返します。

最初の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]

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

ちょっと考えただけです。

Djangoのようなフレームワークでhttpアプリケーションをデバッグするとき、特にそれが非常に長いリストであるときに、以前に使われた無用でめちゃくちゃになった変数でいっぱいの呼び出しスタックは開発者にとって非常に痛いかもしれません。そのため、この時点では名前空間の制御が便利です。

14
tdihp

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

delで変数名を削除することはめったに使用されないものですが、それはキーワードなしでは簡単に達成できないものです。あなたがa=1を書くことによって変数名を作成することができるならば、それを削除することによって理論的にこれを元に戻すことができるのはいいことです。

削除された変数にアクセスしようとすると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
14
TheEspinosa

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

8
Matt

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

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

  • locals()から取り除きます。
  • xがそこに属している場合、それをglobals()から削除します。
  • それをスタックフレームから削除します(参照を物理的に削除しますが、オブジェクト自体はオブジェクトプールに存在し、スタックフレームには存在しません)。
  • 現在のスコープから削除します。ローカル変数の定義範囲を制限することは非常に便利です。そうしないと問題を引き起こす可能性があります。
  • 内容の定義ではなく、名前の宣言についてです。
  • xが指す場所ではなく、xが属する場所に影響します。メモリの物理的な変化はこれだけです。たとえばxが辞書またはリストにある場合、それは(参照として)そこから削除されます(必ずしもオブジェクトプールからは削除されません)。この例では、辞書が属する辞書はlocals()と重なるスタックフレーム(globals())です。
7
Sohail Si

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
6
asmeurer

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

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

私はdelを使用してファイルを解放し、新しいファイルにコピーできるようにしました。

注意コマンドラインでプロットを試していて、tabをあまり押さないでください。withコンテキストマネージャは避けたいと思います。

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

5
atomh33ls

例として 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つの関数は異なるパッケージ/モジュールに存在することができ、プログラマはcのデフォルト値引数fが実際に持っているものを知る必要はありません。したがって、kwargsをdelと組み合わせて使用​​すると、Noneに設定することで「cのデフォルト値が必要です」と言うことができます(この場合も、そのままにします)。

次のようにしても同じことができます。

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

    return f(**kwargs)

しかし、私は前の例をもっとDRYそしてエレガントに見つけました。

3
Jocke

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

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

3
ninjagecko

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

2
fuzzy-waffle

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

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が維持できない場合にシステムが狂ったようにスワップするため、スクリプトを停止することと、十分なヘッドルームを残してゆるいメモリしきい値を下回って完全にスムーズに実行することとの違いですマシンを使用して、動作中に参照およびコーディングします。

1
Nerve

もう1つのニッチな使い方: pyroot ROOT5またはROOT6では、 "del"はもはや存在しない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のsanerオブジェクト管理で閉じられるでしょう。

0
Amnon Harel

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

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

出力:

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

0
Victor Marrerp