1335 votes

Python 3 importations relatives :

Je veux importer une fonction à partir d’un autre fichier dans le même répertoire.

Parfois, ça marche pour moi avec `` mais j’ai parfois un

Parfois, ça marche avec `` , mais parfois j’ai aussi une

J’ai vraiment, vraiment ne comprends pas la logique ici, et je ne pouvais pas trouver une explication. Cela semble complètement aléatoire.

Quelqu'un pourrait-il m’expliquer quelle est la logique derrière tout cela ?

1010voto

Aya Points 13144

malheureusement, ce module doit être à l'intérieur du paquet, et elle aussi doit être exécutable comme un script, parfois. Une idée de comment je pourrais réaliser cela?

Il est assez commun d'avoir une mise en page comme ça...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

...avec un mymodule.py comme ça...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

...un myothermodule.py comme ça...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

...et un main.py comme ça...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

...qui fonctionne très bien lorsque vous exécutez main.py ou mypackage/mymodule.py, mais échoue avec l' mypackage/myothermodule.py, en raison de la relative à l'importation...

from .mymodule import as_int

La façon dont vous êtes censé fonctionner, il est...

python3 -m mypackage.myothermodule

...mais c'est un peu verbeux, et ne se mélange pas avec une ligne shebang comme #!/usr/bin/env python3.

La solution la plus simple pour ce cas, en supposant que le nom de l' mymodule est unique au monde, serait d'éviter l'utilisation relative des importations, et il suffit d'utiliser...

from mymodule import as_int

...bien que, si elle n'est pas unique, ou votre package de la structure est plus complexe, vous aurez besoin d'inclure le répertoire contenant votre répertoire du package en PYTHONPATH, et le faire comme cela...

from mypackage.mymodule import as_int

...ou si vous voulez qu'il fonctionne "out of the box", vous pouvez frob l' PYTHONPATH dans le premier code, avec cette...

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

C'est une sorte de douleur, mais il y a une idée de pourquoi, dans un e-mail écrit par un certain Guido van Rossum...

Je suis -1 sur ce point et sur d'autres twiddlings de l' __main__ de la machinerie. Le seul cas d'utilisation semble être l'exécution de scripts qui arrive vivre à l'intérieur d'un répertoire du module, je l'ai toujours vu comme un antipattern. Pour me faire changer d'avis, vous auriez à me convaincre que il n'est pas.

Si l'exécution de scripts à l'intérieur d'un package est un antipattern ou pas, c'est subjectif, mais personnellement, je trouve ça vraiment utile dans un paquet que j'ai qui contient quelques personnalisé wxPython widgets, donc, je peux utiliser le script pour les fichiers source pour afficher un wx.Frame contenant uniquement à ce widget pour des fins de test.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X