Подтвердить что ты не робот

Является ли хорошей практикой вызывать функции в пакете через::

Я пишу некоторые функции R, которые используют некоторые полезные функции в других пакетах, таких как stringr и base64enc. Хорошо ли не вызывать library(...) или require(...), чтобы сначала загрузить эти пакеты, но использовать ::, чтобы напрямую ссылаться на нужную мне функцию, например stringr::str_match(...)?

Это хорошая практика в общем случае? Или какая проблема может возникнуть?

4b9b3361

Ответ 1

Все зависит от контекста.

:: в первую очередь необходимо, как говорит @hrbrmstr, если есть конфликты пространства имен. Если я загружаю пакеты dplyr, а затем arm, arm::select маскирует dplyr::select, поэтому мне может потребоваться указать, какой из них я имею в виду впоследствии в script. Это также дает мотивацию не загружать много пакетов. Если вам действительно нужна только одна функция из пакета (скажем, просто arm::display), лучше использовать ::, чем загружать весь пакет, особенно если вы знаете, что пакет будет маскировать другие функции, которые вы хотите использовать.

Не в коде, но в общении, я нахожу :: очень полезным. Это гораздо более кратким, чем тип arm::display, чем "display в пакете arm".

С точки зрения производительности существует (очень) небольшая цена за использование ::. Мартин Маэчер написал (в r-devel список рассылки)

Многие люди, похоже, забывают, что каждое использование :: является R вызов функции и использование ее неэффективны по сравнению с использованием только уже импортированное имя.

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

Что касается переносимости, полезно явно загружать пакеты в верхней части script, потому что это позволяет легко взглянуть на первые несколько строк и посмотреть, какие пакеты необходимы, при необходимости установить их, прежде чем получить слишком глубокие во всем остальном, т.е. на полпути через длинный процесс, который теперь не может быть завершен без начала.

Кроме того, аналогичный аргумент можно сделать, чтобы предпочесть library() над require(). Библиотека вызовет ошибку и остановится, если пакета там нет, тогда как require будет предупреждать, но продолжать. Если у вашего кода есть план действий на случай непредвиденных обстоятельств, если пакет там отсутствует, то, во всяком случае, используйте if (require(package)) ..., но если ваш код завершится неудачно без пакета, вы должны использовать library(package) вверху, чтобы он не срабатывал рано и четко. (Спасибо Хью и BondedDust в комментариях.)

Написание собственного пакета

Общее решение состоит в том, чтобы сделать ваш собственный пакет imports другими пакетами, которые необходимо использовать в файле DESCRIPTION. Они будут автоматически установлены, когда ваш пакет будет установлен, тогда вы можете использовать pkg::fun. Или, импортировав их в файл NAMESPACE, вы можете import весь пакет или выборочно importFrom определенные функции и не нуждаться в ::. Мнения различаются по этому поводу. Член R-Core Martin Maechler (тот же источник r-devel, что и выше) говорит:

Лично у меня сложилось впечатление, что:: is много "злоупотребляли" в настоящее время, особенно в пакетах, где я сильно защитите использование importFrom() в NAMESPACE, так что все это происходит при загрузке пакета, а затем не используя :: в пакете источников.

С другой стороны, создатель Tidyverse Хэдли Уикхэм говорит в своей R Packages book:

Его общий для пакетов, которые будут перечислены в imports в DESCRIPTION, но не в NAMESPACE. Фактически, это то, что я рекомендую: перечислите пакет в DESCRIPTION, чтобы он был установлен, а затем всегда ссылайтесь на него явно с помощью pkg::fun(). Если нет веской причины не делать этого, лучше быть явным.

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


Если вы часто используете только одну функцию из другого пакета, вы можете скопировать код и добавить его в свой собственный пакет. Например, у меня есть пакет для личного использования, который заимствует %nin% из пакета Hmisc, потому что я считаю, что это отличная функция, но я не часто использую что-либо еще из Hmisc. С помощью roxygen2 легко добавить @author и @references, чтобы правильно атрибут кода для заимствованной функции. Также убедитесь, что лицензии на пакет совместимы при этом.