在Python中,del和delattr哪个更好?

235
这可能有点愚蠢,但它一直在我的脑海中挥之不去。
Python提供了两种内置的删除对象属性的方法,即“del”命令和“delattr”内置函数。我更喜欢使用“delattr”,因为我认为它更加明确:
del foo.bar
delattr(foo, "bar")

但我想知道它们之间是否存在底层差异。

8个回答

333
第一个比第二个更有效率。 del foo.bar 编译成了两个字节码指令:
  2           0 LOAD_FAST                0 (foo)
              3 DELETE_ATTR              0 (bar)

delattr(foo, "bar") 只需要五个参数:

  2           0 LOAD_GLOBAL              0 (delattr)
              3 LOAD_FAST                0 (foo)
              6 LOAD_CONST               1 ('bar')
              9 CALL_FUNCTION            2
             12 POP_TOP             

这意味着第一个运行略微更快(但差距不大——在我的机器上只有0.15微秒)。

就像其他人所说的,只有在要删除的属性是动态确定的时候,才应该使用第二种形式。

[编辑以显示函数内生成的字节码指令,编译器可以使用LOAD_FASTLOAD_GLOBAL]


8
你用了什么工具来生成这个? - Kenan Banks
46
dis 模块。你可以在命令行中使用 python -m dis 并输入一些代码来运行它,或者使用 dis.dis() 来反汇编一个函数。 - Miles
18
过早地优化是万恶之源。;-) 但是,是的,你当然是正确的。 - Lennart Regebro
27
那么,是否可以得出这样的结论:贪婪金钱就是过早优化? - John Fouhy
6
过早的优化是追求金钱的一个方面,因为它意味着你试图在处理能力上省钱。 - Rob Grant
显示剩余3条评论

50
  • del 更加明确和高效;
  • delattr 允许动态删除属性。

考虑以下示例:

for name in ATTRIBUTES:
    delattr(obj, name)
或:
def _cleanup(self, name):
    """Do cleanup for an attribute"""
    value = getattr(self, name)
    self._pre_cleanup(name, value)
    delattr(self, name)
    self._post_cleanup(name, value)

你不能用del达成这个目的。


3
假设没有元类的问题,您可以使用del self.__dict__[name] 来执行第二个操作。 - smac89

19

毫无疑问是前者更好。在我看来,这就像问foo.bar是否比getattr(foo, "bar")更好,而我认为没有人会提出这个问题 :)


4
我相信至少有一个人会更喜欢使用getattr(foo, "bar")而不是foo.bar。虽然我不太同意这种做法,但只要有那个人存在,它就不能被完全否定。 - Jason Baker
3
根据你对这个短语的解释,那么就没有什么事物是“毫无疑问地更好”的了。我认为使用“毫无疑问”是非常合理的。 - Phob
35
当属性可能不存在且希望设置默认值而无需编写try/except块时,使用getattr更好。例如,使用gettattr(foo,"bar",None)。 - Marc Gibbons
3
@MarcGibbons: 等等,这是一件事吗?我一直在使用模式 if hasattr(obj, 'var') and obj.var == ...... 在大多数情况下,我可以将其简化为 if getattr(obj, 'var', None) == ...!我认为这样更短更容易阅读。 - ArtOfWarfare
@ArtOfWarfare hasattr 实际上调用了 getattr - cheniel

16

这其实是个人喜好的问题,但第一个选项可能更好。只有在你事先不知道要删除的属性名时才使用第二个选项。


6

和getattr以及setattr一样,只有在属性名称未知的情况下才应使用delattr。

在这个意义上,它大致相当于几个Python功能,这些功能用于以比通常可用的更低级别访问内置功能,例如使用__import__而不是import以及使用operator.add而不是+


3

虽然不确定内部机制是如何运作的,但从代码可重用性和不成为讨厌同事的角度来看,请使用del。这更清晰且易于理解,适用于来自其他语言的人。


3

这是一个老问题,但我想发表我的意见。

虽然del foo.bar更加优雅,但有时你需要使用delattr(foo, "bar")。比如,如果你有一个交互式命令行界面,允许用户通过输入名称动态删除对象中的任何成员,那么你只能使用后一种形式。


2

如果您认为delattr更明确,那么为什么不一直使用getattr而不是object.attr呢?

至于底层实现...您的猜测和我一样好。如果不是显著地更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接