2010-08-30 44 views
22

Tengo un paquete mypack con los módulos mod_a y mod_b en él. Tengo la intención del propio paquete como mod_a a importar libremente:Python: módulo 'Privado' en un paquete

import mypack 
import mypack.mod_a 

Sin embargo, me gustaría mantener mod_b para el uso exclusivo de mypack. Eso es porque existe simplemente para organizar el código interno de este último.

Mi primera pregunta es, ¿es una práctica aceptada en la programación de Python tener módulos 'privados' como este?

En caso afirmativo, mi segunda pregunta es, ¿cuál es la mejor manera de transmitir esta intención al cliente? ¿Prefijo el nombre con un guión bajo (es decir, _mod_b)? ¿O sería una buena idea declarar un subpaquete private y colocar todos esos módulos allí?

Respuesta

13

La solución en la que me he decidido es crear un sub-paquete 'privado' y colocar todos los módulos que deseo ocultar allí. De esta forma permanecen guardados, dejando la lista de módulos mypack más limpia y fácil de analizar.

Para mí, esto tampoco parece antiponético.

+0

Llego a esta publicación casi 6 años después con las mismas preguntas y motivaciones que tuviste. ¿Sigue siendo el enfoque de subpaquete privado el que toma o ha intentado otros enfoques desde entonces? –

+2

Sí. Todavía estoy usando este método. No he encontrado una mejor alternativa. –

+3

Gracias por la actualización y por sugerir este enfoque en primer lugar. Prefijo el nombre del subpaquete "privado" con un 'z_', para que aparezca por último en los menús desplegables de finalización de código IDE. Utilizo las importaciones relativas en el '' __init__. Py' del subpaquete para exponer solo las funciones "públicas". En PyCharm y Jupyter, para mantener los nombres de los módulos internos fuera de los menús desplegables, cada módulo debe tener una función con el mismo nombre que el módulo, y debo importar la función en '__init __. Py'. Probablemente ya sepas todo esto, pero si no, aquí está. Si quieres que me expanda como respuesta solo házmelo saber. –

2

Python no conoce ni admite estrictamente métodos o clases "privadas" o "protegidas". Existe una convención de que los métodos con un solo guión bajo no son parte de una API oficial, pero yo no haría esto en clases o archivos, es feo.

Si alguien realmente necesita crear una subclase o acceder a mod_b, ¿por qué impedir que lo haga? Siempre puede suministrar una API preferida en su documentación y documento en su módulo, que no debe acceder directamente y usar mypack en lugar de eso.

+3

Podría dejar accesible 'mod_b' como' mod_a'. Sin embargo, imagine que hay 20 módulos similares a 'mod_b'. Entonces, cuando el cliente escribe 'mypack' en el editor, el intellisense listará los aproximadamente 25 módulos privados y públicos. Esto hará que mi código sea más difícil de explorar. Esa es la razón por la que quiero 'ocultar' aquellos módulos que no son para el cliente. En cuanto a la documentación, las personas generalmente prefieren explorar para leer la documentación. –

+0

Como dijo Matt Joiner, no importe 'mod_b' en su' __init __. Py'. Sugiero que también busques la variable especial '__all__'. Si ninguno de los dos hace el trabajo, el problema está en Intellisense. – ssokolow

+3

ssokolow, vea el tercer comentario bajo la respuesta de Matt. Incluso cuando 'mod_b' no se importa en' mypack/__ init __. Py', al escribir 'import mypack.mod_b' en el código del cliente aún funciona correctamente.Esto se debe a que Python no requiere la importación de módulos anidados en los niveles superiores para que funcionen las importaciones "punto" (como 'mypack.mod_b'). –

6

Si bien no hay palabras clave privadas explícitas, existe la convención de que las funciones privadas comiencen con un guión bajo único, pero un guión bajo doble lo hará para que otros no puedan llamar fácilmente la función desde fuera del módulo. Véase lo siguiente de PEP 8

- _single_leading_underscore: weak "internal use" indicator. E.g. "from M 
    import *" does not import objects whose name starts with an underscore. 

- single_trailing_underscore_: used by convention to avoid conflicts with 
    Python keyword, e.g. 

    Tkinter.Toplevel(master, class_='ClassName') 

- __double_leading_underscore: when naming a class attribute, invokes name 
    mangling (inside class FooBar, __boo becomes _FooBar__boo; see below). 

- __double_leading_and_trailing_underscore__: "magic" objects or 
    attributes that live in user-controlled namespaces. E.g. __init__, 
    __import__ or __file__. Never invent such names; only use them 
    as documented. 

Para hacer un módulo entero privada, no lo incluya __init__.py archivo.

+4

Aterrel, ¿qué quiere decir con "no incluir en' __init __. Py' "? ¿Quiere decir que no coloque la instrucción 'import mod_b' en' __init __. Py'? Si es así, eso aún no resuelve mi problema. El cliente todavía puede importar 'mod_b' al igual que un módulo público:' import mypack.mod_b'. ¿O quieres decir algo más? –

+1

Por lo tanto, no se hará cumplir estrictamente que el módulo sea privado, del mismo modo que un único guión bajo es débil. Pero no aparece sin importarlo explícitamente, que todavía es bastante privado. Me imagino que podría nombrar el archivo con dos guiones bajos principales, pero nunca he jugado con esto. – aterrel

+1

Gracias por la respuesta aterrel. La solución en la que me estoy quedando es crear un subpaquete 'privado' bajo' mypack' y colocar todos los módulos que quiero 'ocultar' en eso. Esto sirve para mi propósito de hacer que mi código sea más fácil de explorar (a través de intellisense, por ejemplo), guardando toda la pelusa no hecha. –

21

Prefijo módulos privados con un guión bajo para comunicar la intención al usuario. En su caso, esto sería mypack._mod_b

Esto tiene el mismo espíritu (pero no completamente análogo) a la recomendación PEP8 de nombrar los módulos de extensión C con un guión bajo cuando está envuelto por un módulo Python; es decir, _socket y socket.

Cuestiones relacionadas