Qual é melhor em python, del ou delattr?

180

Isso pode ser bobo, mas está incomodando a parte de trás do meu cérebro há um tempo.

O Python nos fornece duas maneiras internas de excluir atributos de objetos, a palavra de comando del e a função interna delattr . Prefiro delattr porque acho um pouco mais explícito:

del foo.bar
delattr(foo, "bar")

Mas estou me perguntando se pode haver diferenças ocultas entre eles.

pydanny
fonte

Respostas:

265

O primeiro é mais eficiente que o segundo. del foo.barcompila para duas instruções de bytecode:

  2           0 LOAD_FAST                0 (foo)
              3 DELETE_ATTR              0 (bar)

considerando que delattr(foo, "bar")leva cinco:

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

Isso se traduz na primeira execução ligeiramente mais rápida (mas não é uma grande diferença - 0,15 μs na minha máquina).

Como os outros disseram, você realmente só deve usar a segunda forma quando o atributo que você está excluindo for determinado dinamicamente.

[Editado para mostrar as instruções de bytecode geradas dentro de uma função, onde o compilador pode usar LOAD_FASTe LOAD_GLOBAL]

Milhas
fonte
6
Qual ferramenta você usou para gerar isso?
Triptych
33
O dismódulo Você pode executá-lo na linha de comando usando python -m dise digitando algum código ou desmontar uma função com dis.dis().
Miles
15
Otimização prematura é a raiz de todo o mal. ;-) Mas sim, você está certo, é claro.
Lennart Regebro 13/07/2009
26
..so segue que o amor ao dinheiro é otimização prematura?
31410 John Fouhy
5
A otimização prematura é um subconjunto do amor ao dinheiro, pois significa que você está tentando gastar menos com o poder de processamento :) #
266 Rob Grant Rob
41
  • del é mais explícito e eficiente;
  • delattr permite a exclusão dinâmica de atributos.

Considere os seguintes exemplos:

for name in ATTRIBUTES:
    delattr(obj, name)

ou:

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)

Você não pode fazer isso com del .

Oleksandr Fedorov
fonte
2
Você pode fazer o segundo com del. del self.__dict__[name], Assumindo de negócios claro, nenhuma engraçado acontecendo com a classe meta
smac89
17

Inquestionavelmente o primeiro. Na minha opinião, é como perguntar se foo.baré melhor do que getattr(foo, "bar"), e não acho que alguém esteja fazendo essa pergunta :)

Alex Gaynor
fonte
3
Tenho certeza de que há pelo menos uma pessoa por aí que prefere getattr (foo, "bar") sobre foo.bar. Concedido, eu não concordo com eles. Mas essa pessoa ainda é suficiente para torná-la inquestionavelmente a primeira.
Jason Baker
3
@ Jason Então, nada é "inquestionavelmente melhor" do que qualquer outra coisa pela sua interpretação da frase. Eu acho que esse é um uso perfeitamente razoável de "inquestionavelmente".
Phob
26
O getattr é preferível quando existe a possibilidade de a propriedade não existir e você deseja definir um valor padrão sem ter que escrever blocos try / except. ie gettattr (foo, "bar", None)
Marc Gibbons
2
@ MarcGibbons: Espere, isso é uma coisa? Eu sempre usei o padrão if hasattr(obj, 'var') and obj.var == ...... Eu poderia reduzir isso para, if getattr(obj, 'var', None) == ...na maioria dos casos! Um pouco mais curto e fácil de ler, eu acho.
ArtOfWarfare
@ArtOfWarfare hasattrrealmente chamagetattr
cheniel
14

É realmente uma questão de preferência, mas o primeiro é provavelmente preferível. Eu usaria o segundo apenas se você não souber o nome do atributo que está excluindo antes do tempo.

Jason Baker
fonte
5

Assim como getattr e setattr, delattr deve ser usado apenas quando o nome do atributo for desconhecido.

Nesse sentido, é aproximadamente equivalente a vários recursos python usados ​​para acessar a funcionalidade incorporada em um nível mais baixo do que você normalmente tem disponível, como em __import__vez de importe em operator.addvez de+

Algorias
fonte
3

Não tenho certeza sobre o funcionamento interno, mas de uma reutilização de código e não seja uma perspectiva idiota de colegas de trabalho, use del. É mais claro e compreendido por pessoas vindas de outros idiomas também.

eleddy
fonte
1

Se você acha que delattré mais explícito, por que não usar getattro tempo todo e não object.attr?

Quanto ao assunto ... seu palpite é tão bom quanto o meu. Se não for significativamente melhor.

Dedos Sangrentos
fonte
1

É uma pergunta antiga, mas eu gostaria de colocar meus 2 centavos.

Embora, del foo.barseja mais elegante, às vezes você precisará delattr(foo, "bar"). Digamos, se você tiver uma interface de linha de comando interativa que permita que um usuário exclua dinamicamente qualquer membro do objeto digitando o nome , não terá outra opção a não ser usar o último formulário.

Kaosad
fonte