programa otro modulos lista leer importar ejecutar desde como archivo python module package

otro - leer pdf en python



¿Cómo organizar múltiples archivos Python en un solo módulo sin que se comporte como un paquete? (4)

¿Hay alguna manera de usar __init__.py para organizar múltiples archivos en un módulo ?

Motivo: los módulos son más fáciles de usar que los paquetes, ya que no tienen tantas capas de espacio de nombres.

Normalmente hace un paquete, esto lo consigo. El problema es con un paquete, ''importar el paquete'' me da un espacio de nombres vacío. Luego, los usuarios deben usar "from thepackage import *" (mal visto) o saber exactamente lo que contiene y extraerlo manualmente en un espacio de nombres utilizable.

Lo que quiero es que el usuario ''importe el paquete'' y tenga espacios de nombres limpios y agradables que se vean así, exponiendo funciones y clases relevantes para el proyecto.

current_module / doit_tools/ / - (class) _hidden_resource_pool - (class) JobInfo - (class) CachedLookup - (class) ThreadedWorker - (Fn) util_a - (Fn) util_b - (Fn) gather_stuff - (Fn) analyze_stuff

El trabajo del mantenedor sería evitar definir el mismo nombre en diferentes archivos, lo que debería ser fácil cuando el proyecto es pequeño como el mío.

También sería bueno si las personas pueden hacer from doit_stuff import JobInfo y hacer que recupere la clase, en lugar de un módulo que contenga la clase.

Esto es fácil si todo mi código está en un archivo gigantesco, pero me gusta organizar cuando las cosas empiezan a hacerse grandes. Lo que tengo en el disco se ve así:

place_in_my_python_path/ doit_tools/ __init__.py JobInfo.py - class JobInfo: NetworkAccessors.py - class _hidden_resource_pool: - class CachedLookup: - class ThreadedWorker: utility_functions.py - def util_a() - def util_b() data_functions.py - def gather_stuff() - def analyze_stuff()

Solo los separé para que mis archivos no sean grandes ni navegables. Todos están relacionados, aunque alguien (posible yo) puede querer usar las clases por sí mismo sin importar todo.

He leído varias sugerencias en varios hilos, esto es lo que sucede con cada sugerencia que puedo encontrar sobre cómo hacer esto:

Si no uso un __init__.py , no puedo importar nada porque Python no desciende a la carpeta de sys.path.

Si uso un __init__.py blanco , cuando import doit_tools es un espacio de nombres vacío sin nada en él. Ninguno de mis archivos importados, lo que hace que sea más difícil de usar.

Si __all__ los submódulos en __all__ , puedo usar la sintaxis (¿mal visto?) from thing import * , pero todas mis clases están detrás de barreras de espacio de nombres innecesarias de nuevo. El usuario tiene que (1) saber que debe usar from x import * lugar de import x , (2) modificar manualmente las clases hasta que puedan obedecer razonablemente las restricciones de estilo de ancho de línea.

Si agrego from thatfile import X declaraciones from thatfile import X a __init__.py , me acerco pero tengo conflictos de espacio de nombres (?) Y espacios de nombres adicionales para cosas que no quería que estuvieran allí. En el siguiente ejemplo, verá que:

  1. La clase JobInfo sobrescribió el objeto del módulo denominado JobInfo porque sus nombres eran los mismos. De alguna manera Python puede resolver esto, porque JobInfo es del tipo <class ''doit_tools.JobInfo.JobInfo''> . (doit_tools.JobInfo es una clase, pero doit_tools.JobInfo.JobInfo es esa misma clase ... esto está enredado y parece muy malo, pero no parece romper nada).
  2. Cada nombre de archivo llegó al espacio de nombres doit_tools, lo que hace que sea más confuso mirar si alguien está mirando el contenido del módulo. Quiero que doit_tools.utility_functions.py mantenga algún código, no defina un nuevo espacio de nombres.

.

current_module / doit_tools/ / - (module) JobInfo / - (class) JobInfo - (class) JobInfo - (module) NetworkAccessors / - (class) CachedLookup - (class) ThreadedWorker - (class) CachedLookup - (class) ThreadedWorker - (module) utility_functions / - (Fn) util_a - (Fn) util_b - (Fn) util_a - (Fn) util_b - (module) data_functions / - (Fn) gather_stuff - (Fn) analyze_stuff - (Fn) gather_stuff - (Fn) analyze_stuff

Además, alguien que importa solo la clase de abstracción de datos obtendría algo diferente de lo que esperaban cuando lo hicieran ''desde doit_tools import JobInfo'':

current_namespace / JobInfo (module) / -JobInfo (class) instead of: current_namespace / - JobInfo (class)

Entonces, ¿es esta una forma incorrecta de organizar el código de Python? Si no es así, ¿cuál es la forma correcta de dividir el código relacionado pero aún así recopilarlo en forma de módulo?

¿Tal vez el mejor de los casos es que hacer ''from doit_tools import JobInfo'' es un poco confuso para alguien que usa el paquete?

¿Tal vez un archivo python llamado ''api'' para que las personas que usan el código hagan lo siguiente ?:

import doit_tools.api from doit_tools.api import JobInfo

=========================================

Ejemplos en respuesta a los comentarios:

Tome los siguientes contenidos del paquete, dentro de la carpeta ''foo'' que está en la ruta de Python.

foo/__init__.py

__all__ = [''doit'',''dataholder'',''getSomeStuff'',''hold_more_data'',''SpecialCase''] from another_class import doit from another_class import dataholder from descriptive_name import getSomeStuff from descriptive_name import hold_more_data from specialcase import SpecialCase

foo/specialcase.py

class SpecialCase: pass

foo/more.py

def getSomeStuff(): pass class hold_more_data(object): pass

foo/stuff.py

def doit(): print "I''m a function." class dataholder(object): pass

Hacer esto:

>>> import foo >>> for thing in dir(foo): print thing ... SpecialCase __builtins__ __doc__ __file__ __name__ __package__ __path__ another_class dataholder descriptive_name doit getSomeStuff hold_more_data specialcase

another_class y descriptive_name están another_class cosas, y también tienen copias adicionales de, por ejemplo, doit () debajo de sus espacios de nombres.

Si tengo una clase llamada Data dentro de un archivo llamado Data.py, cuando hago ''de Datos de importación de datos'' entonces aparece un conflicto de espacio de nombres porque Data es una clase en el espacio de nombres actual que está dentro de los datos del módulo, de alguna manera también está en el espacio de nombres actual. (Pero Python parece ser capaz de manejar esto).


Defina __all__ = [''names'', ''that'', ''are'', ''public''] en el __init__.py por ejemplo:

__all__ = [''foo''] from ._subpackage import foo

Ejemplo del mundo real: numpy/__init__.py .

Usted tiene una idea equivocada sobre cómo funcionan los paquetes de Python:

Si no uso un __init__.py , no puedo importar nada porque Python no desciende a la carpeta de sys.path.

Necesita el archivo __init__.py en versiones de Python anteriores a Python 3.3 para marcar un directorio que contiene un paquete de Python.

Si uso un __init__.py blanco, cuando importo doit_tools es un espacio de nombre vacío sin nada en él. Ninguno de mis archivos importados, lo que hace que sea más difícil de usar.

No impide la importación:

from doit_tools import your_module

Funciona como se esperaba.

Si __all__ los submódulos en __all__ , puedo usar la sintaxis (¿mal visto?) from thing import * , pero todas mis clases están detrás de barreras de espacio de nombres innecesarias de nuevo. El usuario debe (1) saber que debe usar from x import * lugar de import x , (2) modificar manualmente las clases hasta que puedan obedecer razonablemente las restricciones de estilo de ancho de línea.

(1) Sus usuarios (en la mayoría de los casos) no deberían usar from your_package import * fuera de un shell interactivo de Python.

(2) podría usar () para romper una línea larga de importación:

from package import (function1, Class1, Class2, ..snip many other names.., ClassN)

Si agrego from thatfile import X declaraciones from thatfile import X a __init__.py , me acerco pero tengo conflictos de espacio de nombres (?) Y espacios de nombres adicionales para cosas que no quería que estuvieran allí.

Depende de usted resolver los conflictos de espacio de nombres (diferentes objetos con el mismo nombre). El nombre puede referirse a cualquier objeto: entero, cadena, paquete, módulo, clase, funciones, etc. Python no puede saber qué objeto puede preferir e incluso si pudiera, sería incoherente ignorar algunos enlaces de nombre en este caso particular con respecto al uso de enlaces de nombre en todos los demás casos.

Para marcar nombres como no públicos, puede prefijarlos con _ eg, package/_nonpublic_module.py .


Existen razones perfectamente válidas para ocultar la subestructura de un paquete (no solo cuando se depura). Entre ellos se encuentran la conveniencia y la eficiencia . Al tratar de hacer un prototipo rápido con un paquete, es extremadamente molesto tener que interrumpir el hilo de pensamiento solo para buscar la información totalmente inútil sobre cuál es el submódulo exacto para una función o clase específica.

Cuando todo está disponible en el nivel superior de un paquete, The idiom:

python -c ''import pkg; help(pkg)''

muestra toda la ayuda , no solo algunos nombres de módulos miserables.

Siempre puede desactivar las importaciones de submódulos para el código de producción, o para limpiar los módulos del paquete después del desarrollo.

La siguiente es la mejor manera que he encontrado hasta ahora. Maximiza la conveniencia al intentar no suprimir los errores válidos. Ver también la fuente completa con la documentación más doctest .

Defina el nombre del paquete y los submódulos que se importan para evitar la duplicación propensa a errores:

_package_ = ''flat_export'' _modules_ = [''sub1'', ''sub2'', ''sub3'']

Use importaciones relativas cuando esté disponible (esto es imperativo, vea is_importing_package ):

_loaded = False if is_importing_package(_package_, locals()): for _module in _modules_: exec (''from .'' + _module + '' import *'') _loaded = True del(_module)

Intente importar el paquete, incluidos __all__ .
Esto ocurre cuando se ejecuta un archivo de módulo como script con el paquete en la ruta de búsqueda (por ejemplo, python flat_export/__init__.py )

if not _loaded: try: exec(''from '' + _package_ + '' import *'') exec(''from '' + _package_ + '' import __all__'') _loaded = True except (ImportError): pass

Como último recurso, intente importar los submódulos directamente.
Esto sucede cuando se ejecuta un archivo de módulo como secuencia de comandos dentro del directorio del paquete sin el paquete en la ruta de búsqueda (por ejemplo, cd flat_export; python __init__.py ).

if not _loaded: for _module in _modules_: exec(''from '' + _module + '' import *'') del(_module)

Construye __all__ (dejando fuera los módulos), a menos que se haya importado antes:

if not __all__: _module_type = type(__import__(''sys'')) for _sym, _val in sorted(locals().items()): if not _sym.startswith(''_'') and not isinstance(_val, _module_type) : __all__.append(_sym) del(_sym) del(_val) del(_module_type)

Aquí está la función is_importing_package :

def is_importing_package(_package_, locals_, dummy_name=None): """:returns: True, if relative package imports are working. :param _package_: the package name (unfortunately, __package__ does not work, since it is None, when loading ``:(``). :param locals_: module local variables for auto-removing function after use. :param dummy_name: dummy module name (default: ''dummy''). Tries to do a relative import from an empty module `.dummy`. This avoids any secondary errors, other than:: ValueError: Attempted relative import in non-package """ success = False if _package_: import sys dummy_name = dummy_name or ''dummy'' dummy_module = _package_ + ''.'' + dummy_name if not dummy_module in sys.modules: import imp sys.modules[dummy_module] = imp.new_module(dummy_module) try: exec(''from .'' + dummy_name + '' import *'') success = True except: pass if not ''sphinx.ext.autodoc'' in __import__(''sys'').modules: del(locals_[''is_importing_package'']) return success


Puede hacerlo, pero no es realmente una buena idea y está luchando contra la forma en que se supone que funcionan los módulos / paquetes de Python. Al importar los nombres apropiados en __init__.py puede hacerlos accesibles en el espacio de nombres del paquete. Al eliminar los nombres de los módulos, puede hacerlos inaccesibles. (Para saber por qué necesita eliminarlos, vea esta pregunta ). Para que pueda acercarse a lo que desea con algo como esto (en __init__.py ):

from another_class import doit from another_class import dataholder from descriptive_name import getSomeStuff from descriptive_name import hold_more_data del another_class, descriptive_name __all__ = [''doit'', ''dataholder'', ''getSomeStuff'', ''hold_more_data'']

Sin embargo, esto interrumpirá los intentos posteriores de import package.another_class . En general, no puede importar nada desde un package.module sin hacer que package.module accesible como una referencia importable a ese módulo (aunque con __all__ puede bloquear from package import module ).

De manera más general, dividiendo su código por clase / función, está trabajando contra el sistema de paquete / módulo de Python. Un módulo Python generalmente debe contener cosas que desea importar como una unidad. No es raro importar componentes de submódulo directamente en el espacio de nombres del paquete de nivel superior para mayor comodidad, pero a la inversa --- tratando de ocultar los submódulos y permitir el acceso a sus contenidos solo a través del espacio de nombres del paquete de nivel superior --- va a conducir a los problemas Además, no se gana nada tratando de "limpiar" el espacio de nombres de los paquetes de los módulos. Se supone que esos módulos están en el espacio de nombres del paquete; ahí es donde pertenecen.


Python no es java. El nombre del archivo del módulo no necesita ser el mismo que el nombre de la clase. De hecho, Python recomienda utilizar todas las minúsculas para el nombre del archivo del módulo.

Además, "de math import sqrt" solo agregará sqrt al espacio de nombres, no a las matemáticas.