Co jest lepsze w Pythonie, Del czy Delattr?

181

To może być głupie, ale od jakiegoś czasu męczy mnie tył mózgu.

Python daje nam dwa wbudowane sposoby usuwania atrybutów z obiektów, słowo polecenia del i funkcję wbudowaną delattr . Wolę delattr, ponieważ wydaje mi się, że jest nieco bardziej wyraźny:

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

Ale zastanawiam się, czy mogą istnieć między nimi ukryte różnice.

pydanny
źródło

Odpowiedzi:

266

Pierwsza jest bardziej wydajna niż druga. del foo.barkompiluje się do dwóch instrukcji kodu bajtowego:

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

podczas gdy delattr(foo, "bar")zajmuje pięć:

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

Przekłada się to na pierwsze uruchomienie nieco szybciej (ale nie jest to duża różnica - na moim komputerze 0,15 μs).

Jak powiedzieli inni, tak naprawdę powinieneś używać drugiego formularza tylko wtedy, gdy usuwany atrybut jest określany dynamicznie.

[Edytowano, aby pokazać instrukcje kodu bajtowego wygenerowane wewnątrz funkcji, w przypadku których kompilator może używać LOAD_FASTi LOAD_GLOBAL]

Miles
źródło
6
Jakiego narzędzia użyłeś do wygenerowania tego?
Tryptyk
33
disModuł. Możesz go uruchomić z linii poleceń używając python -m disi wpisując jakiś kod lub zdemontować funkcję za pomocą dis.dis().
Miles
15
Przedwczesna optymalizacja jest źródłem wszelkiego zła. ;-) Ale tak, oczywiście masz rację.
Lennart Regebro
26
.. czy z tego wynika, że ​​miłość do pieniędzy to przedwczesna optymalizacja?
John Fouhy,
5
Przedwczesna optymalizacja to podzbiór zamiłowania do pieniędzy, ponieważ oznacza to, że starasz się wydawać mniej na moc obliczeniową :)
Rob Grant
41
  • del jest bardziej wyraźny i skuteczny;
  • delattr umożliwia dynamiczne usuwanie atrybutów.

Rozważ następujące przykłady:

for name in ATTRIBUTES:
    delattr(obj, name)

lub:

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)

Nie możesz tego zrobić z del .

Oleksandr Fedorov
źródło
2
Drugą możesz zrobić za pomocą del. del self.__dict__[name], zakładając oczywiście, że z klasą meta nie dzieje się żaden śmieszny interes
smac89
17

Bezsprzecznie ten pierwszy. Moim zdaniem to tak, jakby pytać, czy foo.barjest lepsze niż getattr(foo, "bar"), i nie sądzę, żeby ktokolwiek zadawał to pytanie :)

Alex Gaynor
źródło
3
Jestem pewien, że istnieje przynajmniej jedna osoba, która wolałaby getattr (foo, "bar") od foo.bar. Zgoda, nie zgodziłbym się z nimi. Ale ta jedna osoba wciąż wystarczy, aby nie bezsprzecznie była pierwsza.
Jason Baker
3
@Jason W takim razie nic nie jest „bezsprzecznie lepsze” niż cokolwiek innego dzięki twojej interpretacji wyrażenia. Myślę, że jest to całkiem rozsądne użycie słowa „bez wątpienia”.
Fob
26
getattr jest preferowane, gdy istnieje możliwość, że właściwość nie istnieje i chcesz ustawić wartość domyślną bez konieczności pisania bloków try / except. to znaczy. gettattr (foo, "bar", None)
Marc Gibbons
2
@MarcGibbons: Czekaj, to jest rzecz? Zawsze używałem tego wzorca if hasattr(obj, 'var') and obj.var == ...... if getattr(obj, 'var', None) == ...W większości przypadków mogłem to po prostu zredukować ! Myślę, że trochę krótszy i łatwiejszy do odczytania.
ArtOfWarfare
@ArtOfWarfare hasattrfaktycznie dzwonigetattr
cheniel
14

To naprawdę kwestia preferencji, ale pierwsza jest prawdopodobnie lepsza. Drugiego użyłbym tylko wtedy, gdy nie znasz nazwy atrybutu, który usuwasz z wyprzedzeniem.

Jason Baker
źródło
5

Podobnie jak getattr i setattr, delattr powinien być używany tylko wtedy, gdy nazwa atrybutu jest nieznana.

W tym sensie jest to z grubsza odpowiednik kilku funkcji Pythona, które są używane do uzyskiwania dostępu do wbudowanych funkcji na niższym poziomie niż zwykle dostępne, na przykład __import__zamiast importi operator.addzamiast+

Algorias
źródło
3

Nie jestem pewien co do wewnętrznego działania, ale z perspektywy ponownego wykorzystania kodu i nie bądź głupim współpracownikiem, użyj del. Jest to bardziej jasne i zrozumiałe również dla osób pochodzących z innych języków.

eleddy
źródło
1

Jeśli uważasz, że delattrjest bardziej wyraźny, dlaczego nie używać go przez getattrcały czas, a nie object.attr?

Co do miejsca pod maską ... Twoje przypuszczenia są równie dobre jak moje. Jeśli nie znacznie lepiej.

Krwawiące palce
źródło
1

To stare pytanie, ale chciałbym włożyć swoje 2 centy.

Chociaż del foo.barjest bardziej elegancki, czasami będziesz potrzebować delattr(foo, "bar"). Powiedzmy, że jeśli masz interaktywny interfejs wiersza poleceń, który umożliwia użytkownikowi dynamiczne usuwanie dowolnego elementu w obiekcie przez wpisanie jego nazwy , nie masz innego wyboru, jak tylko użyć tej drugiej formy.

kaosad
źródło