使用del不好吗? [英] Is the use of del bad?

查看:102
本文介绍了使用del不好吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常在代码中使用del删除对象:

I commonly use del in my code to delete objects:

>>> array = [4, 6, 7, 'hello', 8]
>>> del(array[array.index('hello')])
>>> array
[4, 6, 7, 8]
>>> 

但是我听说过很多人表示del的使用是非Python的.是否使用del不良做法?

But I have heard many people say that the use of del is unpythonic. Is using del bad practice?

>>> array = [4, 6, 7, 'hello', 8]
>>> array[array.index('hello'):array.index('hello')+1] = ''
>>> array
[4, 6, 7, 8]
>>> 

如果没有,为什么有很多方法可以在python中完成相同的事情?一个比其他更好吗?

If not, why are there many ways to accomplish the same thing in python? Is one better than the others?

选项1:使用del

Option 1: using del

>>> arr = [5, 7, 2, 3]
>>> del(arr[1])
>>> arr
[5, 2, 3]
>>> 

选项2:使用list.remove()

Option 2: using list.remove()

>>> arr = [5, 7, 2, 3]
>>> arr.remove(7)
>>> arr
[5, 2, 3]
>>> 

选项3:使用list.pop()

Option 3: using list.pop()

>>> arr = [5, 7, 2, 3]
>>> arr.pop(1)
7
>>> arr
[5, 2, 3]
>>> 

选项4:使用切片

>>> arr = [5, 7, 2, 3]
>>> arr[1:2] = ''
>>> arr
[5, 2, 3]
>>> 

很抱歉,这个问题似乎是基于观点的,但是我正在寻找一个合理的答案,如果找不到合适的答案,我会在两天后增加悬赏.

I am sorry if this question appears to be opinion-based, but I am looking for a reasonable answer to my question, and I will add a bounty after 2 days if I don't get a suitable answer.

由于使用del删除对象的某些部分的方法很多,因此del剩下的唯一因素是其完全删除对象的能力:

Since there are many alternates to using del to delete certain parts of objects, the one unique factor left of del is its ability to remove objects completely:

>>> a = 'hello'
>>> b = a
>>> del(a)
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
'hello'
>>> 

但是,使用它取消定义"对象有什么意义呢?

However, what is the point of using it to 'undefine' objects?

此外,为什么以下代码会同时更改两个变量:

Also, why does the following code change both variables:

>>> a = []
>>> b = a
>>> a.append(9)
>>> a
[9]
>>> b
[9]
>>> 

但是del语句不能达到相同的效果?

But the del statement does not achieve the same effect?

>>> a = []
>>> b = a
>>> del(a)
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
[]
>>> 

推荐答案

其他答案是从技术角度(即,修改列表的最佳方法是什么)来看待它,但我会说(很多)人们建议的更重要的原因,例如切片是因为它不会修改原始列表.

The other answers are looking at it from a technical point of view (i.e. what's the best way to modify a list), but I would say the (much) more important reason people are suggesting e.g. slicing is that it doesn't modify the original list.

这又是因为该列表通常来自某个地方.如果对其进行修改,无疑会导致非常糟糕且难以检测的副作用,这可能会导致程序中其他位置的错误.或者,即使您没有立即引起错误,也将使程序的整体更难以理解,推理和调试.

The reason for this in turn is that usually, the list came from somewhere. If you modify it, you can unknowningly cause very bad and hard-to-detect side effects, which can cause bugs elsewhere in the program. Or even if you don't cause a bug immediately, you'll make your program overall harder to understand and reason about, and debug.

例如,列表推导/生成器表达式很不错,因为它们从不改变传递的源"列表:

For example, list comprehensions/generator expressions are nice in that they never mutate the "source" list they are passed:

[x for x in lst if x != "foo"]  # creates a new list
(x for x in lst if x != "foo")  # creates a lazy filtered stream

这当然通常会比较昂贵(在内存方面),因为它会创建一个新列表,但是使用此方法的程序在数学上更纯正,也更容易推理.而对于惰性列表(生成器和生成器表达式),即使是内存开销也将消失,并且仅根据需要执行计算.有关出色的介绍,请参见 http://www.dabeaz.com/generators/.而且,在设计程序时,您不要过多地考虑优化(请参见

This is of course often more expensive (memory wise) because it creates a new list but a program that uses this approach is mathematically purer and easier to reason about. And with lazy lists (generators and generator expressions), even the memory overhead will disappear, and computations are only executed on demand; see http://www.dabeaz.com/generators/ for an awesome introduction. And you should not think too much about optimization when designing your program (see https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil). Also, removing an item from a list is quite expensive, unless it's a linked list (which Python's list isn't; for linked list, see collections.deque).

实际上,具有副作用的免费功能和不可变

In fact, side-effect free functions and immutable data structures are the basis of Functional Programming, a very powerful programming paradigm.

但是,在某些情况下,可以就地修改数据结构(即使在FP中,

However, under certain circumstances, it's OK to modify a data structure in place (even in FP, if the language allows it), such as when it's a locally created one, or copied from the function's input:

def sorted(lst):
    ret = list(lst)  # make a copy
    # mutate ret
    return ret

-从外部看,此函数是一个纯函数,因为它不修改其输入(并且仅取决于其自变量而没有其他内容(即,它不具有(全局)状态)),这是该函数的另一个要求成为

— this function appears to be a pure function from the outside because it doesn't modify its inputs (and also only depends on its arguments and nothing else (i.e. it has no (global) state), which is another requirement for something to be a Pure Function).

只要您知道自己在做什么,del绝不是一件坏事.但是请务必谨慎使用任何形式的数据突变.始终以可能效率较低但更正确且数学上更优雅的代码开始.

So as long as you know what you're doing, del is by no means bad; but use any sort of data mutation with extreme care and only when you have to. Always start out with a possibly less efficient but more correct and mathematically elegant code.

...并学习功能编程:)

P.S.请注意,del还可以用于删除局部变量,从而消除对内存中对象的引用,这对于与GC相关的任何用途通常都是有用的.

P.S. note that del can also be used to delete local variables and thus eliminate references to objects in memory, which is often useful for whatever GC related purposes.

回答第二个问题:

关于您的 del完全删除对象问题的第二部分-并非如此:实际上,在Python中,甚至不可能告诉解释器/VM删除对象.对象是内存中的对象,因为Python是一种垃圾收集语言(例如Java,C#,Ruby,Haskell等),并且运行时决定了删除哪些内容以及何时删除.

As to the second part of your question about del removing objects completely — that's not the case: in fact in Python, it is not even possible to tell the interpreter/VM to remove an object from memory because Python is a garbage collected language (like Java, C#, Ruby, Haskell etc) and it's the runtime that decides what to remove and when.

相反,当像这样对变量(而不是字典键或列表项)进行调用时,del会做什么:

Instead, what del does when called on a variable (as opposed to a dictionary key or list item) like this:

del a

是因为它仅 会删除局部(或全局)变量,而不是变量所指向的内容(Python中的每个变量都保留一个指向其内容的指针/引用,而不是内容本身).实际上,由于本地人和全局人都作为字典存储在后台(请参见 locals() globals() ),等同于:

is that it only removes the local (or global) variable and not what the variable points to (every variable in Python holds a pointer/reference to its contents not the content itself). In fact, since locals and globals are stored as a dictionary under the hood (see locals() and globals()), del a is equivalent to:

del locals()['a']

del globals()['a']应用于全局时.

所以,如果您有:

a = []
b = a

您要创建一个列表,将对它的引用存储在a中,然后再创建该引用的另一个副本,然后将其存储到b中,而无需复制/触摸列表对象本身.因此,这两个调用会影响一个对象和一个对象:

you're making a list, storing a reference to it in a and then making another copy of that reference and storing it into b without copying/touching the list object itself. Therefore, these two calls affect one and the same object:

a.append(1)
b.append(2)
 # the list will be [1, 2]

而删除b与触摸b指向的内容无关:

whereas deleting b is in no way related to touching what b points to:

a = []
b = a
del b
# a is still untouched and points to a list

此外,即使在对象属性(例如del self.a)上调用del时,您实际上仍在修改字典self.__dict__,就像您实际上在修改locals()/globals()时一样del a.

Also, even when you call del on an object attribute (e.g. del self.a), you're still actually modifying a dictionary self.__dict__ just like you are actually modifying locals()/globals() when you do del a.

P.S.正如Sven Marcnah指出的那样,del locals()['a']实际上不会在函数内部删除局部变量a,这是正确的.这可能是由于locals()返回实际本地人的副本所致.但是,答案通常仍然有效.

P.S. as Sven Marcnah has pointed out that del locals()['a'] does not actually delete the local variable a when inside a function, which is correct. This is probably due to locals() returning a copy of the actual locals. However, the answer is still generally valid.

这篇关于使用del不好吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆