什么时候del在python中有用?
我真的不知道为什么python需要del
关键字(大多数语言似乎没有类似的关键字)。 例如,不是删除一个variables,而是可以将None
赋值给它。 从字典中删除时,可以添加一个del
方法。
有没有任何理由保持python的del
,或者它是Python的预垃圾回收日的遗迹?
首先,除了局部variables,你还可以删除其他东西
del list_item[4] del dictionary["alpha"]
这两者都应该是明显有用的。 其次,在局部variables上使用del使得intent更加清晰。 比较:
del foo
至
foo = None
我知道在del foo
的情况下,意图是从范围中删除variables。 目前尚不清楚foo = None
是否正在这样做。 如果有人刚分配foo = None
我可能会认为这是死代码。 但是,我立即知道代码del foo
有人想要做什么。
这是del
的一部分(来自Python语言参考 ):
删除名称将删除该名称与本地或全局名称空间的绑定
将None
分配给名称不会从命名空间中删除该名称的绑定。
(我想可能会有一些关于删除名称绑定是否有用的争论,但这是另一个问题。)
我发现del
有用的一个地方是清除for循环中的无关variables:
for x in some_list: do(x) del x
现在你可以确定,如果你在for循环之外使用x,x将是未定义的。
只是另一个想法。
当像Django一样在框架中debugginghttp应用程序时,调用堆栈中充满了以前使用的无用和混乱的variables,特别是当它是一个很长的列表时,对于开发人员来说可能是非常痛苦的。 所以,在这一点上,命名空间控制可能是有用的。
当你使用sys.exc_info()
来检查一个exception的时候,有一个特别的例子,你应该使用del
(也许还有其他的,但是我知道这个关于这个)。 这个函数返回一个元组,引发的exceptiontypes,消息和回溯。
前两个值通常足以诊断错误并对其执行操作,但是第三个值包含引发exception的位置和exception被捕获的位置之间的整个调用堆栈。 特别是,如果你做类似的事情
try: do_evil() except: exc_type, exc_value, tb = sys.exc_info() if something(exc_value): raise
回溯, tb
结束于调用堆栈的本地,创build一个不能被垃圾回收的循环引用。 因此,做这件事很重要:
try: do_evil() except: exc_type, exc_value, tb = sys.exc_info() del tb if something(exc_value): raise
打破循环引用。 在许多情况下,如果想要调用sys.exc_info()
,就像元类魔术一样,回溯是有用的,所以在可能离开exception处理程序之前,必须确保清除它。 如果你不需要回溯,你应该立即删除,或者只是:
exc_type, exc_value = sys.exc_info()[:2]
一起避免它。
使用numpy.load后强制closures文件:
也许一个利基的用法,但我发现它使用numpy.load
读取文件时很有用。 每过一段时间,我都会更新文件,并需要将同名的文件复制到目录中。
我用del
释放文件,并允许我复制新文件。
注意我想避免with
上下文pipe理器,因为我在命令行中使用图标,并且不想按Tab键很多!
看到这个问题。
明确使用“del”也比将一个variables赋值给None更好。 如果你试图删除一个不存在的variables,你会得到一个运行时错误,但是如果你尝试设置一个不存在的variables,Python会默默地将一个新的variables设置为None,想要删除它在哪里。 所以德尔会帮助你早点发现你的错误
为以上答案添加几点: del x
x的定义表示r – > o(指向对象o的引用r),但del x
改变r而不是o。 它是对对象的引用(指针)的操作,而不是与x关联的对象。 区分r和o是关键。
- 它从
locals()
- 如果它属于那里,则将其从
globals()
移除。 - 将其从堆栈帧中删除(从物理上删除引用,但对象本身驻留在对象池中而不是堆栈帧中)。
- 将其从当前范围中删除。 限制局部variables的定义范围是非常有用的,否则会导致问题。
- 更多的是关于名称的声明而不是内容的定义。
- 它影响
x
所属的位置,而不是x
指向的位置。 记忆中唯一的物理变化就是这个。 例如,如果x
位于字典或列表中,则它(作为引用)将从此处(而不一定是来自对象池)中删除。 在这个例子中,它所属的字典是堆栈框架(locals()
),它与globals()重叠。
删除variables与将其设置为None不同
用del
删除variables名可能是很less用到的东西,但是如果没有关键字就不能实现。 如果你可以通过写a=1
来创build一个variables名,那么理论上你可以通过删除一个来取消它。
在某些情况下,它可以使debugging更容易,因为试图访问已删除的variables会引发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")
如果您selectdynamic地将属性添加到类实例,您当然希望能够通过写入来撤消它
del aa
我认为del有它自己的语法的原因之一是,用函数replace它可能在某些情况下是困难的,因为它在绑定或variables上运行,而不是它引用的值。 因此,如果要创build一个函数版本的del,则需要传入一个上下文。del foo需要成为globals()。remove('foo')或locals()。remove('foo')并且可读性较差。 不过,我认为摆脱德尔将是好的,因为它看似罕见的用途。 但是消除语言特征/缺陷可能是痛苦的。 也许蟒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'
这两个函数可以在不同的包/模块中,程序员不需要知道f
实际具有的默认值参数c
。 所以通过与del组合使用kwargs,可以通过将它设置为None(或者在这种情况下,也可以放弃它)来说“我想要c上的默认值”。
你可以用类似的方法做同样的事情:
def g(a, b, c=None): kwargs = {'a': a, 'b': b} if c is not None: kwargs['c'] = c return f(**kwargs)
不过,我发现前面的例子更干燥优雅。
什么时候del在python中有用?
您可以使用它来移除数组中的单个元素,而不是切片语法x[i:i+1]=[]
。 这可能是有用的,例如,如果你在os.walk
并希望删除目录中的元素。 我不会考虑一个有用的关键字,因为我们可以创build一个[].remove(index)
方法( .remove
方法实际上是search-and-remove-first-instance-value)。
del
在__init__.py
文件中经常出现。 任何在__init__.py
文件中定义的全局variables都会被自动“导出”(它将被包含在from module import *
)。 避免这种情况的一种方法是定义__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
一旦我不得不使用:
del serial serial = None
因为只使用:
serial = None
没有足够快地释放串口来立即打开它。 从这一课我学到了del
真正含义:“GC now!”并等到它完成了,这在很多情况下都是非常有用的。 当然,你可能有一个system.gc.del_this_and_wait_balbalbalba(obj)
。
del在许多语言中相当于“unset”,并且是从另一种语言转换为python的交叉参考点。人们倾向于寻找与他们的第一语言完全相同的命令…也设置var“”或者none都不能真正的将var从范围中删除,只是清空它的值,var本身的名字仍然会被存储在内存中…为什么?!? 在一个内存密集的脚本..保持垃圾背后它只是一个不,无论如何…每种语言都有一些“unset /删除”var函数的forms..为什么不是python?
python中的每个对象都有一个标识符,types,引用计数,当我们使用del时,引用计数减less,当引用计数变为零时,它是一个潜在的垃圾收集候选者。 与将标识符设置为None相比,这区分了del。 在后面的例子中,它只是意味着对象被忽略(直到我们超出了范围,在这种情况下计数减less),现在标识符指向其他对象(内存位置)。