Bessere Erklärung der Verwendung von Imports / Depends

Das Handbuch ” Writing R Extensions ” enthält die folgenden statementen zum Verwenden von Imports oder Depends:

Die allgemeinen Regeln sind

  • Pakete, deren Namespace nur benötigt wird, um das Paket mit der Bibliothek (pkgname) zu laden, müssen im Feld “Imports” und nicht im Feld “Depends” aufgeführt sein.
  • Pakete, die hinzugefügt werden müssen, um das Paket mithilfe der Bibliothek (pkgname) erfolgreich zu laden, müssen nur im Feld “Abhängig” aufgeführt sein.

Kann mir jemand etwas mehr Klarheit verschaffen? Woher weiß ich, wann mein Paket nur geladene Namespaces benötigt und wann ich ein Paket anhängen muss? Was sind Beispiele für beides? Ich denke, das typische Paket ist nur eine Sammlung von functionen, die manchmal functionen in anderen Paketen aufrufen (wo ein bisschen Arbeit bereits programmiert wurde). Ist dieses Szenario 1 oder 2 oben?

Bearbeiten

Ich habe einen Blogeintrag mit einem Abschnitt zu diesem speziellen Thema geschrieben (suche nach ‘Imports v Depends’). Die Visuals machen es viel einfacher zu verstehen.

   

"Imports" ist sicherer als "Depends" (und macht auch ein Paket, das einen “besseren Bürger” in Bezug auf andere Pakete verwendet, die "Depends" ).

Eine "Depends" -Direktive versucht sicherzustellen, dass eine function von einem anderen Paket verfügbar ist, indem das andere Paket an den Hauptsuchpfad angehängt wird (dh die Liste der von search() Umgebungen). Diese Strategie kann jedoch vereitelt werden, wenn ein anderes Paket, das später geladen wird, eine identisch benannte function früher auf dem Suchpfad platziert. Chambers ( in SoDA ) verwendet das Beispiel der function "gam" , die sowohl in den Paketen gam als auch mgcv zu finden ist. Wenn zwei andere Pakete geladen würden, von denen eines abhängig von gam und eins von mgcv abhängig mgcv , würde die function, die bei Aufrufen von gam() , von der Reihenfolge abhängen, in der diese beiden Pakete angehängt wurden. Nicht gut.

Eine "Imports" -Richtlinie platziert das importierte Paket in (unmittelbar nach gesucht) und nicht im regulären Suchpfad. Wenn eines der Pakete im obigen Beispiel den "Imports" -Mechanismus verwendet, werden die Dinge auf zwei Arten verbessert. (1) Das Paket würde selbst steuern, welche mgcv function verwendet wird. (2) Indem der mgcv von den importierten Objekten mgcv , würde er möglicherweise nicht sogar die Abhängigkeit des anderen Pakets von der anderen mgcv function mgcv .

Aus diesem Grund ist die Verwendung von Namespaces eine gute Methode, weshalb sie jetzt von CRAN erzwungen wird und (insbesondere) die Verwendung von "Imports" sicherer ist als die Verwendung von "Depends" .


Bearbeitet, um eine wichtige Einschränkung hinzuzufügen:

Es gibt eine leider häufige Ausnahme zu dem obigen Hinweis: Wenn Ihr Paket auf ein Paket A angewiesen ist, das selbst auf ein anderes Paket B "Depends" , muss Ihr Paket wahrscheinlich A mit einer "Depends statement” verbinden.

Dies liegt daran, dass die functionen in Paket A mit der Erwartung geschrieben wurden, dass Paket B und seine functionen an den Pfad search() angehängt würden .

Eine "Depends" -Richtlinie wird Paket A laden und anhängen. An diesem Punkt wird die eigene "Depends" -Richtlinie von Paket A in einer Kettenreaktion bewirken, dass Paket B geladen und angehängt wird. functionen in Paket A werden dann in der Lage sein, die functionen in Paket B von denen sie abhängen.

Eine "Imports" -Richtlinie wird Paket A laden, aber nicht anhängen und Paket B weder laden noch anhängen. ( "Imports" erwartet schließlich, dass Paketschreiber den Namespace-Mechanismus verwenden, und dass Paket A "Imports" , um auf alle functionen in B zu verweisen, auf die es zugreifen muss.) Aufrufe Ihrer functionen an alle functionen in Paket A die auf functionen in Paket B angewiesen sind, wird folglich fehlschlagen.

Die einzigen beiden Lösungen sind entweder

  1. Lassen Sie Ihr Paket A mit der statement "Depends" anhängen.
  2. Besser auf lange Sicht, kontaktieren Sie den Maintainer von Paket A und bitten Sie sie, ihren Namespace sorgfältiger zu konstruieren (in den Worten von Martin Morgan in dieser verwandten Antwort ).

Hadley Wickham gibt eine einfache Erklärung ( http://r-pkgs.had.co.nz/namespace.html ):

Wenn Sie ein Paket in Depends oder Imports auflisten, wird sichergestellt, dass es bei Bedarf installiert wird. Der Hauptunterschied besteht darin, dass bei Imports nur das Paket Depends , Depends es an. Es gibt keine weiteren Unterschiede. […]

Wenn es keinen anderen guten Grund gibt, sollten Sie die Pakete immer in ” Imports not Depends . Das liegt daran, dass ein gutes Paket eigenständig ist und Änderungen an der globalen Umgebung minimiert (einschließlich des Suchpfads). Die einzige Ausnahme besteht, wenn Ihr Paket für die Verwendung in Verbindung mit einem anderen Paket vorgesehen ist. Zum Beispiel baut das analoge Paket auf vegan. Es ist nicht ohne Vegan nützlich, also hat es Vegan in Depends anstelle von Imports . In ähnlicher Weise sollte ggplot2 wirklich von Skalen abhängig sein, anstatt es zu importieren.

Chambers in SfDA sagt “Imports” zu verwenden, wenn dieses Paket einen “Namespace” -Mechanismus verwendet und da alle Pakete jetzt benötigt werden, dann könnte die Antwort nun immer ‘Importe’ verwenden. In der Vergangenheit konnten Pakete geladen werden, ohne tatsächlich Namespaces zu haben, und in diesem Fall müssten Sie Depends verwendet haben.

Hier ist eine einfache Frage, die Ihnen bei der Entscheidung helfen soll:

Erfordert Ihr Paket, dass der Endbenutzer direkten Zugriff auf die functionen eines anderen Pakets hat?

  • NEIN -> Importe (häufigste Antwort)
  • JA -> Hängt davon ab

Sie sollten “Abhängigkeiten” nur dann verwenden, wenn es sich bei Ihrem Paket um ein Add-On oder einen Companion zu einem anderen Paket handelt, bei dem Ihr Endbenutzer functionen aus Ihrem Paket und dem Paket “Depends” in seinem Code verwendet. Wenn Ihr Endbenutzer nur mit Ihren functionen interagiert und das andere Paket nur hinter den Kulissen arbeitet, verwenden Sie stattdessen “Importe”.

Der Nachteil dabei ist, dass, wenn Sie ein Paket zu “Imports” hinzufügen, wie Sie es normalerweise sollten, Ihr Code auf functionen aus diesem Paket dplyr::mutate() , indem Sie die volle Namespacesyntax verwenden, zB dplyr::mutate() , statt nur mutate() . Es macht den Code ein wenig klirrender zu lesen, aber es ist ein kleiner Preis für eine bessere Pakethygiene.