Что лучше в python, del или delattr?

181

Это может быть глупо, но какое-то время болит затылок.

Python предоставляет нам два встроенных способа удаления атрибутов из объектов, слово команды del и встроенную функцию delattr . Я предпочитаю delattr, потому что я думаю, что это немного более явно:

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

Но мне интересно, могут ли быть скрытые различия между ними.

pydanny
источник

Ответы:

266

Первый более эффективен, чем второй. 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_FASTи LOAD_GLOBAL]

миль
источник
6
Какой инструмент вы использовали для создания этого?
Триптих
33
disМодуль. Вы можете запустить его из командной строки, используя python -m disи введя некоторый код, или разобрать функцию с помощью dis.dis().
Майлз
15
Преждевременная оптимизация - корень всего зла. ;-) Да, конечно, вы правы.
Леннарт Регебро
26
..так из чего следует, что любовь к деньгам - это преждевременная оптимизация?
Джон Фухи
5
Преждевременная оптимизация является подмножеством любви к деньгам, так как это означает, что вы пытаетесь тратить меньше на вычислительную мощность :)
Роб Грант
41
  • 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)

Вы не можете сделать это с дель .

Александр Федоров
источник
2
Вы можете сделать второй с Del. del self.__dict__[name]Если предположить, что с мета-классом, конечно, нет ничего смешного
smac89
17

Несомненно бывший. На мой взгляд, это все равно что спрашивать, foo.barлучше ли getattr(foo, "bar"), и я не думаю, что кто-то задает этот вопрос :)

Алекс Гейнор
источник
3
Я уверен, что есть хотя бы один человек, который предпочел бы getattr (foo, "bar"), а не foo.bar. Конечно, я бы не согласился с ними. Но этого одного человека все еще достаточно, чтобы сделать его, несомненно, первым.
Джейсон Бейкер
3
@ Джейсон Тогда ничто не является «несомненно лучше», чем что-либо еще по вашей интерпретации фразы. Я думаю , что это вполне разумное использование «бесспорно».
Фоб
26
getattr предпочтительнее, когда есть вероятность, что свойство не существует, и вы хотите установить значение по умолчанию без необходимости писать блоки try / кроме. то есть. gettattr (foo, "bar", None)
Марк Гиббонс,
2
@MarcGibbons: Подождите, это вещь? Я всегда использовал шаблон if hasattr(obj, 'var') and obj.var == ...... Я мог бы просто уменьшить это до, if getattr(obj, 'var', None) == ...в большинстве случаев! Думаю, немного короче и проще для чтения.
ArtOfWarfare
@ArtOfWarfare hasattrфактически звонитgetattr
cheniel
14

Это действительно вопрос предпочтений, но первый, вероятно, предпочтительнее. Я бы использовал второй, только если вы не знаете название атрибута, который вы удаляете заранее.

Джейсон Бейкер
источник
5

Как и getattr и setattr, delattr следует использовать только тогда, когда имя атрибута неизвестно.

В этом смысле он примерно эквивалентен нескольким функциям Python, которые используются для доступа к встроенным функциям на более низком уровне, чем у вас обычно есть, например __import__вместо importили operator.addвместо+

Algorias
источник
3

Не уверен насчет внутренней работы, но с точки зрения повторного использования кода и не будь мудрым коллегой, используйте del. Это понятнее и понятнее людям с других языков.

eleddy
источник
1

Если вы думаете, что delattrболее четко, то почему бы не использовать getattrвсе время, а не object.attr?

Что касается под капотом ... Ваше предположение так же хорошо, как мое. Если не значительно лучше.

Кровоточащие пальцы
источник
1

Это старый вопрос, но я бы хотел поставить свои 2 цента.

Хотя, del foo.barизящнее, порой понадобится delattr(foo, "bar"). Скажем, если у вас есть интерактивный интерфейс командной строки, который позволяет пользователю динамически удалять любой элемент в объекте, вводя имя , то у вас нет другого выбора, кроме как использовать последнюю форму.

kaosad
источник