Usando objetos propios del módulo en __main__.py

Estoy tratando de acceder a los datos de un módulo desde su __main__.py .

La estructura es la siguiente:

 mymod/ __init__.py __main__.py 

Ahora, si __init__.py una variable en __init__.py como esta:

 __all__ = ['foo'] foo = {'bar': 'baz'} 

¿Cómo puedo acceder a foo desde __main__.py ?

sys.path tener el paquete ya en sys.path , agregar el directorio que contiene mymod a sys.path en __main__.py , o usar el __main__.py -m .

Para agregar mymod a la ruta se vería algo así (en __main__.py ):

 import sys import os path = os.path.dirname(sys.modules[__name__].__file__) path = os.path.join(path, '..') sys.path.insert(0, path) from myprog import function_you_referenced_from_init_file 

Usando el -m le gustaría:

 python -m mymod 

Vea esta respuesta para más discusión.

El problema con el que más me encuentro con este tipo de cosas es que a menudo quiero ejecutar el archivo __init__.py como una secuencia de comandos para probar las características, pero estas no deben ejecutarse al cargar el paquete. Hay una solución útil para las diferentes rutas de ejecución entre python /__init__.py y python -m .

  • $ python -m ejecuta /__main__.py . __init__.py no está cargado.
  • $ python /__init__.py simplemente ejecuta el script __init__.py como un script normal.

El problema

Cuando queremos que __init__.py tenga una cláusula if __name__ == '__main__': ... que usa cosas de __main__.py . No podemos importar __main__.py porque siempre importará __main__.pyc de la ruta del intérprete. ( A menos que … recurrimos a rutas de importación de rutas absolutas, que pueden causar muchos otros problemas).

La solución Una solución 🙂

Use dos archivos de script para el módulo __main__ :

 / __init__.py __main__.py main.py 

 # __init__.py # ... # some code, including module methods and __all__ definitions __all__ = ['foo', 'bar'] bar = {'key': 'value'} def foo(): return bar # ... if __name__ == '__main__': from main import main main.main() 

 # __main__.py # some code...such as: import sys if (len(sys.argv) > 1 and sys.argv[1].lower() == 'option1'): from main import main() main('option1') elif (len(sys.argv) > 1 and sys.argv[1].lower() == 'option2'): from main import main() main('option2') else: # do something else? print 'invalid option. please use "python -m  option1|option2"' 

 # main.py def main(opt = None): if opt == 'option1': from __init__ import foo print foo() elif opt == 'option2': from __init__ import bar print bar.keys() elif opt is None: print 'called from __init__' 

Las importaciones en main.py probablemente no sean ideales en el caso de que __init__.py desde __init__.py , ya que las estamos recargando en el ámbito local de otro módulo, a pesar de haberlas cargado en __init__.py ya, pero la carga explícita debe evitar Carga circular. Si vuelve a cargar todo el módulo __init__ en su main.py , no se cargará como __main__ , por lo que debe ser seguro en lo que respecta a la carga circular.

El módulo __init__ de un paquete actúa como miembros del mismo paquete, por lo que los objetos se importan directamente desde mymod :

 from mymod import foo 

O

 from . import foo 

Si te gusta ser conciso, lee sobre las importaciones relativas . mymod/__main__.py asegurarse, como siempre, de no invocar el módulo como mymod/__main__.py , por ejemplo, ya que eso evitará que Python detecte mymod como un paquete. Es posible que desee mirar en distutils .

Si ejecuta el módulo con python -m mymod , el código en __main__.py podrá importar del rest del módulo sin tener que agregar el módulo a sys.path .

La estructura del directorio del módulo es la siguiente:

 py/ __init__.py __main__.py 

__init__.py

 #!/usr/bin/python3 # # __init__.py # __all__ = ['foo'] foo = {'bar': 'baz'} info = { "package": __package__, "name": __name__, "locals": [x for x in locals().copy()] } print(info) 

__main__.py

 #!/usr/bin/python3 # # __main__.py # info = { "package": __package__, "name": __name__, "locals": [x for x in locals().copy()] } print(info) from . import info as pyinfo print({"pyinfo: ": pyinfo}) 

Ejecute el módulo como una secuencia de comandos utilizando el indicador -m

$ python -m py

 # the printout from the 'print(info)' command in __init__.py {'name': 'py', 'locals': ['__all__', '__builtins__', '__file__', '__package__', '__path__', '__name__', 'foo', '__doc__'], 'package': None} # the printout from the 'print(info)' command in __main__.py {'name': '__main__', 'locals': ['__builtins__', '__name__', '__file__', '__loader__', '__doc__', '__package__'], 'package': 'py'} # the printout from the 'print(pyinfo)' command in __main__.py {'pyinfo: ': {'name': 'py', 'locals': ['__all__', '__builtins__', '__file__', '__package__', '__path__', '__name__', 'foo', '__doc__'], 'package': None}}