问题:什么时候del在python中有用?

我真的想不出python为什么需要del关键字的任何原因(大多数语言似乎没有类似的关键字)。例如,可以删除变量而不是删除变量None。从字典中删除时,del可以添加一个方法。

是否有任何理由保留del在python中,或者它是Python的垃圾收集日的痕迹?

I can’t really think of any reason why python needs the del keyword (and most languages seem to not have a similar keyword). For instance, rather than deleting a variable, one could just assign None to it. And when deleting from a dictionary, a del method could be added.

Is there any reason to keep del in python, or is it a vestige of Python’s pre-garbage collection days?


回答 0

首先,除了局部变量,您还可以进行其他操作

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

两者都应该明显有用。其次,del在局部变量上使用可使意图更清晰。相比:

del foo

foo = None

我知道在这种情况下del foo,目的是从范围中删除变量。目前尚不清楚这样foo = None做。如果有人刚分配,foo = None我可能认为这是无效代码。但是我立即知道某个编码人员del foo正在尝试做什么。

Firstly, you can del other things besides local variables

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

Both of which should be clearly useful. Secondly, using del on a local variable makes the intent clearer. Compare:

del foo

to

foo = None

I know in the case of del foo that the intent is to remove the variable from scope. It’s not clear that foo = None is doing that. If somebody just assigned foo = None I might think it was dead code. But I instantly know what somebody who codes del foo was trying to do.


回答 1

这是做什么的一部分del(来自Python语言参考):

删除名称会从本地或全局命名空间中删除该名称的绑定

分配None名称不会从命名空间中删除名称的绑定。

(我想可能存在一些关于删除名称绑定是否真正有用的参数,但这是另一个问题。)

There’s this part of what del does (from the Python Language Reference):

Deletion of a name removes the binding of that name from the local or global namespace

Assigning None to a name does not remove the binding of the name from the namespace.

(I suppose there could be some debate about whether removing a name binding is actually useful, but that’s another question.)


回答 2

我发现一个del有用的地方是清理for循环中的无关变量:

for x in some_list:
  do(x)
del x

现在,您可以确定,如果在for循环之外使用x,它将是未定义的。

One place I’ve found del useful is cleaning up extraneous variables in for loops:

for x in some_list:
  do(x)
del x

Now you can be sure that x will be undefined if you use it outside the for loop.


回答 3

删除变量与将其设置为“无”不同

用删除变量名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

Deleting a variable is different than setting it to None

Deleting variable names with del is probably something used rarely, but it is something that could not trivially be achieved without a keyword. If you can create a variable name by writing a=1, it is nice that you can theoretically undo this by deleting a.

It can make debugging easier in some cases as trying to access a deleted variable will raise an NameError.

You can delete class instance attributes

Python lets you write something like:

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

If you choose to dynamically add attributes to a class instance, you certainly want to be able to undo it by writing

del a.a

回答 4

有一个特定的示例说明您在检查异常时应使用的时间del(可能还有其他,但我知道这是sys.exc_info()一时的事)。此函数返回一个元组,引发的异常类型,消息和回溯。

前两个值通常足以诊断错误并采取措施,但第三个值包含引发异常与捕获异常之间的整个调用堆栈。特别是如果您做类似的事情

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]

为了避免所有这一切。

There is a specific example of when you should use del (there may be others, but I know about this one off hand) when you are using sys.exc_info() to inspect an exception. This function returns a tuple, the type of exception that was raised, the message, and a traceback.

The first two values are usually sufficient to diagnose an error and act on it, but the third contains the entire call stack between where the exception was raised and where the the exception is caught. In particular, if you do something like

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

the traceback, tb ends up in the locals of the call stack, creating a circular reference that cannot be garbage collected. Thus, it is important to do:

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

to break the circular reference. In many cases where you would want to call sys.exc_info(), like with metaclass magic, the traceback is useful, so you have to make sure that you clean it up before you can possibly leave the exception handler. If you don’t need the traceback, you should delete it immediately, or just do:

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

To avoid it all together.


回答 5

只是另一种想法。

在像Django这样的框架中调试http应用程序时,调用堆栈充满了以前使用的无用且混乱的变量,尤其是当列表很长时,对于开发人员而言可能非常痛苦。因此,此时,命名空间控制可能会很有用。

Just another thinking.

When debugging http applications in framework like Django, the call stack full of useless and messed up variables previously used, especially when it’s a very long list, could be very painful for developers. so, at this point, namespace controlling could be useful.


回答 6

与将变量分配给None相比,显式使用“ del”也是一种更好的做法。如果尝试删除不存在的变量,则会遇到运行时错误,但如果尝试将不存在的变量设置为None,Python会静默将新变量设置为None,而将变量保留为想删除它在哪里。因此,del将帮助您尽早发现错误

Using “del” explicitly is also better practice than assigning a variable to None. If you attempt to del a variable that doesn’t exist, you’ll get a runtime error but if you attempt to set a variable that doesn’t exist to None, Python will silently set a new variable to None, leaving the variable you wanted deleted where it was. So del will help you catch your mistakes earlier


回答 7

要为以上答案添加几点: del x

x指示的定义r -> or指向对象的引用o),但del x更改r而不是o。这是对对象(而不是与关联的对象)的引用(指针)的操作x。区分ro是此处的关键。

  • 它将从中删除locals()
  • globals()如果x属于它,将其删除。
  • 将其从堆栈框架中删除(从物理上删除引用,但对象本身位于对象池中,而不位于堆栈框架中)。
  • 从当前作用域中删除它。限制局部变量定义的范围非常有用,否则会导致问题。
  • 它更多地是关于名称的声明而不是内容的定义。
  • 它影响x属于的地方,而不影响x指向的地方。内存中唯一的物理更改是这样。例如,如果x在字典或列表中,则将其(作为参考)从那里(不一定从对象池中)删除。在此示例中,它所属的字典是locals()与重叠的堆栈框架()globals()

To add a few points to above answers: del x

Definition of x indicates r -> o (a reference r pointing to an object o) but del x changes r rather than o. It is an operation on the reference (pointer) to object rather than the object associated with x. Distinguishing between r and o is key here.

  • It removes it from locals().
  • Removes it from globals() if x belongs there.
  • Removes it from the stack frame (removes the reference physically from it, but the object itself resides in object pool and not in the stack frame).
  • Removes it from the current scope. It is very useful to limit the span of definition of a local variable, which otherwise can cause problems.
  • It is more about declaration of the name rather than definition of content.
  • It affects where x belongs to, not where x points to. The only physical change in memory is this. For example if x is in a dictionary or list, it (as a reference) is removed from there(and not necessarily from the object pool). In this example, the dictionary it belongs is the stack frame (locals()), which overlaps with globals().

回答 8

使用numpy.load后强制关闭文件:

利基用法也许,但我发现它在numpy.load用于读取文件时很有用。我会不时地更新文件,并且需要将具有相同名称的文件复制到目录中。

我曾经del发布过文件,并允许我复制到新文件中。

请注意,我想避免使用with上下文管理器,因为我在命令行上玩弄图并且不想太多地按下Tab键!

看到这个问题。

Force closing a file after using numpy.load:

A niche usage perhaps but I found it useful when using numpy.load to read a file. Every once in a while I would update the file and need to copy a file with the same name to the directory.

I used del to release the file and allow me to copy in the new file.

Note I want to avoid the with context manager as I was playing around with plots on the command line and didn’t want to be pressing tab a lot!

See this question.


回答 9

del通常在__init__.py文件中看到。__init__.py文件中定义的所有全局变量都将自动“导出”(将包含在中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 is often seen in __init__.py files. Any global variable that is defined in an __init__.py file is automatically “exported” (it will be included in a from module import *). One way to avoid this is to define __all__, but this can get messy and not everyone uses it.

For example, if you had code in __init__.py like

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

Then your module would export the sys name. You should instead write

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

del sys

回答 10

作为一个例子什么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'

这两个功能都可以在不同的封装/模块和程序员不需要知道默认值参数cf实际拥有。因此,通过将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)

但是,我发现前面的示例更加干燥和优雅。

As an example of what del can be used for, I find it useful i situations like this:

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'

These two functions can be in different packages/modules and the programmer doesn’t need to know what default value argument c in f actually have. So by using kwargs in combination with del you can say “I want the default value on c” by setting it to None (or in this case also leave it).

You could do the same thing with something like:

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

    return f(**kwargs)

However I find the previous example more DRY and elegant.


回答 11

什么时候del在python中有用?

您可以使用它删除数组的单个元素,而不是切片语法x[i:i+1]=[]。例如,如果您在其中os.walk并希望删除目录中的元素,这可能会很有用。不过,我认为关键字对此无济于事,因为一个人只能制作一个[].remove(index)方法(该.remove方法实际上是搜索并删除第一个实例值)。

When is del useful in python?

You can use it to remove a single element of an array instead of the slice syntax x[i:i+1]=[]. This may be useful if for example you are in os.walk and wish to delete an element in the directory. I would not consider a keyword useful for this though, since one could just make a [].remove(index) method (the .remove method is actually search-and-remove-first-instance-of-value).


回答 12

del当使用Numpy处理大数据时,我发现对于伪手动内存管理很有用。例如:

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无法跟上系统疯狂地交换脚本而使脚本陷入停顿状态,并且在松散的内存阈值下它可以完美平滑地运行,从而留出了很大的可用空间来浏览机器和代码,而它的工作。

I’ve found del to be useful for pseudo-manual memory management when handling large data with Numpy. For example:

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

This can be the difference between bringing a script to a grinding halt as the system swaps like mad when the Python GC can’t keep up, and it running perfectly smooth below a loose memory threshold that leaves plenty of headroom to use the machine to browse and code while it’s working.


回答 13

我认为del具有自己的语法的原因之一是,在某些情况下,鉴于del操作绑定或变量而不是它引用的值,用函数替换它可能很难。因此,如果要创建del的函数版本,则需要传入上下文。del foo将需要变为globals()。remove(’foo’)或locals()。remove(’foo’),从而变得混乱而且可读性较差。我仍然说,鉴于del似乎很少使用,摆脱它会很好。但是删除语言功能/缺陷可能很痛苦。也许python 4会删除它:)

I think one of the reasons that del has its own syntax is that replacing it with a function might be hard in certain cases given it operates on the binding or variable and not the value it references. Thus if a function version of del were to be created a context would need to be passed in. del foo would need to become globals().remove(‘foo’) or locals().remove(‘foo’) which gets messy and less readable. Still I say getting rid of del would be good given its seemingly rare use. But removing language features/flaws can be painful. Maybe python 4 will remove it :)


回答 14

我想详细说明可接受的答案,以突出显示将变量设置为None与使用删除变量之间的细微差别del

给定变量foo = 'bar',并提供以下函数定义:

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

最初声明后,test_var(foo)Yield将variable tested true达到预期。

现在尝试:

foo = None
test_var(foo)

产生variable tested false

将此行为与:

del foo
test_var(foo)

现在提高了NameError: name 'foo' is not defined

I would like to elaborate on the accepted answer to highlight the nuance between setting a variable to None versus removing it with del:

Given the variable foo = 'bar', and the following function definition:

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

Once initially declared, test_var(foo) yields variable tested true as expected.

Now try:

foo = None
test_var(foo)

which yields variable tested false.

Contrast this behavior with:

del foo
test_var(foo)

which now raises NameError: name 'foo' is not defined.


回答 15

又一小生用法:在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的精明对象管理而关闭。

Yet another niche usage: In pyroot with ROOT5 or ROOT6, “del” may be useful to remove a python object that referred to a no-longer existing C++ object. This allows the dynamic lookup of pyroot to find an identically-named C++ object and bind it to the python name. So you can have a scenario such as:

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

Hopefully, this niche will be closed with ROOT7’s saner object management.


回答 16

“ del”命令对于控制数组中的数据非常有用,例如:

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

输出:

[‘B’,’C’,’D’]

The “del” command is very useful for controlling data in an array, for example:

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

Output:

[‘B’, ‘C’, ‘D’]


回答 17

一旦我不得不使用:

del serial
serial = None

因为仅使用:

serial = None

释放串口的速度不够快,无法立即再次打开它。从那堂课中,我学到了del真正的意思:“现在就GC!等到完成为止”,这在很多情况下非常有用。当然,您可能会有一个system.gc.del_this_and_wait_balbalbalba(obj)

Once I had to use:

del serial
serial = None

because using only:

serial = None

didn’t release the serial port fast enough to immediately open it again. From that lesson I learned that del really meant: “GC this NOW! and wait until it’s done” and that is really useful in a lot of situations. Of course, you may have a system.gc.del_this_and_wait_balbalbalba(obj).


回答 18

del在许多语言中都等同于“未设置”,并且作为从另一种语言到python的交叉参考点。人们倾向于寻找命令,它们执行的操作与以前使用第一语言时所做的相同……将var更改为“”或没有任何操作并不会真正从范围中删除该var。它只是清空其值,该var本身的名称仍将存储在内存中…为什么?!在占用大量内存的脚本中..保持垃圾桶的“否”和“反之……”每种语言都具有某种形式的“未设置/删除” var函数..为什么不使用python?

del is the equivalent of “unset” in many languages and as a cross reference point moving from another language to python.. people tend to look for commands that do the same thing that they used to do in their first language… also setting a var to “” or none doesn’t really remove the var from scope..it just empties its value the name of the var itself would still be stored in memory…why?!? in a memory intensive script..keeping trash behind its just a no no and anyways…every language out there has some form of an “unset/delete” var function..why not python?


回答 19

python中的每个对象都有一个标识符,类型,与之关联的引用计数,当我们使用del时,引用计数会减少,当引用计数变为零时,它很可能成为垃圾回收的候选对象。与将标识符设置为“无”相比,这可以区分del。在后面的情况下,它只是意味着该对象被遗忘了(直到我们超出范围,在这种情况下,计数减少了),现在标识符仅指向其他某个对象(内存位置)。

Every object in python has an identifier, Type, reference count associated with it, when we use del the reference count is reduced, when the reference count becomes zero it is a potential candidate for getting garbage collected. This differentiates the del when compared to setting an identifier to None. In later case it simply means the object is just left out wild( until we are out of scope in which case the count is reduced) and simply now the identifier point to some other object(memory location).


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。