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")
...
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
(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
import Foo; const Bar = Foo
bietet eine perfekte Lösung, wenn der Benutzer Foo
im Namensraum nicht stört,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.
Hilfreichster Kommentar
dieses Thema gibt es schon länger, auch wenn einige Erweiterungen noch diskutiert werden sollten, die
selbst scheint ziemlich vernünftig.