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

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

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

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

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

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

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

Ответы [ 4 ]

133 голосов
/ 27 декабря 2011

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

Директива

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

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

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


Отредактировано для добавления важного предупреждения:

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

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

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

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

Есть только два решения:

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

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

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

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

14 голосов
/ 26 декабря 2011

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

3 голосов
/ 22 марта 2018

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...