Wann werden Namen in den globalen Namespace importiert? (mit x :: y, aus x import y etc.)

8

Ich programmiere jetzt seit ungefähr 10 Jahren in verschiedenen Sprachen. Und ich habe immer noch nicht herausgefunden, wann es eine gute Idee ist, etwas in den globalen Namespace zu importieren ( using x::yin C ++, from x import yin Python usw.), also mache ich es kaum jemals.

Es scheint mir fast immer eine schlechte Idee zu sein, schon allein deshalb, weil es die Menge der Variablennamen einschränkt, die ich verwenden kann. Zum Beispiel: Wo ich using namespace std;oder using std::string;in C ++ verwenden soll, konnte ich nicht mehr stringals Variablennamen verwenden, was ich gelegentlich tue (z. B. für String-Dienstprogrammfunktionen).

Aber ich frage mich: Gibt es Situationen, in denen das Importieren eines Namens in den globalen Namespace wirklich Sinn macht? Faustregeln?

Futlib
quelle

Antworten:

11

In C ++ ist es im Allgemeinen verpönt - besonders using namespace std. Dieser stdNamespace hat so viele Namen, von denen viele sehr generische Algorithmen sind, dass Sie einige äußerst böse Überraschungen erleben können, wenn using namespace std. So etwas using std::cout;ist nicht so schlimm. Aber niemals usingetwas in den globalen Namespace einer Header-Datei. Das ist eine Straftat.

DeadMG
quelle
1
Aber was ist mit meiner Frage? Wann mit x :: y verwenden oder x aus y importieren?
Futlib
4

Sie sollten es tun, wenn es Ihren Code vereinfacht. Sie sollten dies nicht tun, wenn dies zu Namenskonflikten führen würde oder wenn es später in Bereiche gebracht werden könnte, in denen Namenskonflikte auftreten würden, z. B. eine Header-Datei.

Einige Leute denken, dass es selten sein sollte. Ich denke , (außerhalb von Header - Dateien) nicht verwenden sollte es selten sein, weil der Namespacepräfix im Allgemeinen keine nützlichen Informationen hinzufügen, wie jemand der vollen Namen man sie anspricht jedes Mal verwenden.

Lassen Sie es mich so sagen. Wenn Sie stringals Klassenname sehen, denken Sie automatisch std::stringoder mycustom::string? Es ist wie das alte Sprichwort. Wenn Sie das Geräusch von Hufen hören, denken Sie an Pferde, nicht an Zebras. Mit anderen Worten, using namespace stdist fast immer keine große Sache. using namespace mycustomist normalerweise auch keine große Sache, es sei denn, es enthält einen Konflikt mit std. In diesem Fall ist Ihr benutzerdefinierter Namespace derjenige, für den Sie immer das Präfix benötigen.

Karl Bielefeldt
quelle
Was passiert, wenn mycustomeine stringKlasse enthalten ist ? Oben du using namespace mycustom;. Durch den Rest des Codes, den Sie jetzt verwenden string. Alle anderen, die den Code lesen, denken, dass std::stringnur Sie (und einige sehr aufmerksame Personen) denken mycustom::string. Hier haben Sie die Zebras in die Pferdekoppel gelegt. Siehe auch stackoverflow.com/q/1452721/14065
Martin York
1
Hast du meinen letzten Satz nicht gelesen? Ich habe ausdrücklich gesagt, wenn mycustomKonflikte mit stdIhnen immer das mycustom::Präfix erfordern sollten .
Karl Bielefeldt
Ich tat. Das Problem ist, dass die meisten Namespaces nicht trivial groß sind. Es ist noch schwieriger, alles in ihnen zu wissen (und zukünftige Versionen des Namespace können erweitert werden). Das Einschließen eines ganzen Namespace ist daher ein Rezept für eine Katastrophe (die Verwendung bestimmter Elemente (innerhalb eines kleinen bestimmten Bereichs ist einfacher zu steuern)). Wenn Ihr Code enthält doStuff(int). Und eine neuere Version von mycustomfügt doStuff(double)dann die gesamte Bedeutung eines Aufrufs zu doStuff(5.5);Änderungen hinzu (möglicherweise ohne dass Sie es bemerken).
Martin York
3

Wenn ich in Python arbeite, verwende ich ständig von x import y (als z), um klare, präzise Namen für Referenzimporte zu haben.

Importe sind in einer Codebasis mit einer tiefen Namespace-Hierarchie von unschätzbarem Wert. Dies gilt insbesondere dann, wenn der Stilstandard für die Codebasis PEP 8 ist , wodurch die Zeilenlänge auf unter 80 Zeichen begrenzt wird.

Betrachten Sie zum Beispiel:

import foo

foo.bar.baz.baf.perform_task(foo.bar.baz.quux.SOME_CONSTANT, foo.bar.alice.bob.preferred_hash_function, '42', foo.bar.magic_numbers.MY_SALT)

Was stattdessen geschrieben werden könnte:

from foo.bar import baf
from foo.bar.alice import bob
from foo.bar.baz.quux import SOME_CONSTANT
from foo.bar.magic_numbers import MY_SALT

baf.perform_task(SOME_CONSTANT, bob.preferred_hash_function, '42', MY_SALT)

Da bei Python-Bezeichnern zwischen Groß- und Kleinschreibung unterschieden wird und die Länge unbegrenzt ist , gehen uns nicht die Namen aus, unabhängig davon, wie viele wir importieren.

Wenn wir in unserem Modul denselben Namen wie eines der Module verwenden möchten, die wir importieren möchten, können wir einen Alias ​​für den Import verwenden:

from foo.bar.alice import bob as carol

def bob(x, y):
    print "running bob function"
    return carol(x, y, 42)
pcurry
quelle
0

Es liegt am Programmierer, wann er es verwenden soll. IMHO ist es besser, sie überhaupt nicht zu verwenden, besonders in Header-Dateien. Aber es gibt mehrere Fälle, in denen ich es benutze

  • Wenn ich etwas in einen anderen Namespace einführen möchte, z

    namespace cg
    {
      namespace details
      {
        //lots of stuff
        void some_cool_foo()
        {
          //uses a lot stuff from details, here because I don't want prefix everything with details::
        }
      }
      using details::some_cool_foo;
    }
  • So aktivieren Sie ADL für einige Algorithmen aus einem anderen Namespace

    namespace n1
    {
    //some general foo
    }
    namespace n2
    {
      using n1::foo;
    //some struct
    }
    namespace n3
    {
      using n1::foo;
    //some struct
    }

Wenn ich keine langen Namen von Namespaces bei .cpp schreiben möchte, kann ich immer einen Alias ​​erstellen

namespace bl = boost::lambda;
namespace fs = boost::filesystem;
kassak
quelle
Entschuldigung, konnte es nicht dazu bringen, meine Quelle hervorzuheben = /
kassak