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.