font - ¿Cuándo es útil en python?
subplot title python (17)
Realmente no puedo pensar en ninguna razón por la que Python necesite la palabra clave del
(y la mayoría de los idiomas parecen no tener una palabra clave similar). Por ejemplo, en lugar de eliminar una variable, uno podría asignarle None
. Y al eliminar de un diccionario, se podría agregar un método del
.
¿Hay alguna razón para mantener del
en Python, o es un vestigio de los días de recolección de basura de Python?
¿Cuándo es útil en python?
Puede usarlo para eliminar un solo elemento de una matriz en lugar de la sintaxis de segmento x[i:i+1]=[]
. Esto puede ser útil si, por ejemplo, está en os.walk
y desea eliminar un elemento del directorio. Sin embargo, no consideraría una palabra clave útil para esto, ya que uno podría simplemente hacer un método [].remove(index)
(el método .remove
es en realidad búsqueda y eliminación de la primera instancia del valor).
Eliminar una variable es diferente a configurarlo en Ninguno
Eliminar nombres de variables con del
es probablemente algo que se usa raramente, pero es algo que no podría lograrse de manera trivial sin una palabra clave. Si puedes crear un nombre de variable escribiendo a=1
, es bueno que teóricamente puedas deshacer esto eliminando a.
Puede hacer que la depuración sea más fácil en algunos casos, ya que intentar acceder a una variable eliminada generará un error de nombre.
Puede eliminar atributos de instancia de clase
Python te permite escribir algo como:
class A(object):
def set_a(self, a):
self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
print("Hallo")
Si elige agregar atributos dinámicamente a una instancia de clase, ciertamente desea poder deshacerlo escribiendo
del a.a
Cada objeto en Python tiene un identificador, Tipo, recuento de referencia asociado, cuando usamos el recuento de referencia se reduce, cuando el recuento de referencia se convierte en cero, es un candidato potencial para la recolección de basura. Esto diferencia al del cuando se compara con establecer un identificador en Ninguno. En el último caso, simplemente significa que el objeto se queda fuera de control (hasta que quedamos fuera del alcance, en cuyo caso el recuento se reduce) y simplemente ahora el punto de identificación a algún otro objeto (ubicación de la memoria).
Creo que una de las razones por las que del tiene su propia sintaxis es que reemplazarla con una función puede ser difícil en ciertos casos dado que opera en el enlace o variable y no en el valor al que hace referencia. Por lo tanto, si se creara una versión de la función del del, se tendría que pasar un contexto. Del foo tendría que convertirse en globals (). Remove (''foo'') o locals (). Remove (''foo'') que se complica y menos legible. Todavía digo que deshacerse de del sería bueno dado su uso aparentemente raro. Pero eliminar características / defectos del lenguaje puede ser doloroso. Tal vez Python 4 lo eliminará :)
En primer lugar, puedes deleitarte de otras cosas además de variables locales
del list_item[4]
del dictionary["alpha"]
Ambos deberían ser claramente útiles. En segundo lugar, el uso de del
en una variable local aclara la intención. Comparar:
del foo
a
foo = None
Sé que en el caso de del foo
la intención es eliminar la variable del alcance. No está claro que foo = None
esté haciendo eso. Si alguien acaba de asignar foo = None
, podría pensar que era un código muerto. Pero instantáneamente sé lo que alguien que codifica del foo
estaba tratando de hacer.
Hay un ejemplo específico de cuándo debe usar del
(puede haber otros, pero conozco este caso) cuando está usando sys.exc_info()
para inspeccionar una excepción. Esta función devuelve una tupla, el tipo de excepción que se generó, el mensaje y un rastreo.
Los primeros dos valores suelen ser suficientes para diagnosticar un error y actuar sobre él, pero el tercero contiene la pila de llamadas completa entre el lugar donde se generó la excepción y el lugar donde se captura la excepción. En particular, si haces algo como
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
if something(exc_value):
raise
En el rastreo, tb
termina en los locales de la pila de llamadas, creando una referencia circular que no puede ser recogida de basura. Por lo tanto, es importante hacer:
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
del tb
if something(exc_value):
raise
Para romper la referencia circular. En muchos casos en los que desearía llamar a sys.exc_info()
, como con metaclass magic, el rastreo es útil, por lo que debe asegurarse de limpiarlo antes de poder dejar el controlador de excepciones. Si no necesita el rastreo, debe eliminarlo inmediatamente o simplemente haga lo siguiente:
exc_type, exc_value = sys.exc_info()[:2]
Para evitarlo todo junto.
Hay una parte de lo que hace (de la referencia del lenguaje Python ):
La eliminación de un nombre elimina el enlace de ese nombre del espacio de nombres local o global
La asignación de None
a un nombre no elimina el enlace del nombre del espacio de nombres.
(Supongo que podría haber algún debate sobre si eliminar un enlace de nombre es realmente útil , pero esa es otra pregunta).
Otro uso más de nicho: en pyroot con ROOT5 o ROOT6, "del" puede ser útil para eliminar un objeto python que se refiera a un objeto C ++ que ya no existe. Esto permite que la búsqueda dinámica de pyroot encuentre un objeto C ++ con nombre idéntico y lo vincule al nombre de python. Así que puedes tener un escenario como:
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
Con suerte, este nicho se cerrará con la gestión más inteligente de objetos de ROOT7.
Para agregar algunos puntos a las respuestas anteriores: del x
La definición de x indica r -> o (una referencia r que apunta a un objeto o) pero del x
cambia r en lugar de o. Es una operación en la referencia (puntero) a objeto en lugar del objeto asociado con x. Distinguir entre r y o es clave aquí.
- Lo quita de los
locals()
- lo elimina de
globals()
si x pertenece allí. - lo elimina del marco de la pila (elimina la referencia físicamente de él, pero el objeto reside en el conjunto de objetos y no en el marco de la pila).
- lo elimina del ámbito actual. Es muy útil limitar el alcance de la definición de una variable local, que de lo contrario puede causar problemas.
- se trata más de la declaración del nombre en lugar de la definición del contenido.
- Afecta a donde pertenece
x
, no a dondex
apunta. El único cambio físico en la memoria es este. Por ejemplo, six
está en un diccionario o lista, (como referencia) se elimina de allí (y no necesariamente de la agrupación de objetos). En este ejemplo, el diccionario al que pertenece es el marco de pila (locals()
), que se superpone con globals ().
Sólo otro pensamiento.
Al depurar aplicaciones http en un marco como Django, la pila de llamadas llena de variables inútiles y desordenadas usadas previamente, especialmente cuando es una lista muy larga, podría ser muy dolorosa para los desarrolladores. por lo tanto, en este punto, el control del espacio de nombres podría ser útil.
Un lugar que he encontrado del
útil es la limpieza de variables extrañas en los bucles:
for x in some_list:
do(x)
del x
Ahora puede estar seguro de que x no estará definido si lo usa fuera del bucle for.
Una vez tuve que usar:
del serial
serial = None
porque usando solo:
serial = None
no liberó el puerto serie lo suficientemente rápido como para abrirlo de nuevo inmediatamente. De esa lección aprendí que lo que realmente quería decir es: "¡VAYA A CONOCER AHORA! Y espere hasta que termine", y eso es realmente útil en muchas situaciones. Por supuesto, puede tener un system.gc.del_this_and_wait_balbalbalba(obj)
.
Usar "del" explícitamente también es una mejor práctica que asignar una variable a Ninguna. Si intentas eliminar una variable que no existe, obtendrás un error de tiempo de ejecución, pero si intentas establecer una variable que no existe en Ninguno, Python establecerá una nueva variable silenciosamente en Ninguna, dejando la variable que quería borrado donde estaba. Así que del te ayudará a detectar tus errores antes
del es el equivalente de "unset" en muchos idiomas y como punto de referencia cruzada que se mueve de otro idioma a python. Las personas tienden a buscar comandos que hacen lo mismo que solían hacer en su primer idioma ... también configurando una var para "" o ninguna realmente no elimina la var del ámbito ... simplemente vacía su valor, el nombre de la var en sí todavía se almacenaría en la memoria ... ¿por qué?! en una secuencia de comandos de memoria intensiva ... mantener la basura detrás de ella simplemente no, no, y de todos modos ... todos los idiomas tienen alguna forma de función "desarmar / borrar" var ... ¿por qué no python?
del
se ve a menudo en los archivos __init__.py
. Cualquier variable global que se define en un archivo __init__.py
se "exporta" automáticamente (se incluirá en una from module import *
). Una forma de evitar esto es definir __all__
, pero esto puede __all__
y no todos lo usan.
Por ejemplo, si tiene código en __init__.py
como
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
Entonces su módulo exportaría el nombre del sistema. En lugar de eso deberías escribir
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
del sys
Como ejemplo de para qué se puede usar del, me resulta útil en situaciones como esta:
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''
Estas dos funciones pueden estar en diferentes paquetes / módulos y el programador no necesita saber qué valor predeterminado tiene el argumento c
en f
. Entonces, al utilizar kwargs en combinación con del, puede decir "Quiero el valor predeterminado en c" configurándolo en Ninguno (o, en este caso, también dejarlo).
Podrías hacer lo mismo con algo como:
def g(a, b, c=None):
kwargs = {''a'': a,
''b'': b}
if c is not None:
kwargs[''c''] = c
return f(**kwargs)
Sin embargo encuentro el ejemplo anterior más seco y elegante.
Forzar el cierre de un archivo después de usar numpy.load:
Un uso de nicho quizás pero lo encontré útil cuando uso numpy.load
para leer un archivo. De vez en cuando actualizaría el archivo y necesitaría copiar un archivo con el mismo nombre en el directorio.
Utilicé del
para liberar el archivo y permitirme copiar en el nuevo archivo.
Tenga en cuenta que quiero evitar el administrador de contexto ya que estaba jugando con los gráficos en la línea de comandos y no quería presionar la pestaña mucho.
Vea this pregunta.