Лучшее объяснение того, когда использовать импорт / зависимость


148

В руководстве « Writing R Extensions » содержатся следующие рекомендации о том, когда использовать импорт или зависимость:

Общие правила

  • Пакеты, чье пространство имен требуется только для загрузки пакета с использованием библиотеки (pkgname), должны быть указаны в поле «Импорт», а не в поле «Зависит».
  • Пакеты, которые необходимо подключить для успешной загрузки пакета с использованием библиотеки (pkgname), должны быть указаны только в поле «Зависит».

Может кто-нибудь дать немного больше ясности по этому поводу? Как я могу узнать, когда мой пакет нуждается только в загруженных пространствах имен по сравнению с тем, когда мне нужно присоединить пакет? Каковы примеры обоих? Я думаю, что типичный пакет - это просто набор функций, которые иногда вызывают функции в других пакетах (где некоторая часть работы уже была закодирована). Этот сценарий 1 или 2 выше?

редактировать

Я написал сообщение в блоге с разделом по этой конкретной теме (поиск «Imports v Depends»). Визуальные эффекты облегчают понимание.


1
Ваш пост в блоге рассказал мне все о структуре пакета, еще когда я начал планировать модули . Спасибо!
Конрад Рудольф

Ответы:


143

"Imports"безопаснее, чем "Depends"(а также делает пакет, использующий его, «лучшим гражданином» по сравнению с другими пакетами, которые его используют "Depends").

А "Depends"директива попытка гарантировать , что функция из другого пакета можно, прикрепив другой пакет к основному пути поиска (то есть список сред , возвращенных search()). Эта стратегия, однако, может быть сорвана, если другой пакет, загруженный позже, поместит функцию с одинаковым именем ранее в путь поиска. Камеры ( в соде ) использует пример функции "gam", которая находится в обоих gamи mgcvпакетах. Если были загружены два других пакета, один из которых зависит, gamа другой mgcv- от функции, найденной вызовами, gam()будет зависеть от порядка, в котором они были присоединены эти два пакета. Не хорошо.

"Imports"Директива должна быть использована для любого поддерживающего пакета, функции которого должны быть помещены в <imports:packageName>(поиск сразу после <namespace:packageName>), а не на регулярной пути поиска. Если какой-либо из пакетов в приведенном выше примере использует "Imports"механизм (который также требует importили importFromдирективы в NAMESPACEфайле), ситуация может быть улучшена двумя способами. (1) Пакет сам получит контроль над тем, какая mgcvфункция используется. (2) Если очистить основной путь поиска от импортированных объектов, это даже не нарушит зависимость другого пакета от другой mgcvфункции.

Вот почему использование пространств имен является такой хорошей практикой, почему теперь оно обеспечивается CRAN, и (в частности) почему использование "Imports"безопаснее, чем использование "Depends".


Отредактировано, чтобы добавить важное предупреждение:

К сожалению, из приведенного выше совета есть одно общее исключение: если ваш пакет основан на пакете, Aкоторый сам находится "Depends"в другом пакете B, ваш пакет, вероятно, необходимо будет прикрепить Aс помощью "Dependsдирективы.

Это потому, что функции в пакете Aбыли написаны с ожиданием, что пакет Bи его функции будут присоединены к search()пути .

"Depends"Директива будет загружать и приложить пакет A, в котором точки пакета A«s собственная "Depends"будет, в цепной реакции, потому что пакет директива Bдолжна быть загружен и прилагается также. Функции в пакете Aсмогут найти функции в пакете, Bна которые они полагаются.

"Imports"Директива будет загружаться , но не приложить пакет Aи будет ни груз , ни присоединять пакет B. (в "Imports"конце концов, ожидается, что разработчики пакетов используют механизм пространства имен, и этот пакет Aбудет использовать "Imports"для указания на любые функции, к Bкоторым ему необходим доступ.) Вызовы вашими функциями для любых функций в пакете, Aкоторые полагаются на функции в пакете B, следовательно потерпеть неудачу.

Единственные два решения:

  1. Сделайте, чтобы ваш пакет приложил пакет, Aиспользуя "Depends"директиву
  2. Лучше, в конце концов, связаться с сопровождающим пакета Aи попросить их сделать более осторожную работу по созданию своего пространства имен (по словам Мартина Моргана в этом связанном ответе ).

1
Недавно задав такой же вопрос и недавно решительно боролись с этими проблемами, это тонкие и часто плохо сообщаемые концепции. Я отошлю вас сюда для другого объяснения: stackoverflow.com/questions/7880355/…
Брайан Хэнсон,

@BryanHanson - Спасибо, что написали заметки по этой ссылке. Различия между Importsи Dependsтребованиями версии WRT и проверкой примеров в .Rdфайлах действительно тонкие и стоит знать.
Джош О'Брайен

1
Предостережение о зависимостях, которые используют «Зависит» - ужасная вещь. Это означает, что я в принципе не могу использовать «Импорт» в своем пакете, пока все остальные тоже. = (
Кен Уильямс

Одна вещь, по которой я до сих пор неясна, это то, что, если я пишу пакет и хочу Imports: ggplot2, почему мой пакет не находит autoplotфункцию? Очевидно, Dependsприкрепляет библиотеку пакетов ggplot2и поэтому нет проблем. Например, у меня есть функция, autoplot.myFunction() которая использует @import ggplot2тег, и мой пакет имеет, Imports: ggplot2но я получаю сообщение об ошибке: Error in eval(expr, envir, enclos) : could not find function "autoplot"когда я пытаюсь использовать его.
nathaneastwood

1
@ Виллем Спасибо. Вы, конечно, правы, и я отредактировал ответ, чтобы очистить вводящее в заблуждение содержание. Отчасти затрудняло ответить то, что, хотя ОП сформулировал свой вопрос со ссылкой на разделы Dependsи , он действительно спрашивал о том, что означает «импорт» функции (а не «зависимость» от нее). Поскольку на этот последний вопрос я пытался ответить (и - я подозреваю, что большинство людей, ищущих этот ответ, хотят знать), я оставлю ответ без изменений. ImportsDESCRIPTION
Джош О'Брайен

31

Хэдли Уикхем дает простое объяснение ( http://r-pkgs.had.co.nz/namespace.html ):

Перечисление пакета в один Dependsили Importsгарантирует его установку при необходимости. Основное отличие заключается в том, что, где Importsпросто загружается пакет, Dependsприкрепляется его. Других различий нет. [...]

Если нет веской причины, вы должны всегда указывать пакеты Importsне Depends. Это потому, что хороший пакет является автономным и сводит к минимуму изменения в глобальной среде (включая путь поиска). Единственное исключение - если ваш пакет предназначен для использования в сочетании с другим пакетом. Например, аналог пакета основывается на вегане. Это бесполезно без вегана, поэтому Dependsвместо него есть веган Imports. Точно так же ggplot2 должен действительно зависеть от масштабов, а не импортировать его.


15

Камеры в SfDA говорят, что следует использовать «Imports», когда этот пакет использует механизм «пространства имен», и поскольку теперь все пакеты должны иметь их, тогда ответом может быть всегда использование «Imports». В прошлом пакеты можно было загружать, не имея фактически пространства имен, и в этом случае вам нужно было бы использовать Зависит.


2
когда пакет указан в "import" и я хочу использовать функцию в пакете, нужно ли моим собственным функциям вызывать библиотеку (...) или все функции уже доступны в пути поиска? Кроме того, что такое SfDA? ссылки?
SFun28

2
Программное обеспечение для анализа данных : springer.com/statistics/computanional+statistics/book/… ... что касается ваших вопросов, я не знаю ответа от случая к случаю, но вы можете довольно легко взломать минимальный тестовый пакет и найти ответ эмпирически ...
Бен Болкер

1
SfDA == "Программное обеспечение для анализа данных". [65] на r-project.org/doc/bib/R-books.html . Если пакет указывает другой пакет, вы должны увидеть сообщение о загрузке зависимостей (encies) и import (ations), когда вы используете в консоли библиотеку () или require (). Да, они должны быть доступны.
IRTFM

4
+1 - это мое сильное впечатление. Кроме того, пакет, указанный в импорте, будет найден сразу после <namespace:packageName>, как часть <imports:packageName>. Дальнейшего вызова library()не требуется, и R не уведомит вас на консоли во время загрузки пакета, если Importпакет ed не найден.
Джош О'Брайен

5

Вот простой вопрос, который поможет вам решить, какой из них использовать:

Требует ли ваш пакет, чтобы конечный пользователь имел прямой доступ к функциям другого пакета?

  • НЕТ -> Импорт (наиболее распространенный ответ)
  • ДА -> Зависит

Единственный раз, когда вы должны использовать «Зависит», это когда ваш пакет является дополнением или компаньоном к другому пакету, когда ваш конечный пользователь будет использовать функции из вашего пакета и пакета «Зависит» в своем коде. Если ваш конечный пользователь будет взаимодействовать только с вашими функциями, а другой пакет будет выполнять только скрытую работу, используйте вместо этого «Импорт».

Предостережение в том, что если вы добавляете пакет в 'Imports', как обычно, ваш код должен будет ссылаться на функции из этого пакета, используя полный синтаксис пространства имен, например dplyr::mutate(), вместо just mutate(). Это делает код немного неудобнее для чтения, но это небольшая цена за лучшую гигиену упаковки.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.