Julia: módulo e importación de alias

Creado en 5 sept. 2012  ·  96Comentarios  ·  Fuente: JuliaLang/julia

Para el sistema de módulos, podemos importar y usar un módulo con notación de puntos:

import ArgParse
... 
    ArgParse.add_argument(p, "--opt1") 
...

Esto puede ser útil para evitar la contaminación del espacio de nombres. Sin embargo, debido a la verbosidad de los nombres de los módulos, sería bueno tener alias de módulo:

import ArgParse as ap 
... 
    ap.add_argument(p, "--opt1") 
...
design modules speculative

Comentario más útil

este problema ha estado allí durante mucho tiempo, aunque aún se deben discutir algunas extensiones, el

import LongPackage as longpkg

en sí parece bastante razonable.

Todos 96 comentarios

Me di cuenta hace unos minutos que puedes hacer lo siguiente:

import ArgParse
ap = ArgParse

ap.add_argument(...)

Sin embargo, sigo pensando que sería bueno tener la notación "importar como" como azúcar sintáctica.

Mientras estoy aquí y pensando en ello, también sería bueno tener una forma de importar múltiples funciones específicas en la misma línea de importación, como se menciona en la publicación del foro de @JeffreySarnoff . Una búsqueda a través de los problemas aún no reveló tal solicitud.

Algo como

# from the forum post
import Module.(export1,export2,export3)
# or
import Module.[export1,export2,export3]
# or maybe
import Module.{export1,export2,export3}

Es un tema diferente a este, pero relacionado. Debería

  1. actualizar este problema, o
  2. crear un nuevo problema

(Supongo que la utilidad de tal característica no es controvertida...)

Editar : Esto funciona ahora con import Module: export1, export2, export3

Creo que también debería ser compatible, por ejemplo.

import ArgParse.add_argument as addarg

para poder cambiar el nombre de los miembros del módulo al importar.

¿Se pregunta cómo los nombres de funciones renombrados participarían en el envío?

Tendría que funcionar básicamente como un alias, equivalente a const foo = Base.bar .

Tendría que funcionar básicamente como un alias, equivalente a const foo =
Base.bar.

Cuando importamos una función, planeamos usarla o anularla. Dado
lo anterior, con

importar Base.bar como foo

definitivamente podemos usar foo como Base.bar, pero definir foo también anularía
Base.bar? ¿Deberia?

Este es un problema antiguo, pero creo que es hora de revisarlo ya que nos acercamos a 0.2

Al escribir códigos, descubrí que siempre quise escribir import NumericExtensions as ne y terminé recordándome a mí mismo que esto no ha sido compatible.

Supongo que esto no es demasiado difícil de implementar y, en mi opinión, es mucho mejor que escribir

import NumericExtensions
const ne = NumericExtensions

+1

+1

¿Sigue siendo esto relevante? Personalmente, no me importa hacer los foo = Foo adicionales para el alias del módulo, pero parece que hubo cierto consenso para apoyar el alias del azúcar. Alguien que se siente lo suficientemente fuerte puede tener que hacer una PR por sí mismo.
Sin embargo, tenga en cuenta que x as y fue uno de los contendientes más fuertes para la sintaxis de convert(y,x) mencionada en #1470. Parece que no sería demasiado difícil eliminar la ambigüedad de los dos, pero solo notar.

El valor de esta función es que podría evitar importar el nombre original.

+1
Sería genial tener esta función.

+1

En lugar de introducir una nueva palabra clave as , ¿qué le parece usar el operador => , como en

import Tlahuixcalpantecuhtli => Venus: xxxxxxxxx => x9, yyyyyyyy => y8, zzz

Esto permitiría ortogonalmente aliasing del módulo y cualquier subconjunto de variables en la misma sintaxis.

No sé, eso me parece muy feo.

import Tlahuixcalpantecuhtli as Venus: xxxxxxxxx as x9, yyyyyyyy as y8, zzz

¿Es eso mejor? Lo encuentro mucho menos legible.

Personalmente, encuentro que as se explica más por sí mismo que => , lo que parece que podría significar muchas cosas.

revelación completa: sesgo de python.

Me gusta la sintaxis => mejor que as .

Me gustan los cobertizos para bicicletas que se atascan en los equilibrios de Nash.

¿Por qué volvería a vincular los símbolos internos de un módulo? Es feo porque realmente no deberías estar haciendo eso.

Me gusta la sintaxis de importación de Haskell . Siento que los espacios de nombres de Python son más granulares que los módulos de Julia. El módulo de Julia se siente más en espíritu que los módulos de Haskell, así que tal vez deberíamos buscar inspiración allí.

Estoy de acuerdo con @ssfrr , la palabra clave as es mucho más autoexplicativa y también es familiar para los usuarios de Python/Haskell. Para resolver el problema de @StefanKarpinski con la legibilidad, el enfoque similar a Python también ayudaría:

from Tlahuixcalpantecuhtli as Venus import xxxxxxxxx as x9, yyyyyyyy as y8, zzz

Siento que estoy hablando con el REPL. Pero sé que este tipo de sugerencia no es factible.

from Tlahuixcalpantecuhtli as Venus import xxxxxxxxx as x9, yyyyyyyy as y8, zzz

Esta es una de mis elecciones sintácticas menos favoritas en Python. Para cambiar ligeramente el significado, debe reorganizar radicalmente toda la línea, cambiando la palabra clave inicial y el orden de todo. Se ve completamente diferente de otras importaciones, oscureciendo el hecho de que hacen casi lo mismo. Este es un diseño sintáctico terrible, en mi opinión, dando demasiado peso a ser superficialmente similar al inglés.

:+1: por as , :-1: por from

import a => b: c => d, e => f me parece un poco demasiado perl.

Nunca escuché sobre los equilibrios de Nash y después de leer sobre ellos, no creo que esto constituya uno. Pero lo curioso es que, mientras que este cobertizo para bicicletas tiene 10 respuestas en una hora, una propuesta sobre el n.º 6984 que me parece muy importante (pero más difícil) ha pasado 4 horas sin comentarios.

En cuanto a as frente a => : cualquiera de los dos será una buena mejora con respecto a la situación actual.

Buen punto @BobPortmann en #6984.

Creo que => es genial para esto, FWIW.

Pero lo curioso es que, mientras que este cobertizo para bicicletas tiene 10 respuestas en una hora, una propuesta sobre el n.º 6984 que me parece muy importante (pero más difícil) ha pasado 4 horas sin comentarios.

En la analogía original de Parkinson, este número es el cobertizo para bicicletas y el #6984 es el reactor nuclear.

:)

Odio revolver esta olla, pero creo que prefiero as . => es un poco vago, y es raro que comparta la sintaxis con los diccionarios. Tal vez solo = tenga sentido: import Foo: x = y , en analogía con los const x = Foo.y que haría ahora.

Por lo menos, esa tabla en la documentación de Haskell es realmente útil. A menudo (especialmente cuando aprendí a julia por primera vez) me confundí sobre cuándo usar import / using / require , o cuándo hacer import Mod.thing vs import Mod: thing . De hecho, solo estaba buscando la explicación de la sintaxis de dos puntos en las importaciones y no pude encontrarla.

@jakebolewski parece que la sintaxis de Haskell es bastante parecida, con using de Julia equivalente a import de Haskell (no calificado), y import de Julia equivalente a import qualified de Haskell


Como punto de partida, ¿alguien que sepa mejor puede confirmar que este es un buen resumen de la sintaxis de importación/uso disponible actualmente? Digamos que tenemos un módulo Mod que exporta funciones x y y , y también tiene funciones no exportadas p y q .

import Mod trae Mod.x , Mod.y , Mod.p y Mod.q . Todas las funciones importadas están disponibles para la extensión del método.

using Mod trae x , y , Mod.x , Mod.y , Mod.p y Mod.q . x y y no están disponibles para la extensión del método, pero Mod.* sí.

import Mod.x, Mod.p trae x , p , Mod.x , Mod.y , Mod.p y Mod.q . Todos ellos están disponibles para la extensión del método.

import Mod: x, p es lo mismo que import Mod.x, Mod.p

using Mod.x, Mod.p trae x , p , Mod.x , Mod.y , Mod.p y Mod.q . x y p no están disponibles para la extensión del método, pero Mod.* sí.

using Mod: x, p es lo mismo que using Mod.x, Mod.p

Por lo que puedo decir using Mod es el único uso que se preocupa por lo que exporta Mod .

¡Sería realmente útil tener este resumen en los documentos de Module! ¿Alguien puede confirmar esto, para que pueda preparar un PR?

Parece que la versión menos polémica es:

import Tlahuixcalpantecuhtli as Venus: xxxxxxxxx as x9, yyyyyyyy as y8, zzz

Estoy bien con eso. Sin embargo, la versión de asignación es interesante, probándola:

import Venus = Tlahuixcalpantecuhtli: x9 = xxxxxxxxx, y8 = yyyyyyyy, zzz

Pensé que iba a odiar eso, pero en realidad es bastante agradable. Me gusta que los nombres que se presentan en este módulo sean los primeros y los más destacados; en muchos sentidos, eso es lo más importante.

@jakebolewski : ¿Por qué volvería a vincular los símbolos internos de un módulo? Es feo porque realmente no deberías estar haciendo eso.

Es posible que desee importar enlaces con nombres en conflicto de dos módulos diferentes y esto lo permite. También podría calificarlos por completo, pero si admitimos la creación de alias, también podríamos admitir esto.

Algunas líneas nuevas bien ubicadas hacen que sea más legible, en mi opinión:

import Tlahuixcalpantecuhtli as Venus:
    xxxxxxxxx as x9, 
    yyyyyyyy as y8,
    zzz

o

import Venus = Tlahuixcalpantecuhtli: 
    x9 = xxxxxxxxx, 
    y8 = yyyyyyyy, 
    zzz

Me doy cuenta de que prefiero la versión de asignación con bastante fuerza. Después de todo, la importación es una forma de cesión.

¡Sería realmente útil tener este resumen en los documentos de Module! ¿Alguien puede confirmar esto, para que pueda preparar un PR?

@brk00 , ¡adelante!

@kmsquire , ¡trabajaré en eso hoy!

Pero antes de hacer eso, quiero asegurarme de que lo entiendo bien. En el ejemplo de @ssfrr , supongamos que estoy en REPL y escribo using Mod . Las funciones importadas x y y no están disponibles para la extensión del método. Significa que, si declaro otras funciones x e y, ya no tendré acceso a los métodos Mod que una vez importé, ¿solo a los nuevos?

Esto es lo que sucede si intenta extender una función sin importarla:

julia> module Mod

       export x, y

       x() = "x"
       y() = "y"
       p() = "p"
       q() = "q"

       end

julia> using Mod

julia> x()
"x"

julia> p()
ERROR: p not defined

julia> x(n) = n
ERROR: error in method definition: function Mod.x must be explicitly imported to be extended

Puedes agregar un método así:

julia> import Mod: x # or import Mod.x

julia> x(n) = n
x (generic function with 2 methods)

julia> methods(x)
# 2 methods for generic function "x":
x() at none:5
x(n) at none:1

Bueno, estaba confundido por el comportamiento de resolución de nombres:

julia> module Mod

       export x, y

       x() = "x"
       y() = "y"
       p() = "p"
       q() = "q"

       end

julia> using Mod

julia> x(n) = n
x (generic function with 1 method)

Si asigno una nueva función a x antes de _usar_ la que acabo de importar con using Mod , el error no aparece. Pero si, por ejemplo, llamo a x() antes de la nueva asignación (como lo hizo en su ejemplo), el error se genera de hecho.

¡Ay, interesante! Yo no sabía acerca de eso. Acabo de llamar a x para demostrar el espacio de nombres después de using .

Tal vez uno de los desarrolladores principales pueda arrojar algo de luz. ¿Qué sucede cuando se llama a x que desencadena el error al intentar sobrecargar?

Encuentro el alias sugerido por @carlobaldassi arriba muy útil en la práctica.

Me pregunto si import podría simplemente devolver el objeto del módulo, de modo que pudiera tener un alias directamente con una asignación, con o sin const . P.ej

const Shortname = import ModuleWithLongName

en lugar de

import ModuleWithLongName
const Shortname = ModuleWithLongName

Esto no requeriría una sintaxis nueva, solo una combinación de elementos de sintaxis existentes. Me doy cuenta de que actualmente import es una "declaración", llamada únicamente por efectos secundarios, y no tiene valor. Si el analizador no permite esto, preferiría import("Module") o algo similar.

Creo que la opción de alias de los módulos podría ser buena, pero también creo que hay un inconveniente que nadie ha mencionado: podría oscurecer significativamente el código. Desde la perspectiva de un lector de código, es bueno tener solo un nombre descriptivo para un módulo.

¿Bastante trivial para mirar hacia arriba? Es probable que las formas abreviadas también se estandaricen para paquetes populares como np por numpy .

Todavía prefiero numpy a np estandarizados e incluso Arrays a numpy . numpy suena como un cruce entre un movimiento de baile de 1950 y una plaga mortal.

fácilmente puede simplemente escribir:

Base.require("ArgParse")
const ap = Main.ArgParse

esto no necesita una sintaxis para 1.0

Siento que deberíamos tener una sintaxis para esto. Sí, podemos vivir sin él, ya que puedes hacer require y una asignación const , pero usar require es bastante feo y la falta de una sintaxis conveniente desalienta a las personas a cambiar el nombre de las cosas. como quieren/necesitan.

El truco const que es fácil se queda corto cuando uno necesita alias de una macro, esta es la forma en que lo hago, y me tomó un tiempo darme cuenta:

julia> macro foo(a, b, c)                                  
           a, b, c                                         
       end                                                 
<strong i="8">@foo</strong> (macro with 1 method)                                 

julia> macro f(args...)                                    
           Expr(:macrocall, Symbol("@foo"), args...) |> esc
       end                                                 
<strong i="9">@f</strong> (macro with 1 method)                                   

julia> <strong i="10">@f</strong> 1 2 3                                            
(1,2,3)                                                    

En ImportMacros.jl estoy implementando:

  • <strong i="15">@from</strong> Foo.Bar use foo as f
  • <strong i="18">@from</strong> Foo.Bar use <strong i="19">@foo</strong> as @f

Consulte: https://github.com/fredrikekre/ImportMacros.jl/pull/3

@Ismael-VC

Tratar

<strong i="7">@eval</strong> const $(Symbol("@foo")) = $(Symbol("@bar"))

que es más feo, pero más corto y quizás más claro que definir una macro localmente

@TotalVerb ¡ gracias de nuevo por tu ayuda!

Parece que la única funcionalidad que falta en Julia + ImportMacros es crear un alias tanto para el módulo como una combinación de crear un alias para un número variable de objetos de dicho módulo e importar otros sin alias:

  • <strong i="9">@from</strong> Foo.Bar as B use foo as f, <strong i="10">@bar</strong> as <strong i="11">@b</strong>, baz

O sin el from :

  • import Foo.Bar as B: foo as f, <strong i="17">@bar</strong> as <strong i="18">@b</strong>, baz
  • import B = Foo.Bar: f = foo, <strong i="21">@b</strong> = <strong i="22">@bar</strong>, baz

El último parece no ser posible con macros:

julia> parse("<strong i="26">@from</strong> Foo.Bar as B use foo as f, <strong i="27">@bar</strong> as <strong i="28">@b</strong>, baz")
:(<strong i="29">@from</strong> Foo.Bar as B use foo as (f,@bar(as,(@b(),baz))))

julia> parse("<strong i="30">@import</strong> Foo.Bar as B: foo as f, <strong i="31">@bar</strong> as <strong i="32">@b</strong>, baz")
:(<strong i="33">@import</strong> Foo.Bar as B:foo as (f,@bar(as,(@b(),baz))))

julia> parse("<strong i="34">@import</strong> B = Foo.Bar: f = foo, <strong i="35">@b</strong> = <strong i="36">@bar</strong>, baz")
ERROR: ParseError("unexpected \"=\"")
 in #parse#310(::Bool, ::Bool, ::Function, ::String, ::Int64) at .\parse.jl:184
 in (::Base.#kw##parse)(::Array{Any,1}, ::Base.#parse, ::String, ::Int64) at .\<missing>:0
 in #parse#311(::Bool, ::Function, ::String) at .\parse.jl:194
 in parse(::String) at .\parse.jl:194

En realidad, esto no necesita decidirse para 1.0, ya que todas las sintaxis propuestas son errores o tonterías totales.

¿Qué debería pasar con un alias de módulo cuando se redefine el módulo original, por ejemplo, con reload("...") en REPL? Con el enfoque const M = MyModule , M todavía hace referencia al módulo anterior después de recargar, por lo que cualquier nombre recién definido en MyModule solo será accesible para MyModule.name pero no M.name .

En ese caso, una sintaxis de alias debería ser más que azúcar sintáctica para un const M = Module , pero asegúrese de que M siempre se refiera a lo mismo que MyModule .

Esto también simplificaría el flujo de trabajo de REPL ya que puedo continuar import un módulo durante el desarrollo pero puedo referirme a él a través de un alias más corto sin tener que restablecer un alias (no const ) cada vez que reload .

A partir de ahora, reload se elimina, por lo que esta preocupación ya no se aplica.

Esto también se aplica a include , ¿o me estoy perdiendo algo? En general, cuando se redefine un módulo, el nombre del módulo import ed se refiere a la nueva definición, mientras que un alias definido por asignación se refiere a la definición anterior, ¿verdad?

No, eso no debería ser una preocupación. El nombre importado NUNCA se cambiará cuando se redefina un módulo, incluido el import normal. Lo que ha cambiado es el módulo que se importará si lo vuelve a importar. Lo importado siempre ha sido sólo una unión.

Ok, tal vez no me expresé claramente, así que aquí hay un ejemplo: Si creas un archivo test.jl con el contenido

module Tst
f() = 1
end

puede cargarlo, importar Tst , definir un alias para Tst , y todo está bien:

julia> include("test.jl")
Tst

julia> import Tst

julia> const Tst2 = Tst
Tst

julia> Tst.f()
1

julia> Tst2.f()
1

Si ahora cambia test.jl a

module Tst
f() = 2
end

y re- include en el REPL, el módulo y su alias se comportan de manera diferente:

julia> include("test.jl")
WARNING: replacing module Tst
Tst

julia> Tst.f()
2

julia> Tst2.f()
1

Veo por qué este es el caso, pero creo que esto no debería suceder cuando crea un alias con algo como import Tst as Tst2 .

Probé esto en 0.6.2, y por el momento no puedo probarlo en 0.7, así que no sé si este sigue siendo el caso.

No lo estás importando en absoluto. El módulo que incluye ya está definido en su alcance. El import no funciona.

Cierto, pero ese no es el punto. El punto es lo que sucede cuando hago algo como el import Tst as Tst2 hipotético. Entonces esta declaración no es un no-op sino que crea un alias.

Si este alias funciona como const Tst2 = Tst , al redefinir el módulo Tst el alias apuntará a la versión anterior del módulo. Esto no es deseable en ningún caso. El alias también debe apuntar a la nueva versión de Tst , o el usuario debe verse obligado a restablecer el alias. Pero en el último caso, usar el alias anterior sin restablecerlo debería arrojar un error en lugar de apuntar al módulo anterior.

Ese es completamente el punto. Este problema se trata de agregar una función a import no a la definición del módulo. Su import no funciona y, después de eliminarlo, su código ya no tiene import o using , por lo que no está relacionado con este problema. Cámbielo para que el módulo no esté definido en el mismo ámbito que import .

import Tst as Tst2 funcionará igual que import Tst en términos de lo que vincula a ese nombre, que siempre es vinculante y no algo mágico que desee. NO se trata de agregar un alias al definir el módulo.

Dicho de otra manera, tu código es básicamente,

a = Ref(1) # include
a = a # import
b = a # alias
a = Ref(2) # include again

Y no tiene ningún sentido quejarse del comportamiento del b = a ya que el a no está vinculado en absoluto por el a = a . Todo lo que ve es el efecto secundario de definir el módulo en el mismo ámbito que la importación (es decir a = a y a = Ref(...) en el mismo ámbito) en un mal ejemplo.

Ok, solo quería señalar que en algunas situaciones, un alias definido por una asignación no funcionaría como se esperaba. Tal vez elegí un mal ejemplo. Pensé que podría ser importante para una sintaxis que crea un alias de módulo (ya sea relacionado o no con import ), pero en este momento esto es hipotético de todos modos. Lo siento por el ruido.

este problema ha estado allí durante mucho tiempo, aunque aún se deben discutir algunas extensiones, el

import LongPackage as longpkg

en sí parece bastante razonable.

Protuberancia. Me pregunto cuál es la mejor solución, por ahora, ¿parece? Esto es lo que estoy haciendo:

import LinearAlgebra
const linalg = LinearAlgebra

¡Corrígeme si hay una solución mejor!

Ese es el estándar actual.

¿Qué pasa con una sintaxis ~? No sé las ramificaciones, pero tiene una estética agradable. Además, ~ se usa como símbolo de aproximado.

import LongPackage ~ lp

@JeffreySarnoff citando a Stefan

@stefankarpinski

Esta es una de mis elecciones sintácticas menos favoritas en Python. Para cambiar ligeramente el significado, debe reorganizar radicalmente toda la línea, cambiando la palabra clave inicial y el orden de todo. Se ve completamente diferente de otras importaciones, oscureciendo el hecho de que hacen casi lo mismo. Este es un diseño sintáctico terrible, en mi opinión, dando demasiado peso a ser superficialmente similar al inglés.

En este caso, ~ no tendría nada que ver con el aspecto inglés de la sintaxis de Python. Creo que cuando veo ~, solo reconozco el concepto matemático de aproximado. 10.001 ~ 10.

Entonces, en ese sentido, encuentro ~ bastante agradable en realidad.

import LongPackage ~ lp
import HugePackage ~ hp
import MassivePackage ~ mp
import GiantPackage ~ gp

:-)

ok, olvídate de python, estoy eliminando ese comentario a favor de

lp imports LongPlayingRecords
hp imports HewlettPackard
mp imports MilitaryPolice
gp imports PariForNumberTheory

Originalmente no me gustó, pero parece que muchas personas naturalmente quieren escribir esto con as Debo decir que parece perverso hacer cualquier otra cosa. No tiene que reservarse como una palabra clave ni nada, ya que este es un contexto sintáctico claro.

¡¿Un lenguaje de programación que _intenta_ que la gente sepa lo que significa?!

@JeffreySarnoff

¡¡¡Un lenguaje de programación que intenta ser mejor que Python!!!

@neilpanchal Julia es definitivamente un lenguaje que intenta ser mejor que Python en muchos sentidos. Por otro lado, obviamente no se esfuerza por ser _diferente_ a Python, donde Python hizo algo bien. Julia toma prestadas las convenciones sintácticas de Python de izquierda a derecha.

Adopte el python as . Lo hicieron bien.

julia> importar LightGraphs como lg
ERROR: sintaxis: token adicional "como" después del final de la expresión

Solo otro comentario de $0.02 a favor de as que se aleja de Python. Fwiw, ahora que estoy usando a Julia con cierta regularidad nuevamente extraño esto. No como en Python, sino como en Clojure (ver ejemplo ), donde los espacios de nombres del ámbito del paquete (que son buenos para la desambiguación) se pueden simplificar para hacer que el uso explícito de las bibliotecas sea mucho más manejable. Dado que prefiero evitar using (es decir, importaciones de comodines) tener algo de azúcar sintáctico en import Gadlfy as gf sin la adición de la línea const gf = (lo que hago actualmente) sería ser útil

Otro comentario más apoyando la sintaxis as :heart: Lo deseo mucho para futuros lanzamientos de Julia.

Yo también deseo que esto suceda. Sobre todo porque no es un cambio radical (¿verdad?).

Creo que esto se implementará en algún momento (lo intentaría yo mismo si tuviera tiempo), pero mientras tanto, el paquete ImportMacros tiene casi toda la funcionalidad solicitada aquí (aunque falta documentación) :

<strong i="8">@import</strong> ModuleA as ma
<strong i="9">@using</strong> ModuleB as mb
<strong i="10">@from</strong> ModuleC use long_function_name as func
<strong i="11">@from</strong> Module use <strong i="12">@macroname</strong> as <strong i="13">@alias</strong>

No sabía sobre ImportMacros .jl, gracias por señalarlo. Si esta funcionalidad existe en un paquete, supongo que no es tan importante tenerla en el idioma base.

Sigo pensando que sería bueno tener esto en el idioma.

Las importaciones son, en mi opinión, exactamente el tipo de cosas para las que casi _siempre_ desea ceder a las convenciones del idioma base y no incluir macros o agregar una dependencia de paquete. import ... const es mejor como alternativa, incluso (especialmente) si el idioma base nunca se amplía para hacer que el proceso de dos pasos sea más conciso.

En particular, es un poco feo de ver

using ImportMacros
<strong i="6">@using</strong> OtherPackage as ...
<strong i="7">@using</strong> ThirdPackage as ...

porque el no macro using sobresale.

¿Qué tal import devolviendo el módulo/función/lo que realmente trae al alcance?
Entonces puedes escribir
lg = import LightGraphs
baz = import foo.bar
baz, kit, kat = import foo : bar1, bar2, bar3
Lo único que debe cambiarse es la función de importación.

Realmente me gusta la solución de @DhruvaSambrani porque encaja con el enfoque general de "todo es una expresión" de Julia.

Lo único es que, para ser consistente, la expresión de importación aún tendría que presentar el efecto secundario de incluir el nombre completo en el alcance (tal vez no sea un desastre). También podría estar en mayúsculas y minúsculas para no importar el nombre completo, pero las mayúsculas y minúsculas son asquerosas.

En OCaml (¡el lenguaje con los mejores módulos!), puedes hacer algo como:

module LG = LightGraphs

La diferencia importante aquí es que el nombre calificado de cada módulo que se compila con el programa OCaml está automáticamente dentro del alcance.

Por supuesto, usar import LightGraphs as LG tiene la ventaja de que "todo el mundo" ya lo conoce de Python, pero mi gusto personal es que es mejor reutilizar la sintaxis de asignación para algo que literalmente es asignación.

O un cambio más extenso sería introducir un "espacio de nombres" como Tipo (no sé si ya está hecho). Entonces import puede expandir el módulo/lo que sea en un espacio de nombres y devolver el espacio de nombres. Pero esto romperá todo el código de Julia porque simplemente hacer import mod_name no hará que el espacio de nombres mod_name esté disponible en el ámbito global. Si de alguna manera uno puede hacer que el espacio de nombres mod_name esté disponible para global cuando se usa la importación sin una asignación que lo preceda, entonces eso no es un problema.

O simplemente agregue una nueva función import_as_ns(mod_name) :: Namespace que será una función pura que devuelve todas las funciones/módulos, etc. en un solo espacio de nombres.

encaja con el enfoque general de "todo es una expresión" de Julia

Sin embargo, import y using son especiales porque se usan solo por sus efectos secundarios y solo en el nivel superior.

Por cierto, dado que este problema ha estado abierto durante mucho tiempo, me pregunto si Triage estaría dispuesto a revisarlo y tomar una decisión. Yo recomendaría el cierre, ya que

  1. import Foo; const Bar = Foo proporciona una solución perfecta cuando al usuario no le importa Foo en el espacio de nombres,
  2. ImportMacros.jl debería encargarse del resto,
  3. ninguno parece usarse con mucha frecuencia en el código práctico para garantizar una sintaxis especial.

Diré que después de todo este tiempo, todavía extraño esto (y también uso ImportMacros en mi propio código).

Creo que el estilo de café que estás escribiendo afecta la necesidad (o el deseo) de esto. Cuando estoy escribiendo ML o código científico, encuentro que no lo extraño mucho. Cuando he escrito otro código que usa una cantidad de paquetes con nombres largos, es cuando encuentro que uso más ImportMacros.

ImportMacros es suficiente. Solo estoy de acuerdo con los comentarios de que no se ve tan limpio.

También espero con ansias el día en que pueda usar un formateador automático en mi editor para ordenar mis importaciones... pero es menos probable que sepa qué hacer con @using ...

También estoy de acuerdo con @kmsquire en que este no es un problema tan grande y que ImportMacros debería ser suficiente. Pero cualquier método debe documentarse para que no vuelva a aparecer.

Aunque todavía me gustaría el azúcar m=import Module 😅

No pretendía que mi mensaje implicara que esto no es gran cosa.

Todavía preferiría una sintaxis para esto.

ImportMacros es suficiente. Solo estoy de acuerdo con los comentarios de que no se ve tan limpio.

Estoy de acuerdo. También por:

using ImportMacros
<strong i="8">@using</strong> OtherPackage as ...

Cuando se presenta el lenguaje a los recién llegados oa los principiantes en programación, resulta un poco molesto explicar por qué un script dado comienza con esta inconsistencia, ya que complica el flujo y cambia el enfoque de la enseñanza.

ninguno parece usarse con mucha frecuencia en el código práctico para garantizar una sintaxis especial

La razón por la que las personas no usan mucho ImportMacros en el código real podría deberse a una compensación. Por ejemplo, usaría import ... as ... casi todas las veces, pero probablemente no a costa de tener que importar primero otro paquete para hacerlo. Más que una dependencia adicional, también tiene un impacto en términos de "sensación" (y a algunas personas les gusta que su código se vea elegante (especialmente en python o Julia) 🤷‍♂️, y esto using/@using da un " hacky" a la introducción de un guión).

Entonces sí, "ImportMacros es suficiente". Para las personas que realmente quieren usarlo. Pero esa es la cuestión, no es un tema vital, y la gente puede trabajar sin él. No obstante, creo firmemente que normalmente son estas pequeñas cosas las que hacen que la sintaxis de un idioma se mantenga, por lo tanto, este hilo monstruoso agrega su soporte a la base.

Creo que import ... as ... es azúcar sintáctico que definitivamente valdría la pena, es realmente fácil de entender y explicar, y especialmente útil en lenguajes como Julia en el que los paquetes tienden a tener nombres bastante largos (obviamente, esto importa solo bajo el supuesto de que la gente no quiere hacer using ... ).

Y el hecho de que Python lo haya implementado primero no debería ser relevante; Julia debe esforzarse por tener la mejor sintaxis antes de intentar distanciarse de otros lenguajes y/o enfatizar su propia identidad.

Tener sintaxis para esto y convenciones en torno a módulos populares (estoy pensando en cómo siempre es import numpy as np y import matplotlib.pyplot as plt ) también daría una alternativa concisa a hacer using SuchAndSuch y confiar en export ed nombres (que es algo que generalmente evito en el código de "biblioteca").

@DominiqueMakowski :

presentar el lenguaje a los recién llegados o principiantes en programación para explicar por qué un script dado comienza con esta inconsistencia

No entiendo por qué piensa que es una inconsistencia, es simplemente la gestión del espacio de nombres, que es una parte normal de la programación en general.

Además, cambiar el nombre de los módulos puede no ser algo que los recién llegados a Julia encuentren primero.

No digo que no haya un caso de uso, pero puede ser demasiado raro para justificar su propia palabra clave. Por el momento, buscar using ImportMacros da <10 resultados únicos en Github.

Estaría usando importar ... como ... casi siempre, pero probablemente no a costa de tener que importar primero otro paquete para hacerlo

Esto funciona en ambos sentidos: si el costo (muy pequeño) de usar un paquete liviano como ImportMacros o un símbolo adicional ( import LongFoo; const Foo = LongFoo ) no vale el beneficio, entonces el beneficio puede no ser tan grande .

Julia debe esforzarse por tener la mejor sintaxis antes de intentar distanciarse de otros lenguajes y/o enfatizar su propia identidad.

No estoy seguro de por qué crees que esto es una motivación en esta discusión.

Hay algunos casos en los que podría querer usar as donde la asignación const no funciona del todo:

julia> using Distributed

julia> import Future; const future = Future
Future

julia> Future === Distributed.Future # oops, this is what we wanted
false

julia> Future === future # not what we wanted `Future` to mean
true

Sí, puedes solucionar esto, pero es incómodo. Dado que a menudo es útil, a veces es necesario y que import FooBar as FB es la sintaxis "menos sorprendente" generalmente acordada, eso parece ser lo que deberíamos elegir. Todo esto necesita que alguien haga un PR implementándolo.

Nueva usuaria de Julia aquí.
Vengo de un fondo mayormente R, usando Python también. Tengo malas experiencias con el espacio de nombres comunes del paquete al que conducen los mecanismos de carga como using . El riesgo de colisión es uno, pero solo desde la perspectiva de la legibilidad, hay una carga mental de pensar constantemente en el módulo de cada método.

No sé cuán complejo es agregar esta sintaxis. ¿Es factible para un novato?

Probablemente no sea muy fácil. Implicará piratear el código del analizador que está escrito en Scheme y conectar el cambio a través del AST, lo que podría tocar también algún código C.

Sería una buena característica para evitar conflictos de nombres de funciones en varios módulos.

A partir de una discusión sobre holgura, agrego algunas ideas

Me pregunto si esto hará que las personas sean menos cuidadosas al elegir los nombres de las funciones y al agregar métodos correctamente a las funciones correctas. El hecho de que, por ejemplo,

numpy.sin
sympy.sin

son funciones diferentes es una forma segura de tener que implementar dos versiones de su función si desea que funcione tanto para entradas numéricas como simbólicas. Si dicho espacio de nombres también se generaliza en julia debido a la conveniencia, ¿podríamos perdernos una gran cantidad de reutilización de código? Es decir, me temo que esto podría darnos menos de " Esto anima a las personas a trabajar juntas ", como lo expresó Lyndon en https://www.oxinabox.net/2020/02/09/whycompositionaljulia.html

@baggepinnen No creo que esto cambie nada en ese sentido.

En Julia, los métodos implementados en diferentes módulos no se fusionan importando ambos métodos en el mismo espacio de nombres.

julia> module Foo
           export sin
           sin(s::String) = uppercase(s)
       end
Main.Foo

julia> sin(1)
0.8414709848078965

julia> using .Foo
WARNING: using Foo.sin in module Main conflicts with an existing identifier.

julia> sin("wat")
ERROR: MethodError: no method matching sin(::String)
Closest candidates are:
  sin(::BigFloat) at mpfr.jl:727
  sin(::Missing) at math.jl:1197
  sin(::Complex{Float16}) at math.jl:1145
  ...
Stacktrace:
 [1] top-level scope at REPL[4]:1
 [2] run_repl(::REPL.AbstractREPL, ::Any) at /build/julia/src/julia-1.5.1/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

julia> Foo.sin("wat")
"WAT"

Uno tiene que agregar explícitamente un envío a la función original para que esto funcione:

julia> Base.sin(s::String) = Foo.sin(s)

julia> sin("wat")
"WAT"

Por lo que puedo decir, no hay forma posible de que el alias del módulo cambie la forma en que se envían las funciones.

Y honestamente, algunas funciones con el mismo nombre _deberían_ vivir en espacios de nombres separados. Una función find_delta en una biblioteca numérica va a hacer algo no relacionado con find_delta en una biblioteca de diferencias de archivos. Una vez que su código es tan polimórfico que encontrará una manera de ejecutarse en una entrada rota, está ingresando al territorio de JavaScript, y nadie quiere eso.

@ninjaaron Es posible que no haya podido transmitir algunos matices en mi preocupación anterior. No me preocupa que este cambio cambie nada más que la estrategia que las personas eligen tomar cuando implementan bibliotecas.
La persona que implementa Foo encuentra una advertencia como

julia> using .Foo
WARNING: using Foo.sin in module Main conflicts with an existing identifier.

puede optar por simplemente import .Foo.sin as sin2 , o pensar si realmente desea o no proporcionar un nuevo despacho por Base.sin . Mi punto era que si se vuelve muy fácil simplemente considerarlas funciones diferentes, tal vez esto se generalice demasiado, incluso en situaciones en las que realmente deberían ser métodos diferentes de la misma función. La situación actual, en la que es un poco más incómodo tratar con diferentes funciones con el mismo nombre, tiene el agradable efecto secundario de que las personas hablan entre sí y hacen todo lo posible para averiguar si realmente es la misma función o no. No estoy argumentando en contra de la posibilidad de tener diferentes funciones con el mismo nombre, lo que por supuesto puede ser muy útil. Ni siquiera estoy seguro de si mi inquietud es importante o no, pero pensé que valía la pena levantarla para asegurarme de que se haya considerado.

@baggepinnen Eso tiene sentido, y no hay nada de malo en mencionarlo. No creo que esto marque una gran diferencia para las personas que crean bibliotecas, ya que el alias del módulo solo afectará a los usuarios de la biblioteca. Supongo que es posible que tener un alias de módulo más fácil resulte en menos usuarios _quejándose_ sobre conflictos de nombres, pero me sorprendería si eso tiene un tremendo impacto en las API.

Cuando escribo una biblioteca, por lo general soy bastante consciente de si quiero agregar un despacho a una función en Base o si quiero mantenerlo separado. Supongo que la mayoría de los otros autores de bibliotecas también lo son.

@ninjaaron Creo que si la convención actual usa una implementación específica para el envío como

numpy.sin
sympy.sin

usar import numpy.sin as np_sin como una opción adicional para el usuario/desarrollador no debería afectar la base de código actual.
La única preocupación solo afectará la función/interfaz de exposición.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

tkoolen picture tkoolen  ·  3Comentarios

dpsanders picture dpsanders  ·  3Comentarios

i-apellaniz picture i-apellaniz  ·  3Comentarios

felixrehren picture felixrehren  ·  3Comentarios

Keno picture Keno  ·  3Comentarios