web-dev-qa-db-fra.com

Quand est-il utile en python?

Je ne vois pas vraiment pourquoi Python aurait besoin du mot clé del (et la plupart des langues ne semblent pas avoir un mot clé similaire). Par exemple, plutôt que de supprimer une variable, on pourrait simplement lui affecter None. Et lors de la suppression d'un dictionnaire, une méthode del peut être ajoutée.

Existe-t-il une raison de conserver del en python ou s'agit-il d'un vestige des jours de collecte des déchets avant Python?

305
Jason Baker

Tout d’abord, vous pouvez supprimer d’autres choses que des variables locales

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

Les deux devraient être clairement utiles. Deuxièmement, l'utilisation de del sur une variable locale rend l'intention plus claire. Comparer:

del foo

à

foo = None

Je sais dans le cas de del foo que le but est de supprimer la variable de la portée. Ce n'est pas clair que foo = None le fait. Si quelqu'un vient d'assigner foo = None, je pourrais penser qu'il s'agit d'un code mort. Mais je sais instantanément ce que quelqu'un qui code del foo essayait de faire.

428
Winston Ewert

Il y a cette partie de ce que del fait (à partir du Référence du langage Python ):

La suppression d'un nom supprime la liaison de ce nom de l'espace de nom local ou global

L'affectation de None à un nom ne supprime pas la liaison du nom de l'espace de noms.

(Je suppose qu'il pourrait y avoir un débat sur le point de savoir si la suppression d'une corrélation de noms est réellement utile, mais c'est une autre question.)

140
Greg Hewgill

Un endroit où j'ai trouvé del utile est le nettoyage des variables étrangères dans les boucles for:

for x in some_list:
  do(x)
del x

Maintenant, vous pouvez être sûr que x sera indéfini si vous l'utilisez en dehors de la boucle for. 

35
Jason Baker

Juste une autre pensée.

Lors du débogage d'applications http dans un cadre tel que Django, la pile d'appels contenant des variables inutiles et gâchées précédemment utilisées, en particulier lorsqu'il s'agit d'une très longue liste, pourrait être très pénible pour les développeurs. donc, à ce stade, le contrôle de l'espace de noms pourrait être utile.

14
tdihp

Il existe un exemple spécifique indiquant quand vous devriez utiliser del (il y en a peut-être d'autres, mais je suis au courant de cela) lorsque vous utilisez sys.exc_info() pour inspecter une exception. Cette fonction renvoie un tuple, le type d'exception levée, le message et une trace. 

Les deux premières valeurs sont généralement suffisantes pour diagnostiquer une erreur et agir sur celle-ci, mais la troisième contient toute la pile d'appels entre le moment où l'exception a été déclenchée et celle où l'exception est interceptée. En particulier, si vous faites quelque chose comme

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

le traceback, tb se termine dans les sections locales de la pile d'appels, créant une référence circulaire qui ne peut pas être nettoyée. Ainsi, il est important de faire:

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

casser la référence circulaire. Dans de nombreux cas où vous voudriez appeler sys.exc_info(), comme avec la magie de métaclasse, traceback is utile, vous devez donc vous assurer de le nettoyer avant de pouvoir éventuellement quitter le gestionnaire d'exceptions. Si vous n'avez pas besoin du suivi, vous devez le supprimer immédiatement ou simplement:

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

Pour éviter tout cela ensemble. 

La suppression d'une variable est différente de la définition sur Aucune

La suppression de noms de variables avec del est probablement quelque chose d’utilisé rarement, mais c’est quelque chose qui ne pourrait pas être réalisé trivialement sans mot clé. Si vous pouvez créer un nom de variable en écrivant a=1, c’est bien que vous puissiez théoriquement annuler cela en supprimant a.

Cela peut faciliter le débogage dans certains cas, car essayer d'accéder à une variable supprimée provoquera une erreur NameError.

Vous pouvez supprimer les attributs d'instance de classe

Python vous permet d'écrire quelque chose comme:

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

Si vous choisissez d'ajouter dynamiquement des attributs à une instance de classe, vous voulez certainement pouvoir l'annuler en écrivant

del a.a
13
TheEspinosa

Il est également préférable d’utiliser explicitement "del" plutôt que d’affecter une variable à None. Si vous essayez de supprimer une variable qui n'existe pas, vous obtiendrez une erreur d'exécution, mais si vous tentez de définir une variable qui n'existe pas, aucune voulu supprimé où il était. Donc, del vous aidera à attraper vos erreurs plus tôt

8
Matt

Pour ajouter quelques points aux réponses ci-dessus: del x

La définition de x indique r -> o (une référence r pointant vers un objet o) mais del x change r plutôt que o. C'est une opération sur la référence (pointeur) à l'objet plutôt que l'objet associé à x. Distinguer r et o est la clé ici.

  • Il le supprime de locals().
  • Le supprime de globals() si x y appartient.
  • Le supprime du cadre de pile (supprime physiquement la référence, mais l'objet lui-même réside dans le pool d'objets et non dans le cadre de pile).
  • Le supprime de la portée actuelle. Il est très utile de limiter l'étendue de la définition d'une variable locale, ce qui peut sinon causer des problèmes.
  • Il s’agit plus de la déclaration du nom que de la définition du contenu.
  • Cela affecte la propriété de x et non celle de x. Le seul changement physique en mémoire est le suivant. Par exemple, si x figure dans un dictionnaire ou une liste, il (en tant que référence) est supprimé de celui-ci (et pas nécessairement du pool d'objets). Dans cet exemple, le dictionnaire auquel il appartient est le cadre de pile (locals()), qui chevauche le globals().
7
Sohail Si

Forcer la fermeture d'un fichier après avoir utilisé numpy.load:

Un usage de niche peut-être, mais je l’ai trouvé utile lors de l’utilisation de numpy.load pour lire un fichier. De temps en temps, je mettais à jour le fichier et je devais copier un fichier du même nom dans le répertoire.

J'ai utilisé del pour libérer le fichier et me permettre de le copier dans le nouveau fichier.

Note Je veux éviter le gestionnaire de contexte with car je jouais avec les tracés sur la ligne de commande et je ne voulais pas trop appuyer sur tab!

Voir ceci question.

5
atomh33ls

del apparaît souvent dans les fichiers __init__.py. Toute variable globale définie dans un fichier __init__.py est automatiquement "exportée" (elle sera incluse dans un from module import *). Une façon d'éviter cela est de définir __all__, mais cela peut devenir compliqué et tout le monde ne l'utilise pas. 

Par exemple, si vous aviez un code dans __init__.py comme

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

Ensuite, votre module exportera le nom sys. Vous devriez plutôt écrire

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

del sys
5
asmeurer

À titre d'exemple de ce à quoi del peut être utilisé, je trouve cela utile dans des situations comme celle-ci:

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'

Ces deux fonctions peuvent être dans différents packages/modules et le programmeur n'a pas besoin de savoir quel argument de valeur par défaut c dans f possède réellement. Donc, en utilisant kwargs en combinaison avec del, vous pouvez dire "Je veux la valeur par défaut de c" en le réglant sur Aucun (ou dans ce cas, le laisse également).

Vous pourriez faire la même chose avec quelque chose comme:

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

    return f(**kwargs)

Cependant, je trouve que l'exemple précédent est plus DRY et élégant.

3
Jocke

Quand est-il utile en python?

Vous pouvez l'utiliser pour supprimer un seul élément d'un tableau au lieu de la syntaxe de tranche x[i:i+1]=[]. Cela peut être utile si, par exemple, vous êtes dans os.walk et souhaitez supprimer un élément du répertoire. Cependant, je ne considérerais pas un mot-clé utile pour cela, car on pourrait créer une méthode [].remove(index) (la méthode .remove est en fait une méthode de recherche et de suppression de la première instance de valeur).

3
ninjagecko

Je pense que l'une des raisons pour lesquelles del a sa propre syntaxe est que son remplacement par une fonction peut être difficile dans certains cas, étant donné qu'il opère sur la liaison ou la variable et non sur la valeur à laquelle elle fait référence. Ainsi, si une version de fonction de del devait être créée, un contexte devrait être passé. Del foo devrait devenir globals (). Remove ('foo') ou locals (). Remove ('foo') et moins lisible. Je dis toujours que se débarrasser de del serait bien compte tenu de son utilisation apparemment rare. Mais supprimer les caractéristiques/défauts de la langue peut être douloureux. Peut-être que python 4 va l'enlever :)

2
fuzzy-waffle

J'ai trouvé que del était utile pour la gestion de la mémoire pseudo-manuelle lors du traitement de données volumineuses avec Numpy. Par exemple:

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()

Cela peut faire la différence entre mettre un script à l'arrêt, car le système bascule comme un fou quand le Python GC ne peut pas suivre, et qu'il fonctionne parfaitement en dessous d'un seuil de mémoire lâche qui laisse beaucoup de marge. d'utiliser la machine pour parcourir et coder pendant qu'il fonctionne.

1
Nerve

Encore une autre utilisation de niche: Dans pyroot avec ROOT5 ou ROOT6, "del" peut être utile pour supprimer un objet python faisant référence à un objet C++ n’existant plus. Cela permet à la recherche dynamique de pyroot de rechercher un objet C++ portant le même nom et de le lier au nom python. Donc, vous pouvez avoir un scénario tel que:

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

Espérons que ce créneau sera fermé avec la gestion d’objets plus saine de ROOT7.

0
Amnon Harel

La commande "del" est très utile pour contrôler les données d'un tableau, par exemple:

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

Sortie:

['B', 'C', 'D']

0
Victor Marrerp