Краще пояснення, коли використовувати імпорт / залежно


148

Посібник " Написання розширень R " надає наступні вказівки щодо використання імпорту або залежностей:

Загальні правила є

  • Пакети, простору імен яких потрібно лише для завантаження пакету за допомогою бібліотеки (pkgname), повинні бути вказані в полі "Імпорт", а не в полі "Залежить".
  • Пакети, які потрібно приєднати для успішного завантаження пакета за допомогою бібліотеки (pkgname), повинні бути вказані лише у полі "Залежить".

Чи може хтось надати трохи більше ясності щодо цього? Як дізнатися, коли мій пакет потребує завантаження лише просторів імен порівняно з тим, коли мені потрібен пакет, який потрібно додавати? Якими є приклади обох? Я думаю, що типовий пакет - це лише сукупність функцій, які іноді викликають функції в інших пакетах (де деякі роботи вже зашифровані). Це сценарій 1 або 2 вище?

Редагувати

Я написав допис у блозі з розділом на цю конкретну тему (пошук "Імпорт проти залежних"). Наочні зображення значно полегшують розуміння.


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

Відповіді:


143

"Imports"є безпечнішим, ніж "Depends"(а також робить пакет, використовуючи його "кращим громадянином" стосовно інших пакетів, які використовують"Depends" ).

А "Depends"директива спроба гарантувати , що функція з іншого пакета можна, прикріпивши інший пакет до основного шляху пошуку (тобто список середовищ , повернутих search()). Ця стратегія, однак, може бути зірвана, якщо інший пакет, завантажений пізніше, розміщує ідентично названу функцію раніше на шляху пошуку. Чемберс ( в SoDA ) використовує приклад функції "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файлах дійсно тонкі і варто знати.
Josh O'Brien

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
@Willem Дякую Ви, звичайно, правильні, і я відредагував відповідь, щоб очистити оманливий вміст. Частина того, що ускладнила відповідь, полягає в тому, що, хоча ОП формулювала своє запитання з посиланням на Dependsта Importsрозділи DESCRIPTION, він справді запитував, що означає "імпорт" функції (а не "залежно" від неї). Оскільки це останнє - це питання, на яке я намагався відповісти (і - підозрюю - що хочуть знати більшість людей, які шукають цю відповідь), я залишу відповідь інакше незмінною.
Josh O'Brien

31

Хедлі Вікхем дає просте пояснення ( http://r-pkgs.had.co.nz/namespace.html ):

Перерахування пакету в DependsабоImports гарантує його встановлення за потреби. Основна відмінність полягає в тому, що там, де Importsпросто завантажується пакет, Dependsприкріплюється його. Інших відмінностей немає. [...]

Якщо немає поважних причин інакше, ви завжди повинні перераховувати пакети в Importsне Depends. Це тому, що хороший пакет є самостійним і мінімізує зміни в глобальному середовищі (включаючи шлях пошуку). Єдиний виняток - якщо ваш пакунок призначений для використання разом з іншим пакетом. Наприклад, аналоговий пакет будується поверх веганського. Це не корисно без веганства, тому він має веганську Dependsзамість Imports. Аналогічно, ggplot2 дійсно повинен залежати від масштабів, а не імпортувати їх.


15

Chambers в SfDA говорить, що використовувати "Імпорт", коли цей пакет використовує механізм "простору імен", і оскільки всі пакети тепер повинні мати їх, то тепер у відповіді завжди можна використовувати "Імпорт". У минулому пакунки могли бути завантажені без фактичного простору імен, і в цьому випадку вам потрібно було б використовувати залежно.


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

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

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

4
+1 - Це теж моє сильне враження. Також пакет, вказаний в імпорті, буде шукати відразу після <namespace:packageName>, як частина <imports:packageName>. Більше не потрібно більше дзвонити library(), і R не повідомляє вас на консолі під час завантаження пакета, якщо Importне вдасться знайти пакет ed.
Josh O'Brien

5

Ось просте запитання, яке допоможе вам вирішити, який використовувати:

Чи вимагає ваш пакет, щоб кінцевий користувач мав прямий доступ до функцій іншого пакету?

  • НІ -> Імпорт (найчастіша відповідь)
  • ТАК -> Залежить

Єдиний раз, коли ви повинні використовувати "Залежить", це коли ваш пакет є додатком або супутником до іншого пакету, де ваш кінцевий користувач буде використовувати функції як вашого пакета, так і пакета "Залежить" у своєму коді. Якщо ваш кінцевий користувач буде взаємодіяти лише з вашими функціями, а інший пакет буде виконувати роботу лише за кадром, тоді замість цього використовуйте "Імпорт".

Застереження в цьому полягає в тому, що якщо ви додасте пакет до "Імпорту", як зазвичай, ваш код повинен буде посилатися на функції цього пакету, використовуючи повний синтаксис простору імен, наприклад dplyr::mutate(), замість просто mutate(). Це робить код трохи незграбним для читання, але це плата за кращу гігієну упаковки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.