зачем нужна пустая функция

9

Я начал изучать Python и мне интересно, почему в языке программирования нужны пустые функции

например в питоне:

def empty_func():
    pass

даже в скриптах оболочки пустые функции доступны пустые функции.

Мое понимание и вопрос:

  1. Зачем языку программирования нужны пустые функции? Это просто игра с языком программирования или что-то еще, что действительно имеет значение?

  2. Если у этого есть цель, может кто-нибудь описать вариант использования или привести реальный пример использования пустых функций?

  3. Или есть ли традиция языков программирования, допускающих пустые функции?


РЕДАКТИРОВАТЬ (Вещи, которые я получил от чтения ваших ответов):

  • Для алгоритмов рисования или с абстрактными функциями
  • Для отправки форм без действий необходимо выполнить
  • Заполнитель для некоторых обязательных операций
jeyanthinath
источник
1
они могут быть использованы в качестве STUBS, если выполнение программы ожидает их найти / использовать, однако вы не хотите ничего менять через них.
Г.Рассовский

Ответы:

5

В языках оболочки семейства Bourne :команда, которая вообще ничего не делает, обычно используется в двух ситуациях:

  • Заполнитель для случаев, когда что-то ожидает обязательной команды, например

    while some_condtion
    do :
    done

    т.к. doтребуется хотя бы одна команда.

  • Отказ от аргументов, но выполнение побочных эффектов внутри списка аргументов, например

    : ${myvar=foo}

Я уверен, что есть и другие приложения, которые эксперты по оболочкам будут знать :)

В Python (и других языках) он используется реже. Он может выступать в качестве аргумента для функции более высокого порядка, когда вы на самом деле ничего не хотите делать. Например, скажем, у вас есть функция, которая отправляет форму и позволяет функции вызываться асинхронно после завершения отправки:

def submit(callback=empty_func):
    ...

Таким образом, если callbackне предоставлено, отправка все равно будет проходить, но дальнейшие действия выполняться не будут. Если бы вы использовали Noneзначение по умолчанию, вам пришлось бы явно проверить, был ли обратный вызов None, добавив беспорядок в код.

Rufflewind
источник
1

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

def full_algo():
  init_stuff()
  process_stuff()
  ...

Вы знаете, как это init_stuffбудет работать, это довольно просто в вашей голове, но вам это на самом деле не нужно, поэтому вы объявляете это пустой функцией. Это позволит вашему коду компилироваться и запускаться, не беспокоясь о кровавых деталях.

Другое использование для выпущенных приложений - при использовании наследования. Предположим, у вас есть большой класс, который определяет поведение кода, специфичного для платформы. Вы можете получить логику, подобную этой:

init_filesystem();
access_files();
release_filesystem();

Этот код будет работать на многих платформах, но некоторые платформы могут не нуждаться в инициализации файловой системы. Тогда ваше наследование будет выглядеть так (виртуальный с = 0 в C ++ означает, что производные классы ДОЛЖНЫ реализовывать эти методы):

class FileSystem{
  virtual void init_filesystem() = 0;
  virtual void access_files() = 0;
  virtual void release_filesystem() = 0;
};

Тогда конкретная реализация этого класса (интерфейса) может ничего не делать для некоторых из этих методов. Кроме того, базовый класс может объявлять пустые методы для init / release вместо объявления их виртуальными.

Наконец (и позорно), иногда вы поддерживаете очень старое приложение. Вы боитесь, что удаление методов сломает вещи. Это происходит, когда у вас сложное наследование, которое неправильно понимается, или когда у вас много указателей на функции (обратные вызовы). Вы просто удаляете код внутри них, чтобы они все равно вызывались, ничего не нарушая.

Эрик
источник
0

Rufflewind хорошо поработал, когда вы могли использовать пустую функцию в законченной программе. По моему опыту, он чаще используется в незавершенных программах, поэтому вы можете планировать, что вы собираетесь писать, и по-прежнему компилировать его, пока вы не приступите к его реализации. Другими словами, это обычно просто заполнитель.

Это необходимо в случае с python, потому что он использует отступы для маркировки блоков, в отличие от C-подобных языков, которые используют фигурные скобки {}. Это означает, что если у вас его нет pass, парсер не сможет определить, хотите ли вы оставить его пустым или забыли. Включение passделает синтаксический анализатор намного проще и дает удобное слово для поиска, когда вы ищете невыполненные блоки.

Карл Билефельдт
источник
1
Для незавершенного кода выбрасывание NotImplementedErrorявляется более адекватным решением, поскольку «ошибки никогда не должны проходить молча», а вызов нереализованной функции в живой программе является ошибкой.
ivan_pozdeev
Это зависит от. Для кода, который вы отправляете, да. Но если это код, который вы планируете реализовать через час, и вы просто оставляете его нереализованным, пока работаете над модульными тестами, лучше просто не оставлять реализацию. Часто мой рабочий процесс: 1) записать метод-заглушку с pass 2) записать модульный тест, который проверяет возвращаемое значение 3) проверить, что тест не пройден (так как метод возвращает неопределенное значение) 4) реализовать метод 5) проверить, что тест пройден
Gort the Robot
0

Хотя это и не то, что вы ожидаете сделать в Python, в мире драйверов устройств бывают ситуации, когда вам нужно предоставить пустую функцию для обработки события, которое, как вы (а) знаете, не произойдет, или ( б) не волнует, даже если это так.

Вы также видите это в C с обратными вызовами. Иногда вы увидите код, который просто предполагает, что вы предоставили обратный вызов, и попытается вызвать его, игнорируя риск нулевого указателя. Все, что вы можете сделать в этом случае, это предоставить пустую процедуру обратного вызова. (Да, я имею в виду конкретного продавца.)

Джон Р. Штром
источник
Я часто использовал passв качестве заполнителя при написании кода, особенно в классах, когда я хочу, чтобы что-то работало до того, как все будет завершено. Это действительно эквивалент Python {}, который Python не может сделать, так как он не использует фигурные скобки. В этом смысле все языки, которые мне известны, допускают это, просто для пары pythonтребуется ключевое слово. Даже в дни сборок у нас было NOP.
Gort the Robot
@StevenBurnap, обычно, когда я делаю что-то подобное, я включаю локальный эквивалент printf (">>> рутина XXX называется \ n");
Джон Р. Штром,