web-dev-qa-db-fra.com

Comment importer un module personnalisé à Julia

J'ai un module que j'ai écrit ici:

# Hello.jl
module Hello
    function foo
        return 1
    end
end

et

# Main.jl
using Hello
foo()

Lorsque j'exécute le module Main:

$ Julia ./Main.jl

Je reçois cette erreur:

ERROR: LoadError: ArgumentError: Hello not found in path
 in require at ./loading.jl:249
 in include at ./boot.jl:261
 in include_from_node1 at ./loading.jl:320
 in process_options at ./client.jl:280
 in _start at ./client.jl:378
while loading /Main.jl, in expression starting on line 1
14
dopatraman

Vous devriez include("./Hello.jl") avant using Hello

10
张实唯

Il y a déjà eu quelques réponses courtes, mais je voulais donner une réponse plus complète si possible. 

Lorsque vous exécutez using MyModule, Julia ne le recherche que dans une liste de répertoires appelée LOAD_PATH. Si vous tapez LOAD_PATH dans Julia REPL, vous obtiendrez le résultat suivant:

2-element Array{ByteString,1}:
 "/Applications/Julia-0.4.5.app/Contents/Resources/Julia/local/share/Julia/site/v0.4"
 "/Applications/Julia-0.4.5.app/Contents/Resources/Julia/share/Julia/site/v0.4"

Ce sont les répertoires que Julia recherchera pour les modules à inclure lorsque vous tapez using Hello. Dans l'exemple que vous avez fourni, étant donné que Hello n'était pas dans votre LOAD_PATH, Julia n'a pas pu le trouver. 

Si vous souhaitez inclure un module local, vous pouvez spécifier son emplacement par rapport à votre répertoire de travail actuel. 

Julia> include("./src/Hello.jl")

Une fois le fichier inclus, vous pouvez exécuter using Hello normalement pour obtenir le même comportement. Pour certains scripts, c'est probablement la meilleure solution. Toutefois, si vous vous retrouvez régulièrement devant include() avec un certain ensemble de répertoires, vous pouvez les ajouter définitivement à votre LOAD_PATH

Ajout de répertoires à LOAD_PATH

Ajouter manuellement des répertoires à votre LOAD_PATH peut s'avérer difficile si vous souhaitez utiliser régulièrement des modules particuliers stockés en dehors du Julia LOAD_PATH. Dans ce cas, vous pouvez ajouter des répertoires supplémentaires à la variable d'environnement LOAD_PATH. Julia effectuera alors automatiquement une recherche dans ces répertoires à chaque fois que vous lancerez une commande import ou using

Une façon de faire est d'ajouter ce qui suit à votre .basrc, .profile, .zshrc

export Julia_LOAD_PATH="/path/to/module/storage/folder"

Cela ajoutera ce répertoire aux répertoires standard que Julia recherchera. Si vous courez alors 

Julia> LOAD_PATH

Il devrait revenir

3-element Array{ByteString,1}:
 "/path/to/module/storage/folder"
 "/Applications/Julia-0.4.5.app/Contents/Resources/Julia/local/share/Julia/site/v0.4"
 "/Applications/Julia-0.4.5.app/Contents/Resources/Julia/share/Julia/site/v0.4"

Vous pouvez maintenant exécuter librement using Hello et Julia trouvera automatiquement le module (tant qu'il est stocké sous /path/to/module/storage/folder

Pour plus d'informations, consultez la page this des documents Julia. 

13
Remy Prechelt

Il existe une nouvelle réponse à cette question depuis la publication de Julia v0.7 et v1.0 qui est légèrement différente. Je devais simplement faire cela, alors je me suis dit que je posterais mes découvertes ici.

Comme déjà expliqué dans d'autres solutions, il est nécessaire d'inclure le script approprié qui définit le module. Toutefois, le module personnalisé n'étant pas un package, il ne peut pas être chargé en tant que package avec les mêmes commandes using ou import, comme cela pouvait être le cas dans les anciennes versions de Julia.

Donc, le script Main.jl serait écrit avec une importation relative comme ceci:

include("./Hello.jl")
using .Hello
foo()

J'ai trouvé cela expliqué simplement dans le commentaire du discours de Stefan Karpinski sur une question similaire. Comme il le décrit, la situation peut également devenir plus complexe lorsqu'il s'agit de sous-modules. La section documentation sur les chemins de modules est également une bonne référence.

13
kiliantics

Bien que la réponse de 张 实 唯 soit la plus pratique, vous ne devriez pas utiliser include en dehors de REPL. Si vous écrivez un fichier de programme, évitez d'ajouter le répertoire approprié à LOAD_PATH. Remy donne une très bonne explication sur la façon de procéder, mais il convient également d'expliquer pourquoi vous devriez le faire en premier lieu. (De plus, à partir de la documentation: Push!(LOAD_PATH, "/Path/To/My/Module/"), mais notez que votre module et votre fichier doivent avoir le même nom)

Le problème est que tout ce que vous include sera défini là où vous appelez includemême s'il est également défini ailleurs. Dans la mesure où l'objectif des modules est de réutiliser, vous utiliserez probablement éventuellement MyModule dans plusieurs fichiers. Si vous appelez include dans chaque fichier, chacun aura sa propre définition de MyModule et, même si elles sont identiques, il s'agira de définitions différentes. Cela signifie que toutes les données définies dans la variable MyModule (telles que les types de données) ne seront pas les mêmes.

Pour comprendre pourquoi il s’agit d’un énorme problème, considérons ces trois fichiers:

types.jl

module TypeModule
struct A end
export A
end

a_function.jl

include("types.jl")
module AFunctionModule
using TypeModule
function takes_a(a::A)
    println("Took A!")
end
export takes_a
end

function_caller.jl

include("a_function.jl")
include("types.jl")
using TypeModule, AFunctionModule
my_a = A()
takes_a(my_a)

Si vous exécutez Julia function_caller.jl, vous obtiendrez MethodError: no method matching takes_a(::TypeModule.A). En effet, le type A utilisé dans function_caller.jl est différent de celui utilisé dans a_function.jl. Dans ce cas simple, vous pouvez réellement "régler" le problème en inversant l'ordre des inclus dans function_caller.jl (ou simplement en supprimant include("types.jl") entièrement de function_caller.jl! Ce n'est pas bon!). Mais que faire si vous vouliez un autre fichier b_function.jl qui utilisait également un type défini dans TypeModule? Vous auriez à faire quelque chose de très hacky. Ou vous pouvez simplement modifier votre LOAD_PATH pour que le module ne soit défini qu'une seule fois.

EDIT en réponse à xji: Pour distribuer un module, utilisez Pkg ( docs ). J'ai compris que la prémisse de cette question était un module personnalisé et personnel.

Incidemment, si vous n’aimez vraiment pas l’idée de modifier votre chemin de chargement (même si cela n’appartient qu’à un script unique ...), vous pouvez créer un lien symbolique vers votre module dans un répertoire de paquetage (par exemple, ~/.Julia/v0.6/MyModule/MyModule.jl), puis Pkg.add(MyModule), puis importer comme d'habitude. Je trouve cela un peu plus difficile.

7
Graham Smith

À moins de charger explicitement le fichier (include("./Hello.jl")), Julia recherche les fichiers de module dans les répertoires définis dans la variable LOAD_PATH.

Voir cette page .

1
daycaster

Si vous souhaitez accéder à la fonction foo lors de l'importation du module avec "using", vous devez ajouter "export foo" dans l'en-tête du module. 

0
Accumulator