web-dev-qa-db-fra.com

Est-ce une bonne pratique d'appeler des fonctions dans un package via ::

J'écris des fonctions R qui utilisent des fonctions utiles dans d'autres packages comme stringr et base64enc. Est-il bon de ne pas appeler library(...) ou require(...) Pour charger ces packages en premier, mais d'utiliser :: Pour se référer directement à la fonction dont j'ai besoin, comme stringr::str_match(...)?

Est-ce une bonne pratique dans le cas général? Ou quel problème cela pourrait-il induire?

41
Kun Ren

Tout dépend du contexte.

:: Est principalement nécessaire s'il y a collisions d'espace de noms, des fonctions de différents packages portant le même nom. Lorsque je charge le package dplyr, il fournit une fonction filter, qui entre en collision (et masque) la fonction filter chargée par défaut dans le package stats . Donc, si je veux utiliser la version stats de la fonction, je devrai l'appeler avec stats::filter. Cela donne également une motivation pour ne pas charger beaucoup de paquets. Si vous ne voulez vraiment qu'une seule fonction d'un package, il peut être préférable d'utiliser :: Que de charger le package entier, surtout si vous savez que le package masquera les autres fonctions que vous souhaitez utiliser.

Pas en code, mais en texte, je trouve que :: Est très utile. Il est beaucoup plus concis de taper stats::filter Que "la fonction filter dans le package stats".

Du point de vue des performances , il y a un (très) petit prix pour l'utilisation de ::. Martin Maechler, membre de longue date de l'équipe de développement de R-Core, a écrit (sur la liste de diffusion r-devel (septembre 2017) )

Beaucoup de gens semblent oublier que chaque utilisation de :: Est un appel de fonction R et son utilisation est inefficace par rapport à l'utilisation du nom déjà importé.

La pénalité de performance est très faible , de l'ordre de quelques microsecondes, donc ce n'est un problème que lorsque vous avez besoin d'un code hautement optimisé. L'exécution d'une ligne de code qui utilise :: Un million de fois prendra une seconde ou deux de plus que le code qui n'utilise pas ::.

En ce qui concerne la portabilité, il est agréable de charger explicitement les packages en haut d'un script car cela permet de jeter un coup d'œil aux premières lignes et de voir quels packages sont nécessaires, en les installant si nécessaire avant d'aller trop loin dans autre chose, c'est-à-dire , à mi-chemin d'un long processus qui ne peut maintenant être achevé sans recommencer.

A part: un argument similaire peut être fait pour préférer library() à require(). La bibliothèque provoquera une erreur et s'arrêtera si le paquet n'est pas là, alors que require avertira mais continuera. Si votre code a un plan d'urgence au cas où le package ne serait pas là, alors utilisez certainement if (require(package)) ..., mais si votre code échoue sans package, vous devez utiliser library(package) au haut donc il échoue tôt et clairement.

Dans votre propre forfait

La solution générale consiste à créer votre propre package qui imports les autres packages que vous devez utiliser dans le fichier DESCRIPTION. Ces packages seront automatiquement installés lors de l'installation de votre package, vous pouvez donc utiliser pkg::fun En interne. Ou, en les important également dans le fichier NAMESPACE, vous pouvez import un package entier ou sélectivement importFrom des fonctions spécifiques sans avoir besoin de ::. Les opinions divergent sur ce point. Martin Maechler (même source r-devel que ci-dessus) dit:

Personnellement, j'ai l'impression que :: est beaucoup "surutilisé" de nos jours, notamment dans les packages où je recommande fortement d'utiliser importFrom () dans NAMESPACE, donc tout cela se produit au moment du chargement du package, puis pas en utilisant :: dans les sources du paquet lui-même.

D'un autre côté, tidyverse créateur Hadley Wickham dit dans son R Packages book :

Il est courant que les packages soient répertoriés dans Imports dans DESCRIPTION, mais pas dans NAMESPACE. En fait, voici ce que je recommande: répertoriez le package dans DESCRIPTION pour qu’il soit installé, puis faites-y toujours référence explicitement avec pkg::fun(). À moins qu'il y ait une bonne raison de ne pas le faire, il vaut mieux être explicite.

Avec deux experts R estimés donnant des recommandations opposées, je pense qu'il est juste de dire que vous devez choisir le style qui vous convient le mieux et répond à vos besoins de clarté, d'efficacité et de maintenabilité.


Si vous vous retrouvez fréquemment à utiliser une seule fonction d'un autre package, vous pouvez copier le code et l'ajouter à votre propre package. Par exemple, j'ai un package à usage personnel qui emprunte %nin% Au package Hmisc parce que je pense que c'est une excellente fonction, mais je n'utilise souvent rien d'autre de Hmisc. Avec roxygen2, Il est facile d'ajouter @author Et @references Pour attribuer correctement le code d'une fonction empruntée. Assurez-vous également que les licences de package sont compatibles lorsque vous effectuez cette opération.

54
Gregor Thomas