Julia: Modul und Aliasing importieren

Erstellt am 5. Sept. 2012  ·  96Kommentare  ·  Quelle: JuliaLang/julia

Für das Modulsystem können wir ein Modul mit Punktnotation importieren und verwenden:

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

Dies kann nützlich sein, um eine Namespace-Verschmutzung zu verhindern. Aufgrund der Ausführlichkeit der Modulnamen wäre es jedoch schön, Modulaliase zu haben:

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

Hilfreichster Kommentar

dieses Thema gibt es schon länger, auch wenn einige Erweiterungen noch diskutiert werden sollten, die

import LongPackage as longpkg

selbst scheint ziemlich vernünftig.

Alle 96 Kommentare

Mir ist vor wenigen Minuten klar geworden, dass Sie Folgendes tun können:

import ArgParse
ap = ArgParse

ap.add_argument(...)

Ich denke immer noch, dass es schön wäre, die Notation "Importieren als" als syntaktischen Zucker zu haben.

Während ich hier bin und darüber nachdenke, wäre es auch schön, mehrere spezifische Funktionen in derselben Importzeile zu importieren, wie in @JeffreySarnoffs Forumsbeitrag erwähnt. Eine Suche in den Ausgaben hat eine solche Anfrage noch nicht ergeben.

Etwas wie

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

Es ist ein anderes Problem als dieses, aber verwandt. Sollte ich

  1. Aktualisieren Sie dieses Problem, oder
  2. ein neues Problem erstellen

(Ich gehe davon aus, dass die Nützlichkeit einer solchen Funktion nicht umstritten ist ...)

Bearbeiten : Dies funktioniert jetzt mit import Module: export1, export2, export3

Ich denke, dass es auch zB unterstützen sollte

import ArgParse.add_argument as addarg

Modulmitglieder beim Import umbenennen zu können.

Sie fragen sich, wie umbenannte Funktionsnamen am Versand teilnehmen würden?

Es müsste im Grunde wie ein Alias ​​funktionieren, äquivalent zu const foo = Base.bar .

Es müsste im Grunde wie ein Alias ​​​​funktionieren, äquivalent zu const foo =
Basisleiste.

Wenn wir eine Funktion importieren, planen wir entweder, sie zu verwenden oder zu überschreiben. Gegeben
oben, mit

importiere Base.bar als foo

wir können definitiv foo als Base.bar verwenden, aber die Definition von foo würde auch überschreiben
Base.bar? Sollte es?

Dies ist ein altes Problem, aber ich denke, es ist an der Zeit, dies erneut zu betrachten, da wir uns 0,2 nähern

Beim Schreiben von Codes stellte ich fest, dass ich schon immer import NumericExtensions as ne schreiben wollte, und erinnerte mich schließlich daran, dass dies nicht unterstützt wurde.

Ich denke, das ist nicht allzu schwer umzusetzen, und meiner Meinung nach ist das viel schöner als das Schreiben

import NumericExtensions
const ne = NumericExtensions

+1

+1

Ist das noch aktuell? Es macht mir persönlich nichts aus, nur die zusätzlichen foo = Foo für Modul-Aliasing zu machen, aber es hört sich so an, als ob es einen Konsens gab, Aliasing-Zucker zu unterstützen. Jemand, der stark genug fühlt, muss vielleicht selbst eine PR machen.
Beachten Sie jedoch, dass x as y einer der stärksten Konkurrenten für die in #1470 erwähnte convert(y,x) -Syntax war. Es scheint, als wäre es nicht allzu schwierig, die beiden zu disambiguieren, aber nur zu bemerken.

Der Wert dieser Funktion besteht darin, dass Sie den Import des ursprünglichen Namens vermeiden könnten.

+1
Wäre toll diese Funktion zu haben.

+1

Anstatt ein neues Schlüsselwort as einzuführen, wie wäre es mit dem Operator => , wie in

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

Dies würde ein orthogonales Aliasing des Moduls und einer beliebigen Teilmenge von Variablen in derselben Syntax ermöglichen.

Ich weiß nicht, das kommt mir sehr hässlich vor.

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

Ist das besser? Ich finde es viel weniger lesbar.

Ich persönlich finde as selbsterklärender als => , was so aussieht, als könnte es eine Reihe von Dingen bedeuten.

vollständige Offenlegung: Python-Voreingenommenheit.

Ich mag die Syntax => besser als as .

Ich mag Fahrradschuppen, die in Nash-Gleichgewichten stecken bleiben.

Warum sollten Sie die inneren Symbole eines Moduls neu binden? Es ist hässlich, weil Sie das wirklich nicht tun sollten.

Ich mag die Importsyntax von Haskell . Ich glaube, dass die Namespaces von Python granularer sind als die Module von Julia. Die Module von Julia haben mehr Ähnlichkeit mit den Modulen von Haskell, also sollten wir vielleicht dort nach Inspiration suchen.

Ich stimme @ssfrr zu, das Schlüsselwort as ist viel selbsterklärender und ist Python/Haskell-Benutzern ebenfalls vertraut. Um das @StefanKarpinski -Problem mit der Lesbarkeit zu lösen, würde auch ein Python-ähnlicher Ansatz helfen:

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

Ich habe das Gefühl, mit der REPL zu sprechen. Aber ich weiß, dass diese Art von Vorschlag nicht durchführbar ist.

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

Dies ist eine meiner unbeliebtesten syntaktischen Entscheidungen in Python. Um die Bedeutung leicht zu ändern, müssen Sie die gesamte Zeile radikal neu anordnen, das ursprüngliche Schlüsselwort und die Reihenfolge von allem ändern. Es sieht völlig anders aus als andere Importe und verschleiert die Tatsache, dass sie fast dasselbe tun. Dies ist ein schreckliches syntaktisches Design, imo, das viel zu viel Gewicht darauf legt, oberflächlich englisch zu sein.

:+1: für as , :-1: für from

import a => b: c => d, e => f fühlt sich für mich etwas zu perlartig an.

Ich habe noch nie von Nash-Gleichgewichten gehört und nachdem ich darüber gelesen habe, glaube ich nicht, dass dies eines darstellt. Aber das Lustige ist, während dieser Fahrradschuppen 10 Antworten in einer Stunde hat, ist ein Vorschlag auf # 6984, der mir sehr wichtig (aber schwieriger) erscheint, 4 Stunden ohne Kommentar vergangen!

Was as vs. => : Beides wird eine nette Verbesserung gegenüber der gegenwärtigen Situation sein.

Guter Punkt @BobPortmann auf #6984.

Ich denke, => ist großartig dafür, FWIW.

Aber das Lustige ist, während dieser Fahrradschuppen 10 Antworten in einer Stunde hat, ist ein Vorschlag auf # 6984, der mir sehr wichtig (aber schwieriger) erscheint, 4 Stunden ohne Kommentar vergangen!

In Parkinsons ursprünglicher Analogie ist dieses Problem der Fahrradschuppen und #6984 ist der Kernreaktor.

:)

Ich hasse es, in diesem Topf umzurühren, aber ich glaube, ich bevorzuge as . => ist ein bisschen vage, und es ist seltsam, dass dies die Syntax mit Wörterbüchern teilt. Vielleicht macht einfach = Sinn: import Foo: x = y , in Analogie zu den const x = Foo.y , die Sie jetzt machen würden.

Nicht zuletzt ist diese Tabelle in der Haskell-Dokumentation wirklich hilfreich. Ich war oft (besonders als ich zum ersten Mal Julia lernte) verwirrt, wann ich import / using / require verwenden sollte oder wann ich import Mod.thing vs import Mod: thing . Ich habe eigentlich nur nach der Erklärung der Doppelpunktsyntax für Importe gesucht und sie nicht gefunden.

@jakebolewski es scheint, als wäre die Haskell-Syntax ziemlich nah, wobei Julias using Haskells (nicht qualifiziertes) import entspricht und Julias import Haskells import qualified entspricht


Kann jemand, der es besser weiß, als Ausgangspunkt bestätigen, dass dies eine gute Zusammenfassung der derzeit verfügbaren Syntax zum Importieren/Verwenden ist? Angenommen, wir haben ein Modul Mod , das die Funktionen x und y exportiert und auch die nicht exportierten Funktionen p und q hat.

import Mod liefert Mod.x , Mod.y , Mod.p und Mod.q . Die importierten Funktionen stehen alle für die Methodenerweiterung zur Verfügung

using Mod bringt x , y , Mod.x , Mod.y , Mod.p und Mod.q ein . x und y sind nicht für die Methodenerweiterung verfügbar, Mod.* hingegen schon.

import Mod.x, Mod.p bringt x , p , Mod.x , Mod.y , Mod.p und Mod.q ein . Sie alle stehen zur Methodenerweiterung zur Verfügung.

import Mod: x, p ist dasselbe wie import Mod.x, Mod.p

using Mod.x, Mod.p bringt x , p , Mod.x , Mod.y , Mod.p und Mod.q ein . x und p sind für die Methodenerweiterung nicht verfügbar, Mod.* hingegen schon.

using Mod: x, p ist dasselbe wie using Mod.x, Mod.p

Soweit ich das beurteilen kann, ist using Mod die einzige Verwendung, die sich darum kümmert, was von Mod exportiert wird.

Es wäre wirklich nützlich, diese Zusammenfassung in den Moduldokumenten zu haben! Kann das jemand bestätigen, damit ich eine PR vorbereiten kann?

Es scheint, als wäre die am wenigsten umstrittene Version:

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

Ich bin cool damit. Die Aufgabenversion ist jedoch interessant, testen Sie sie:

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

Ich dachte, ich würde das hassen, aber es ist eigentlich ziemlich nett. Mir gefällt, dass die Namen, die in diesem Modul vorgestellt werden, zuerst kommen und am prominentesten sind – in vielerlei Hinsicht ist das das Wichtigste.

@jakebolewski : Warum würden Sie die inneren Symbole eines Moduls neu binden? Es ist hässlich, weil Sie das wirklich nicht tun sollten.

Möglicherweise möchten Sie Bindungen mit widersprüchlichen Namen aus zwei verschiedenen Modulen importieren, und dies ermöglicht dies. Sie könnten sie auch vollständig qualifizieren, aber wenn wir Aliasing unterstützen, können wir dies genauso gut unterstützen.

Einige gut platzierte Zeilenumbrüche machen beide besser lesbar, IMO:

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

oder

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

Ich finde, dass ich die Aufgabenversion ziemlich stark bevorzuge. Der Import ist schließlich eine Form der Abtretung.

Es wäre wirklich nützlich, diese Zusammenfassung in den Moduldokumenten zu haben! Kann das jemand bestätigen, damit ich eine PR vorbereiten kann?

@brk00 , mach es!

@kmsquire , ich werde heute daran arbeiten!

Aber bevor ich das tue, möchte ich sicherstellen, dass ich es gut verstehe. Angenommen, ich bin im @ssfrr- Beispiel auf der REPL und gebe using Mod ein. Die importierten Funktionen x und y sind für die Methodenerweiterung nicht verfügbar. Das bedeutet, dass ich, wenn ich weitere x- und y-Funktionen deklariere, keinen Zugriff mehr auf die Methoden Mod habe, die ich einmal importiert habe, sondern nur noch auf die neuen?

Folgendes passiert, wenn Sie versuchen, eine Funktion zu erweitern, ohne sie zu importieren:

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

Sie können eine Methode wie folgt hinzufügen:

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

Nun, ich war verwirrt durch das Namensauflösungsverhalten:

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)

Wenn ich x eine neue Funktion zuweise, bevor ich die Funktion _verwende_, die ich gerade mit using Mod importiert habe, wird der Fehler nicht ausgelöst. Aber wenn ich zB x() vor der neuen Zuweisung aufrufe (wie du es in deinem Beispiel getan hast), wird der Fehler tatsächlich ausgelöst.

Ach, interessant! Ich wusste nichts davon. Ich habe zufällig x aufgerufen, um den Namensraum nach dem using $ zu demonstrieren.

Vielleicht kann einer der Kernentwickler etwas Licht ins Dunkel bringen. Was passiert, wenn x aufgerufen wird, das den Fehler bei versuchter Überladung auslöst?

Ich finde das von @carlobaldassi oben vorgeschlagene Aliasing in der Praxis sehr nützlich.

Ich frage mich, ob import das Modulobjekt einfach zurückgeben könnte, damit es direkt mit einer Zuweisung mit oder ohne const aliasiert werden könnte? Z.B

const Shortname = import ModuleWithLongName

anstatt

import ModuleWithLongName
const Shortname = ModuleWithLongName

Dies würde keine neue Syntax erfordern, sondern nur eine Kombination bestehender Syntaxelemente. Mir ist klar, dass derzeit import eine "Aussage" ist, die nur wegen Nebenwirkungen aufgerufen wird und keinen Wert hat. Wenn der Parser dies nicht zulässt, würde ich import("Module") oder ähnliches bevorzugen.

Ich denke, die Option, Module zu aliasieren, könnte nett sein, aber ich denke auch, dass es einen Nachteil gibt, den niemand erwähnt hat: Es könnte den Code erheblich verschleiern. Aus Sicht eines Codelesers ist es schön, nur einen beschreibenden Namen für ein Modul zu haben.

Ziemlich trivial nachzuschlagen? Die verkürzten Formen werden wahrscheinlich auch für beliebte Pakete wie np für numpy standardisiert.

Ich würde immer noch numpy dem standardisierten np und sogar Arrays numpy vorziehen. numpy klingt wie eine Mischung aus einer Tanzbewegung aus den 1950er Jahren und einer tödlichen Seuche.

kann einfach schreiben:

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

dies benötigt keine Syntax für 1.0

Ich finde, dass wir dafür eine Syntax haben sollten. Ja, wir können ohne sie leben, da Sie require und eine const -Zuweisung machen können, aber die Verwendung require ist ziemlich hässlich und das Fehlen einer praktischen Syntax hält Leute davon ab, Dinge umzubenennen wie sie wollen/müssen.

Der const -Trick , einfach zu sein, greift zu kurz, wenn man ein Makro aliasieren muss. So mache ich das, und es hat eine Weile gedauert, bis ich es herausgefunden habe:

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)                                                    

In ImportMacros.jl implementiere ich:

  • <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

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

@Ismael-VC

Versuchen

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

Das ist hässlicher, aber kürzer und vielleicht klarer, als ein Makro lokal zu definieren

@TotalVerb Nochmals vielen Dank für Ihre Hilfe!

Es scheint, dass die einzige Funktionalität, die Julia + ImportMacros fehlt, darin besteht, sowohl das Modul als auch eine Mischung aus dem Aliasing einer variablen Anzahl von Objekten aus einem solchen Modul und dem Importieren anderer ohne Aliasnamen zu verwenden:

  • <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

Oder ohne 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

Letzteres scheint mit Makros nicht möglich zu sein:

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

Dies muss eigentlich nicht für 1.0 entschieden werden, da alle vorgeschlagenen Syntaxen entweder Fehler oder totaler Unsinn sind.

Was soll mit einem Modul-Alias ​​passieren, wenn das ursprüngliche Modul neu definiert wird, zB durch ein reload("...") auf der REPL? Beim const M = MyModule -Ansatz bezieht sich M nach dem Neuladen immer noch auf das alte Modul, sodass auf alle neu definierten Namen in MyModule nur von MyModule.name werden kann, aber nicht M.name .

In diesem Fall sollte eine Alias-Syntax mehr als syntaktischer Zucker für ein const M = Module sein, aber stellen Sie stattdessen sicher, dass sich M immer auf dasselbe bezieht wie MyModule .

Dies würde auch den REPL-Workflow vereinfachen, da ich während der Entwicklung weiterhin auf ein Modul import zugreifen kann, aber über einen kürzeren Alias ​​darauf verweisen kann, ohne jedes Mal einen (nicht const ) Alias ​​neu erstellen zu müssen reload .

Ab sofort ist reload entfernt, sodass diese Bedenken nicht mehr bestehen.

Dies gilt auch für include , oder übersehe ich etwas? Wenn ein Modul neu definiert wird, bezieht sich der import ed-Modulname im Allgemeinen auf die neue Definition, während ein durch Zuweisung definierter Alias ​​auf die alte Definition verweist, richtig?

Nein, das sollte nicht besorgniserregend sein. Der importierte Name wird NIE geändert, wenn ein Modul neu definiert wird, einschließlich des normalen import . Was sich geändert hat, ist das Modul, das importiert wird, wenn Sie es erneut importieren. Das Importierte war immer nur eine Bindung.

Ok, vielleicht habe ich mich nicht klar ausgedrückt, deshalb hier ein Beispiel: Wenn Sie eine Datei test.jl mit dem Inhalt erstellen

module Tst
f() = 1
end

Sie können es laden, Tst importieren, einen Alias ​​für Tst definieren und alles ist in Ordnung:

julia> include("test.jl")
Tst

julia> import Tst

julia> const Tst2 = Tst
Tst

julia> Tst.f()
1

julia> Tst2.f()
1

Wenn Sie jetzt test.jl in ändern

module Tst
f() = 2
end

und include es in der REPL erneut ausführen, verhalten sich das Modul und sein Alias ​​anders:

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

julia> Tst.f()
2

julia> Tst2.f()
1

Ich verstehe, warum dies der Fall ist, aber ich denke, dies sollte nicht passieren, wenn Sie einen Alias ​​mit etwas wie import Tst as Tst2 erstellen.

Ich habe das auf 0.6.2 getestet, und im Moment kann ich es nicht auf 0.7 testen, also weiß ich jetzt nicht, ob das immer noch der Fall ist.

Sie importieren es überhaupt nicht. Das von Ihnen aufgenommene Modul ist bereits in Ihrem Geltungsbereich definiert. Das import ist ein no-op.

Stimmt, aber darum geht es nicht. Der Punkt ist, was passiert, wenn ich so etwas wie das hypothetische import Tst as Tst2 mache. Dann ist diese Anweisung kein No-Op, sondern erzeugt einen Alias.

Wenn dieser Alias ​​wie ein const Tst2 = Tst funktioniert, dann wird das Neudefinieren des Moduls Tst den Alias ​​auf die alte Version des Moduls verweisen lassen. Dies ist in keinem Fall wünschenswert. Entweder sollte der Alias ​​auch auf die neue Version von Tst zeigen, oder der Benutzer sollte gezwungen werden, den Alias ​​neu einzurichten. Aber im letzteren Fall sollte die Verwendung des alten Alias ​​ohne Wiederherstellung einen Fehler ausgeben, anstatt auf das alte Modul zu verweisen.

Das ist ganz der Punkt. In dieser Ausgabe geht es darum, eine Funktion zu import hinzuzufügen, nicht zur Moduldefinition. Ihr import ist no-op und nachdem Sie es entfernt haben, enthält Ihr Code keine import oder using mehr, sodass es nichts mit diesem Problem zu tun hat. Bitte ändern Sie es so, dass das Modul nicht im selben Bereich wie import definiert ist.

import Tst as Tst2 funktioniert genauso wie import Tst in Bezug darauf, was an diesen Namen gebunden ist, was immer eine Bindung ist und nichts Magisches, was Sie wollen. Hier geht es NICHT um das Hinzufügen eines Alias ​​beim Definieren des Moduls.

Anders ausgedrückt, Ihr Code ist im Grunde genommen

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

Und es macht keinen Sinn, sich über das Verhalten des b = a zu beschweren, da das a überhaupt nicht an das a = a gebunden ist. Alles, was Sie sehen, ist der Nebeneffekt der Definition des Moduls im selben Geltungsbereich wie der Import (dh a = a und a = Ref(...) im selben Geltungsbereich) in einem schlechten Beispiel.

Ok, ich wollte nur darauf hinweisen, dass in manchen Situationen ein durch eine Zuweisung definierter Alias ​​nicht wie erwartet funktioniert. Vielleicht habe ich ein schlechtes Beispiel gewählt. Ich dachte, das könnte für eine Syntax wichtig sein, die einen Modul-Alias ​​erstellt (unabhängig davon, ob es sich um import handelt oder nicht), aber im Moment ist dies sowieso hypothetisch. Sorry für den Lärm.

dieses Thema gibt es schon länger, auch wenn einige Erweiterungen noch diskutiert werden sollten, die

import LongPackage as longpkg

selbst scheint ziemlich vernünftig.

Stoßen. Ich frage mich, wie die beste Lösung - für den Moment - aussieht? Folgendes mache ich:

import LinearAlgebra
const linalg = LinearAlgebra

Bitte korrigiert mich, wenn es eine bessere Lösung gibt!

Das ist der aktuelle Standard.

Was ist mit einer ~-Syntax? Ich kenne die Auswirkungen nicht, aber es hat eine schöne Ästhetik. Außerdem wird ~ als Symbol für ungefähr verwendet.

import LongPackage ~ lp

@JeffreySarnoff zitiert Stefan

@StefanKarpinski

Dies ist eine meiner unbeliebtesten syntaktischen Entscheidungen in Python. Um die Bedeutung leicht zu ändern, müssen Sie die gesamte Zeile radikal neu anordnen, das ursprüngliche Schlüsselwort und die Reihenfolge von allem ändern. Es sieht völlig anders aus als andere Importe und verschleiert die Tatsache, dass sie fast dasselbe tun. Dies ist ein schreckliches syntaktisches Design, imo, das viel zu viel Gewicht darauf legt, oberflächlich englisch zu sein.

In diesem Fall hätte ~ nichts mit dem englischen Aspekt der Python-Syntax zu tun. Ich denke, wenn ich ~ sehe, erkenne ich nur das mathematische Konzept der Annäherung. 10.001 ~ 10.

Insofern finde ich ~ eigentlich ganz nett.

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

:-)

ok – vergiss Python – ich lösche diesen Kommentar zugunsten von

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

Ich mochte es ursprünglich nicht, aber so viele Leute scheinen das natürlich mit as schreiben zu wollen. Ich muss sagen, es scheint pervers, irgendetwas anderes zu tun. Es muss nicht als Schlüsselwort oder ähnliches reserviert werden, da dies ein klarer syntaktischer Kontext ist.

Eine Programmiersprache, die _versucht_, die Leute wissen zu lassen, was sie bedeutet!?!

@JeffreySarnoff

Eine Programmiersprache, die versucht besser zu sein als Python !!!

@neilpanchal Julia ist definitiv eine Sprache, die versucht, in vielerlei Hinsicht besser als Python zu sein. Auf der anderen Seite gibt es sich ganz offensichtlich nicht die Mühe, _anders_ zu sein als Python, wo Python etwas richtig gemacht hat. Julia leiht sich links und rechts syntaktische Konventionen von Python.

Bitte übernehmen Sie die Python as . Sie haben es richtig gemacht.

julia> LightGraphs als lg importieren
FEHLER: Syntax: zusätzliches Token „as“ nach Ende des Ausdrucks

Nur ein weiterer $0,02-Kommentar zugunsten von as , der von Python wegkommt. fwiw, jetzt, wo ich Julia wieder mit einiger Regelmäßigkeit benutze, vermisse ich das. Nicht wie in Python, sondern wie in Clojure (siehe Beispiel ), wo paketbezogene Namespaces (die gut zur Begriffsklärung sind) vereinfacht werden können, um die explizite Verwendung von Bibliotheken viel handlicher zu machen. Da ich es vorziehe zu vermeiden, dass using (dh Wildcard-Importe) etwas syntaktischen Zucker zu import Gadlfy as gf haben, ohne die Zeile const gf = hinzuzufügen (was ich derzeit tue). handlich sein.

Noch ein weiterer Kommentar, der die as -Syntax unterstützt :heart: Ich wünsche es wirklich sehr für zukünftige Julia-Veröffentlichungen.

Das wünsche ich mir auch. Zumal es keine Breaking Change ist (richtig?).

Ich denke, dass dies irgendwann implementiert wird (ich würde es selbst versuchen, wenn ich die Zeit finden könnte), aber in der Zwischenzeit hat das ImportMacros -Paket so ziemlich alle hier angeforderten Funktionen (obwohl ihm die Dokumentation fehlt). :

<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>

Ich wusste nichts über ImportMacros .jl, danke für den Hinweis. Wenn diese Funktionalität in einem Paket vorhanden ist, ist es meiner Meinung nach nicht so wichtig, sie in der Basissprache zu haben.

Ich denke immer noch, dass dies in der Sprache gut wäre.

Importe sind meiner Meinung nach genau die Art von Dingen, für die Sie sich fast _immer_ an die Konventionen der Basissprache halten und keine Makros einschließen oder eine Paketabhängigkeit hinzufügen möchten. import ... const ist eine bessere Sache, auf die man zurückgreifen kann, selbst (besonders) wenn die Basissprache nie erweitert wird, um diesen zweistufigen Prozess prägnanter zu machen.

Insbesondere ist es etwas hässlich zu sehen

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

weil das Nicht-Makro using hervorsticht.

Wie wäre es, wenn import das Modul/die Funktion/was auch immer es tatsächlich in den Geltungsbereich bringt zurückgibt?
Dann kannst du schreiben
lg = import LightGraphs
baz = import foo.bar
baz, kit, kat = import foo : bar1, bar2, bar3
Das einzige, was geändert werden muss, ist die Importfunktion

Ich mag die Lösung von @DhruvaSambrani sehr , weil sie zu Julias allgemeinem „Alles ist ein Ausdruck“-Ansatz passt.

Die einzige Sache ist, dass der Importausdruck, um konsistent zu sein, immer noch den Nebeneffekt haben müsste, den vollständigen Namen in den Geltungsbereich zu bringen (vielleicht keine Katastrophe). Es könnte auch ein Sonderfall sein, den vollständigen Namen nicht zu importieren, aber Sonderfälle sind ekelhaft.

In OCaml (der Sprache mit den besten Modulen!) können Sie so etwas tun:

module LG = LightGraphs

Der wichtige Unterschied besteht hier darin, dass der qualifizierte Name jedes Moduls, das mit dem OCaml-Programm kompiliert wird, automatisch im Geltungsbereich ist.

Natürlich hat die Verwendung import LightGraphs as LG den Vorteil, dass "jeder" es bereits von Python kennt, aber mein persönlicher Geschmack ist, dass es besser ist, die Zuweisungssyntax für etwas wiederzuverwenden, das buchstäblich eine Zuweisung ist.

Oder eine umfassendere Änderung wäre die Einführung eines "Namespace" als Typ (idk, falls dies bereits geschehen ist). Dann kann import das Modul/was auch immer in einen Namensraum erweitern und den Namensraum zurückgeben. Dies wird jedoch den gesamten Julia-Code beschädigen, da das einfache Ausführen import mod_name den Namensraum mod_name nicht im globalen Bereich verfügbar macht. Wenn man den Namensraum mod_name global verfügbar machen kann, wenn import verwendet wird, ohne dass ihm eine Zuweisung vorangeht, dann ist das kein Problem.

Oder fügen Sie einfach eine neue Funktion import_as_ns(mod_name) :: Namespace hinzu, die eine reine Funktion ist, die alle Funktionen/Module usw. in einem einzigen Namensraum zurückgibt.

es passt zu Julias allgemeinem „alles ist ein Ausdruck“-Ansatz

Allerdings sind import und using etwas Besonderes, da sie nur für ihre Nebenwirkungen und nur auf der obersten Ebene verwendet werden.

Übrigens, da dieses Thema schon seit langem offen ist, frage ich mich, ob Triage bereit wäre, es erneut zu prüfen und eine Entscheidung zu treffen. Da würde ich für eine Schließung plädieren

  1. import Foo; const Bar = Foo bietet eine perfekte Lösung, wenn der Benutzer Foo im Namensraum nicht stört,
  2. ImportMacros.jl sollte den Rest erledigen,
  3. keiner scheint in praktischem Code sehr häufig verwendet zu werden, um eine spezielle Syntax zu rechtfertigen.

Ich werde sagen, dass ich das nach all der Zeit immer noch vermisse (und ich verwende ImportMacros auch in meinem eigenen Code).

Ich denke, dass der Kaffeestil, den Sie schreiben, die Notwendigkeit (oder den Wunsch) danach beeinflusst. Wenn ich ML oder wissenschaftlichen Code schreibe, vermisse ich es nicht sehr. Wenn ich anderen Code geschrieben habe, der eine Reihe von Paketen mit langen Namen verwendet, finde ich, dass ich ImportMacros am häufigsten verwende.

ImportMacros ist ausreichend. Ich stimme nur den Kommentaren zu, dass es nicht so sauber aussieht.

Ich freue mich auch auf den Tag, an dem ich einen Autoformatter in meinem Editor verwenden kann, um meine Importe zu sortieren ... aber es ist weniger wahrscheinlich, dass er weiß, was er mit @using machen soll ...

Ich stimme @kmsquire auch zu, dass dies kein so großes Problem ist und ImportMacros ausreichen sollte. Aber jede Methode sollte dokumentiert werden, damit sie nicht wieder auftaucht.

Obwohl ich den m=import Module -Zucker immer noch gerne hätte 😅

Ich wollte nicht, dass meine Nachricht andeutet, dass dies keine große Sache ist.

Ich würde immer noch eine Syntax dafür bevorzugen.

ImportMacros ist ausreichend. Ich stimme nur den Kommentaren zu, dass es nicht so sauber aussieht.

Ich stimme zu. Auch für:

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

Es macht es ein bisschen nervig, wenn man Neulingen oder Programmieranfängern die Sprache präsentiert, wenn man erklärt, warum ein bestimmtes Skript mit dieser Inkonsistenz beginnt, da es den Fluss verkompliziert und den Fokus des Unterrichts verschiebt.

keiner scheint in praktischem Code sehr häufig verwendet zu werden, um eine spezielle Syntax zu rechtfertigen

Der Grund, warum Leute ImportMacros nicht oft im tatsächlichen Code verwenden, könnte auf einen Kompromiss zurückzuführen sein. Zum Beispiel würde ich fast jedes Mal import ... as ... verwenden, aber wahrscheinlich nicht auf Kosten des Importierens eines anderen Pakets, um dies zu tun. Mehr als eine zusätzliche Abhängigkeit, es hat auch Auswirkungen auf das "Feeling" (und einige Leute mögen es, wenn ihr Code elegant aussieht (besonders in Python oder Julia) 🤷‍♂️ , und dieses using/@using gibt ein ziemlich " hacky"-Vibe bis hin zur Einführung eines Skripts).

Also ja, "ImportMacros ist ausreichend". Für Leute, die es wirklich nutzen wollen. Aber das ist die Sache, es ist kein wichtiges Thema, und die Leute können ohne es arbeiten. Nichtsdestotrotz bin ich fest davon überzeugt, dass es normalerweise diese kleinen Dinge sind, die dafür sorgen, dass die Syntax einer Sprache hängen bleibt, daher dieser Monster-Thread, um seine Unterstützung für base hinzuzufügen.

Ich denke, dass import ... as ... syntaktischer Zucker ist, der es definitiv wert wäre, es ist wirklich einfach zu verstehen und zu erklären, und besonders nützlich in Sprachen wie Julia, in denen Pakete dazu neigen, ziemlich lange Namen zu haben (offensichtlich ist das wichtig nur unter der Annahme, dass die Leute using ... nicht machen wollen).

Und die Tatsache, dass Python es zuerst implementiert hatte, sollte nicht wirklich relevant sein; Julia sollte sich bemühen, die beste Syntax zu haben, bevor sie versucht, sich von anderen Sprachen zu distanzieren und/oder ihre eigene Identität zu betonen.

Eine Syntax dafür und Konventionen rund um beliebte Module (ich denke daran, dass es immer import numpy as np und import matplotlib.pyplot as plt ist) würde auch eine prägnante Alternative dazu bieten, using SuchAndSuch zu tun und sich auf export zu verlassen

@DominiqueMakowski :

Neueinsteigern oder Programmieranfängern die Sprache vorzustellen, um zu erklären, warum ein bestimmtes Skript mit dieser Inkonsistenz beginnt

Ich verstehe nicht, warum Sie denken, dass es eine Inkonsistenz ist, es ist einfach Namespace-Management, was im Großen und Ganzen ein normaler Teil der Programmierung ist.

Außerdem ist das Umbenennen von Modulen möglicherweise nicht etwas, auf das Julia-Neulinge zuerst stoßen würden.

Ich sage nicht, dass es keinen Anwendungsfall gibt, aber es kann zu selten sein, um ein eigenes Schlüsselwort zu rechtfertigen. Im Moment liefert die Suche nach using ImportMacros <10 eindeutige Ergebnisse auf Github.

Ich würde fast jedes Mal import ... as ... verwenden, aber wahrscheinlich nicht auf Kosten des Importierens eines anderen Pakets, um dies zu tun

Dies wirkt sich in beide Richtungen aus: Wenn die (sehr geringen) Kosten für die Verwendung eines leichten Pakets wie ImportMacros oder eines zusätzlichen Symbols ( import LongFoo; const Foo = LongFoo ) den Nutzen nicht wert sind, ist der Nutzen möglicherweise nicht so groß .

Julia sollte sich bemühen, die beste Syntax zu haben, bevor sie versucht, sich von anderen Sprachen zu distanzieren und/oder ihre eigene Identität zu betonen.

Ich bin mir nicht sicher, warum Sie denken, dass dies eine Motivation in dieser Diskussion ist.

Es gibt einige Fälle, in denen Sie as verwenden möchten, wenn die const -Zuweisung nicht ganz funktioniert:

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

Ja, Sie können das umgehen, aber es ist umständlich. Angesichts der Tatsache, dass es oft praktisch ist, manchmal benötigt wird und dass import FooBar as FB die allgemein vereinbarte "am wenigsten überraschende" Syntax ist, scheint dies das zu sein, was wir tun sollten. Alles, was dies braucht, ist, dass jemand eine PR macht, die es umsetzt.

Neuer Julia-Benutzer hier.
Ich habe hauptsächlich einen R-Hintergrund und benutze auch Python. Ich habe schlechte Erfahrungen mit dem Paket-Common-Namespace gemacht, zu dem Lademechanismen wie using führen. Das Kollisionsrisiko ist eins, aber nur aus Sicht der Lesbarkeit ist es eine mentale Belastung, ständig über das Modul jeder Methode nachzudenken.

Ich weiß nicht, wie komplex das Hinzufügen dieser Syntax ist? Ist es für einen Neuling machbar?

Wahrscheinlich nicht ganz einfach. Dazu gehört das Hacken des in Scheme geschriebenen Parser-Codes und das Verdrahten der Änderung durch den AST, wobei möglicherweise auch C-Code berührt wird.

Es wäre eine nette Funktion, um Funktionsnamenskonflikte in mehreren Modulen zu vermeiden.

Aus einer Diskussion über Slack füge ich einige Gedanken hinzu

Ich frage mich, ob die Leute dadurch weniger vorsichtig mit der Auswahl von Funktionsnamen und dem richtigen Hinzufügen von Methoden zu den richtigen Funktionen werden. Die Tatsache, dass z.

numpy.sin
sympy.sin

are different functions ist eine todsichere Möglichkeit, zwei Versionen Ihrer Funktion zu implementieren, wenn Sie möchten, dass sie sowohl für numerische als auch für symbolische Eingaben funktioniert. Wenn solche Namensräume aufgrund der Bequemlichkeit auch in Julia weit verbreitet sind, könnten wir eine Menge Code-Wiederverwendung verpassen? Das heißt, ich fürchte, dies könnte uns weniger von „ Das ermutigt Menschen zur Zusammenarbeit “ geben, wie es von Lyndon in https://www.oxinabox.net/2020/02/09/whycompositionaljulia.html formuliert wurde

@baggepinnen Ich glaube nicht, dass dies daran etwas ändert.

In Julia werden Methoden, die in verschiedenen Modulen implementiert sind, nicht zusammengeführt, indem beide Methoden in denselben Namensraum importiert werden.

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"

Man muss der ursprünglichen Funktion explizit einen Versand hinzufügen, damit dies funktioniert:

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

julia> sin("wat")
"WAT"

Soweit ich das beurteilen kann, gibt es für Modul-Aliasing keine Möglichkeit, die Art und Weise zu ändern, wie Funktionen versendet werden.

Und ehrlich gesagt _sollten_ einige Funktionen mit dem gleichen Namen in separaten Namespaces leben. Eine find_delta -Funktion in einer numerischen Bibliothek wird etwas tun, das nichts mit find_delta in einer Datei-Diff-Bibliothek zu tun hat. Sobald Ihr Code so polymorph ist, dass er einen Weg findet, ihn bei fehlerhafter Eingabe auszuführen, betreten Sie JavaScript-Territorium, und das will niemand.

@ninjaaron Ich habe es möglicherweise versäumt, einige Nuancen in meiner obigen Besorgnis zu vermitteln. Mir geht es nicht darum, dass diese Änderung irgendetwas anderes ändert als die Strategie, die die Leute wählen, wenn sie Bibliotheken implementieren.
Die Person, die Foo implementiert, erhält eine Warnung wie

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

kann entweder einfach import .Foo.sin as sin2 wählen oder darüber nachdenken, ob er wirklich eine neue Sendung für Base.sin bereitstellen wollte oder nicht. Mein Punkt war, dass, wenn es sehr einfach wird, sie einfach als unterschiedliche Funktionen zu betrachten, dies möglicherweise zu weit verbreitet ist, selbst in Situationen, in denen es eigentlich unterschiedliche Methoden derselben Funktion sein sollten. Die aktuelle Situation, wo es etwas umständlicher ist, mit verschiedenen Funktionen mit dem gleichen Namen umzugehen, hat den netten Nebeneffekt, dass die Leute miteinander reden und ihr Bestes geben, um herauszufinden, ob es wirklich die gleiche Funktion ist oder nicht. Ich argumentiere nicht gegen die Möglichkeit, verschiedene Funktionen mit demselben Namen zu haben, was natürlich sehr nützlich sein kann. Ich bin mir nicht einmal sicher, ob mein Anliegen wichtig ist oder nicht, aber ich dachte, es wäre es wert, es aufzuheben, um sicherzustellen, dass es berücksichtigt wurde.

@baggepinnen Das macht Sinn, und es schadet nicht, es anzusprechen. Ich glaube nicht, dass dies einen großen Unterschied für Leute machen wird, die Bibliotheken erstellen, da Modul-Aliasing nur Bibliotheksbenutzer betreffen wird. Ich schätze, es ist möglich, dass ein einfacheres Modul-Aliasing dazu führt, dass sich weniger Benutzer über Namenskonflikte _beschweren_, aber ich wäre überrascht, wenn dies einen enormen Einfluss auf APIs hätte.

Wenn ich eine Bibliothek schreibe, bin ich mir normalerweise ziemlich bewusst, ob ich einer Funktion in Base einen Dispatch hinzufügen oder ihn separat halten möchte. Ich würde annehmen, dass die meisten anderen Bibliotheksautoren es auch sind.

@ninjaaron Ich denke, wenn die aktuelle Konvention eine bestimmte Implementierung für den Versand verwendet, wie z

numpy.sin
sympy.sin

Die Verwendung import numpy.sin as np_sin als zusätzliche Option für Benutzer/Entwickler sollte die aktuelle Codebasis nicht beeinflussen.
Die einzige Sorge betrifft nur die Exposé-Funktion/Schnittstelle.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

tkoolen picture tkoolen  ·  3Kommentare

Keno picture Keno  ·  3Kommentare

wilburtownsend picture wilburtownsend  ·  3Kommentare

i-apellaniz picture i-apellaniz  ·  3Kommentare

dpsanders picture dpsanders  ·  3Kommentare