2011-02-27 10 views
5

No estoy seguro de cómo definí bien las funciones privadas. Cuando estoy escribiendo un paquete de Mathematica, acabo de hacer esto:Definir la función privada en un paquete matemático

BeginPackage["myPackage`"] 
myPublicFunction::usage="myPublicFunction blahblahblah"; 
Begin["Private"] 
myPrivateFunction[input_]:= ... ; 
myPublicFunction[input_]:= ... ; 
End[] 
EndPackage[] 

Es esta la forma correcta o me estoy perdiendo algo?

Respuesta

12

Sí, esa es una forma correcta. Puede ser útil comprender algunos de los mecanismos internos del paquete. Los contextos de Mathematica son similares a espacios de nombres en otros idiomas. Ellos pueden ser anidados. Cada símbolo pertenece a algún contexto. En cualquier momento dado, algún contexto es "actual". Cada vez que se crea un nuevo símbolo, el sistema debe decidir a qué contexto pertenecerá el símbolo. Esto sucede en el momento del análisis. La cantidad fundamental (variable) aquí es $ContextPath. Básicamente es la ruta de búsqueda de símbolos. Es una lista de contextos, y cada vez que el sistema ve un nuevo símbolo, prueba si el símbolo con el mismo nombre corto (es decir, el nombre del símbolo propiamente dicho, sin el contexto) existe en algún contexto en el $ContextPath. Si existe, entonces la ocurrencia dada del símbolo se asociará con la existente. Si no es así, entonces el símbolo se crea en un contexto actual. Tenga en cuenta que esto es algo dinámico: si cambia el $ContextPath en cualquier momento, la aparición del siguiente símbolo puede asociarse con un símbolo diferente.

De todas formas, lo que BeginPackage hace es que simplemente reemplaza el valor actual de $ ContextPath con sólo {youPublicPackageContext, "System'"}, además de contextos posiblemente adicionales que importe públicamente a través del segundo argumento opcional de BeginPackage. Por lo tanto, todos los símbolos que están en la sección "pública" se analizan en el contexto público, si no están en "Sistema" u otros contextos que usted importe. Y lo que EndPackage hace es restaurar el valor de $ContextPath a lo que era antes de que comenzara a cargar el paquete. Entonces, técnicamente el mensaje de uso no es la única forma de hacer público un símbolo en su contexto principal; simplemente podría simplemente escribir un símbolo con un punto y coma, como myFunction; (esta práctica es desaconsejable, solo lo mencioné para aclarar el mecanismo) Ahora, lo que sucede cuando ingresa Begin["'Private'"] es que el contexto actual se convierte en YourContext'Private' (un subcontenido). El $ContextPath no se cambia. Por lo tanto, cualquier símbolo ingresado allí, que no existe en su paquete público u otros paquetes importados (es decir, contextos actualmente en el $ContextPath), se analiza automáticamente en el subcontexto 'Private'.

Lo que realmente hace que estos símbolos sean privados es que cada vez que importa su paquete a otro contexto (paquete), solo se agrega el paquete principal al $ContextPath, pero no sus subpaquetes. Técnicamente, puede romper la encapsulación agregando manualmente YourPackage'Private' al $ ContextPath (por ejemplo, PrependTo[$ContextPath, YourPackage'Private']), y luego todas sus funciones privadas y otros símbolos se harán públicos en ese contexto particular en el que realiza la importación. De nuevo, esta práctica se desaconseja, pero explica la mecánica. La conclusión es que la noción de privado o público puede entenderse completamente cuando sabemos cómo se analizan los símbolos, y cuáles son las manipulaciones con $ContextPath y $Context (otra variable del sistema que da el valor del contexto actual), que se realizan mediante comandos como Begin y BeginPackage. Para decirlo de otra manera, uno podría, en principio, emular las acciones de BeginPackage, Begin, End y EndPackage con un código definido por el usuario. Hay unos pocos principios que operan aquí (que traté de delinear arriba), y el mecanismo en sí está de hecho muy expuesto al usuario, de modo que si, en algunos casos raros, uno puede querer algún otro comportamiento, uno puede hacer algunas manipulaciones "personalizadas" con $ContextPath y Context, para garantizar una forma no estándar de análisis de símbolos y, por lo tanto, controlar la encapsulación a escala de paquete de alguna manera "no estándar".No estoy alentando esto, solo menciono para enfatizar que el mecanismo es de hecho mucho más simple y mucho más controlable de lo que pueda parecer en la superficie.

+0

Gracias por la respuesta exhaustiva. Eso ayudó mucho. Hice esa pregunta porque traté de poner algunas declaraciones de funciones del público en la "sección" privada de mi código, y luego volver a cargar la declaración de importación del paquete en el cuaderno donde probé el paquete. Bueno, los nombres correspondientes a esas funciones se volvieron rojos, pero aún podía ejecutar esas funciones como si no se hubieran vuelto privadas. –

+0

También noté que mathematica (versión 7) a veces se equivoca con los paquetes importados actualmente. Por ejemplo, quería crear el mismo paquete exacto pero con impresiones de depuración en todo el código. Así que tomé el paquete original, cambié el nombre en la parte superior y lo guardé como un paquete diferente. Bueno, la matemática comenzó a quejarse de que tenía dos definiciones de las mismas funciones. ¿Por qué molestaría? –

+1

Me parece que no está borrando definiciones antiguas al modificar su código. Por ejemplo, si mueve los símbolos de "foo'" a "foo'private" y vuelve a cargar el paquete, cuando Mathematica analiza las definiciones en foo'private, detecta los conflictos con los símbolos ya definidos en foo' y le avisa. Entonces, probablemente quieras hacer algo como 'ClearAll [" foo \ '*"]; Quite ["foo \' * "]' cuando vuelva a cargar un paquete modificado foo. –

Cuestiones relacionadas