2010-08-05 14 views
39

Estoy tratando de acceder a los datos de un módulo desde adentro de __main__.py.Uso de objetos propios del módulo en __main__.py

La estructura es la siguiente:

mymod/ 
    __init__.py 
    __main__.py 

Ahora, si expongo una variable en __init__.py así:

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

Cómo puedo acceder a foo de __main__.py?

+4

Up up up! He tenido problemas con esto muchas veces, es muy decepcionante ver que un comportamiento tan obvio no funciona de la manera que uno espera. –

Respuesta

22

Usted necesita tener ya sea el paquete ya en sys.path, añadir el directorio que contiene mymod a sys.path en __main__.py, o utilizar el interruptor -m.

Para añadir mymod a la ruta sería algo como esto (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 

Utilizando el interruptor -m le gustaría:

python -m mymod 

Ver this answer para más discusión.

+1

agregando 'sys.path.append (os.getcwd())' antes 'de mymod import foo' funcionó perfectamente, gracias – sharvey

+0

Creo que esto depende de que uno ejecute el paquete desde el directorio padre. En este caso, 'python mymod'. –

+8

'sys.path.append (os.path.dirname (__ file__))' agregará el directorio del archivo que se está ejecutando al sys.path – jdi

2

El módulo __init__ de a package actúa como miembros del propio envase, por lo que los objetos se importan directamente de mymod:

from mymod import foo 

O

from . import foo 

si le gustaría ser conciso, a continuación, leer aproximadamente relative imports. Debe asegurarse, como siempre, de que no invoque 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.

+0

Quería hacer el directorio del módulo ejecutable. – sharvey

+0

Sí, he probado estas sugerencias y no funcionaron para mí. –

+2

Cuando uso 'from. import foo', obtengo un 'ValueError: intento de importación relativa en non-package', y' ImportError: ningún módulo llamado mymod' en caso contrario. – sharvey

-2

estructura de directorios del módulo es el 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}) 

Ejecutar el módulo como una secuencia de comandos utilizando la bandera -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}} 
+2

Esta es tu respuesta? ¿Qué tal un poco de contexto o descripción para ir junto con lo que estás haciendo ? – jdi

+0

Este es un hack gigante y feo. ¿Copiando las variables a través de los locales? HAHAHA lo siento, pero esto fue realmente divertido. –

1

Si ejecuta el módulo con python -m mymod continuación código en __main__.py será capaz de importar del resto del módulo sin tener que agregar el módulo a sys.path.

4

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

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


El problema

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


La solución Una solución :)

Uso dos archivos de comandos para el módulo de __main__:

<package>/ 
     __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 <package> 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 son ideales en el caso que se están ejecutando desde __init__.py, tal y como los vuelve a cargar en el ámbito local de otro módulo, a pesar de tener cargarlos en __init__.py ya, pero la carga explícita debe evitar la carga circular. Si carga todo el módulo __init__ nuevamente en su main.py, no se cargará como __main__, por lo que debe ser seguro en lo que a la carga circular se refiere.

Cuestiones relacionadas