이름공간

**이름공간** 또는 **네임스페이스**()는 다양한 종류의 객체를 식별하고 참조하는 데 사용되는 일련의 기호(이름)이다. 이름공간은 주어진 객체 집합의 모든 객체가 고유한 이름을 갖도록 하여 쉽게 식별될 수 있도록 한다.

이름공간은 일반적으로 다른 컨텍스트에서 이름의 재사용을 허용하기 위해 계층적으로 구성된다. 비유를 들자면, 각 사람이 주어진 이름과 친척들과 공유하는 성을 가지고 있는 사람 이름 지정 시스템을 생각해보자. 만약 가족 구성원의 이름이 각 가족 내에서만 고유하다면, 각 사람은 이름과 성의 조합으로 고유하게 식별될 수 있다. 제인이라는 이름의 사람은 많을 수 있지만 제인 도우는 한 명뿐이다. 도우 가족의 이름공간 내에서는 "제인"만으로도 이 사람을 명확하게 지정하기에 충분하지만, 모든 사람의 "글로벌" 이름공간 내에서는 전체 이름을 사용해야 한다.

이름공간의 대표적인 예로는 파일에 이름을 할당하는 파일 시스템이 있다.
일부 프로그래밍 언어는 변수와 서브루틴을 이름공간에 조직한다.
컴퓨터 망 및 분산 시스템은 컴퓨터, 프린터, 웹사이트 및 원격 파일과 같은 리소스에 이름을 할당한다. 운영체제는 가상화 컨테이너를 지원하기 위해 격리된 이름공간으로 커널 리소스를 분할할 수 있다.

마찬가지로 디렉토리는 파일을 계층적으로 구성한다. 각 디렉토리는 별도의 이름공간이므로 "letters"와 "invoices" 디렉토리 모두 "to_jane" 파일을 포함할 수 있다.

컴퓨터 프로그래밍에서 이름공간은 일반적으로 특정 기능 주위에 기호와 식별자를 그룹화하고 동일한 이름을 공유하는 여러 식별자 간의 이름 충돌을 피하기 위해 사용된다.

네트워킹에서 도메인 네임 시스템은 웹사이트(및 기타 리소스)를 계층적 이름공간으로 구성한다.

## 이름 충돌
요소 이름은 개발자가 정의한다. 이는 다른 XML 응용 프로그램의 XML 문서를 혼합하려고 할 때 종종 충돌을 초래한다.

이 XML은 HTML 표 정보를 담고 있다.

```xml
<table>
    <tr>
        <td>Good</td>
        <td>Bad</td>
    </tr>
</table>
```

이 XML은 탁자 (즉, 가구 조각)에 대한 정보를 담고 있다.

```xml
<table>
    <name>Mahogany Coffee Table</name>
    <width>30</width>
    <length>120</length>
</table>
```


이 XML 조각들을 함께 추가하면 이름 충돌이 발생한다. 둘 다  요소를 포함하지만, 요소는 다른 내용과 의미를 갖는다.

XML 파서는 이러한 차이점을 처리하는 방법을 알지 못할 것이다.

### 접두사를 통한 해결
XML의 이름 충돌은 이름 접두사를 사용하여 쉽게 피할 수 있다.

다음 XML은 요소 시작 부분에 "h"와 "f"를 접두사로 붙여 HTML 테이블 정보와 가구 정보를 구별한다.


```xml
<h:table>
    <h:tr>
        <h:td>Good</h:td>
        <h:td>Bad</h:td>
    </h:tr>
</h:table>

<f:table>
    <f:name>Mahogany Coffee Table</f:name>
    <f:width>30</f:width>
    <f:length>120</f:length>
</f:table>
```


## 명명 시스템
이름공간의 이름은 이름공간 이름과 로컬 이름으로 구성된다. 이름공간 이름은 일반적으로 로컬 이름의 접두사로 적용된다.

확장 배커스-나우르 표기법으로:

```abnf
name = <namespace name> separator <local name>
```

로컬 이름이 단독으로 사용될 때, 이름 해결은 특정 로컬 이름이 어떤 (있는 경우) 특정 이름을 지칭하는지 결정하는 데 사용된다.

### 예시

### 위임
책임의 위임은 월드 와이드 웹의 구조와 같은 실제 응용 프로그램에서 중요하다. 이름공간은 글로벌 고유성을 유지하면서 여러 이름 발행 기관에 식별자 할당을 위임할 수 있도록 한다. 중앙 등록 기관은 할당된 이름공간 이름을 등록한다. 각 이름공간 이름은 해당 이름공간 내에서 이름 할당을 담당하는 조직에 할당된다. 이 조직은 이름을 직접 할당하는 이름 발행 조직이거나, 이름공간의 일부를 다른 조직에 추가로 위임하는 다른 등록 기관일 수 있다.

### 계층 구조
이름공간의 하위 위임을 제3자에게 허용하는 명명 체계를 **계층적 이름공간**이라고 한다.

이름공간 이름의 구문이 각 하위 위임에 대해 동일하면 계층 구조는 재귀적이다. 재귀적 계층 구조의 예는 도메인 네임 시스템이다.

비재귀적 계층 구조의 예는 IANA 번호를 나타내는 URN이다.

### 이름공간 대 스코프
이름공간 이름은 이름에 컨텍스트(스코프 in 컴퓨터 과학)를 제공할 수 있으며, 이 용어는 때때로 상호 교환적으로 사용된다. 그러나 이름의 컨텍스트는 이름이 나타나는 위치나 이름의 구문과 같은 다른 요소에 의해서도 제공될 수 있다.

## 프로그래밍 언어에서

많은 프로그래밍 언어에서 이름공간은 식별자의 컨텍스트이다. 운영 체제에서 이름공간의 예는 디렉토리이다. 디렉토리의 각 이름은 하나의 파일 또는 하위 디렉토리를 고유하게 식별한다.

일반적으로 이름공간의 이름은 두 가지 이상의 의미를 가질 수 없다. 즉, 다른 의미는 동일한 이름공간에서 동일한 이름을 공유할 수 없다. 이름공간은 또한 컨텍스트라고도 불린다. 왜냐하면 다른 이름공간의 동일한 이름이 다른 의미를 가질 수 있으며, 각 의미는 해당 이름공간에 적합하기 때문이다.

이름공간의 다른 특징들은 다음과 같다.
* 이름공간의 이름은 객체뿐만 아니라 개념도 나타낼 수 있으며, 이름공간은 자연어 또는 민족 언어, 인공어, 직업의 전문 용어, 방언, 사회방언 또는 인공 언어(예: 프로그래밍 언어)가 될 수 있다.
* 자바 프로그래밍 언어에서 이름공간에 나타나는 식별자는 이름공간 외부에서 사용하기 위한 짧은 (로컬) 이름과 고유한 긴 "정규화된" 이름을 갖는다.
* 일부 컴파일러(C++와 같은 언어의 경우)는 네임 맹글링이라는 프로세스에서 컴파일러 내부 사용을 위해 이름공간과 이름을 결합한다.

위에서 설명한 추상적인 언어 기술적 용법 외에도, 일부 언어는 다른 용도 중에서 명시적 이름공간 제어를 위한 특정 키워드를 가지고 있다. 다음은 C++ 이름공간의 예이다.


```cpp
import std;

// This is how one brings a name into the current scope.  In this case, it's
// bringing them into global scope.
using std::println;

namespace box1 {
    constexpr int BOX_SIDE = 4;
}

namespace box2 {
    constexpr int BOX_SIDE = 12;
}

int main() {
    constexpr int BOX_SIDE = 42;
    println("{}", box1::BOX_SIDE);  // Outputs 4.
    println("{}", box2::BOX_SIDE);  // Outputs 12.
    println("{}", BOX_SIDE);  // Outputs 42.
}
```


### 컴퓨터 과학적 고려사항
컴퓨터 과학에서 이름공간(때로는 **이름 스코프**라고도 함)은 고유한 식별자 또는 상징 (즉, 이름)의 논리적 그룹화를 담기 위해 생성된 추상적인 컨테이너 또는 환경이다. 이름공간에 정의된 식별자는 해당 이름공간과만 연관된다. 동일한 식별자는 여러 이름공간에 독립적으로 정의될 수 있다. 즉, 한 이름공간에 정의된 식별자는 다른 이름공간에 정의된 동일한 식별자와 동일한 의미를 가질 수도 있고 가지지 않을 수도 있다. 이름공간을 지원하는 언어는 식별자가 (정의가 아닌) 어떤 이름공간에 속하는지 결정하는 규칙을 지정한다.

이 개념은 비유로 설명할 수 있다. 두 회사 X와 Y가 각각 직원에게 ID 번호를 할당한다고 가정해 보자. X는 동일한 ID 번호를 가진 두 명의 직원을 가질 수 없으며, Y도 마찬가지이다. 그러나 동일한 ID 번호가 두 회사 모두에서 사용되는 것은 문제가 되지 않는다. 예를 들어, 빌이 회사 X에서 일하고 제인이 회사 Y에서 일한다면, 각각 직원 번호 #123을 사용하는 것은 문제가 되지 않는다. 이 비유에서 ID 번호는 식별자이고, 회사는 이름공간 역할을 한다. 동일한 식별자가 각 이름공간에서 다른 사람을 식별하는 것은 문제를 일으키지 않는다.

대규모 컴퓨터 프로그램이나 문서에는 수백 또는 수천 개의 식별자가 있는 것이 일반적이다. 이름공간(또는 유사한 기술, 이름공간 에뮬레이션 참조)은 로컬 식별자를 숨기는 메커니즘을 제공한다. 이들은 논리적으로 관련된 식별자를 해당 이름공간으로 그룹화하는 수단을 제공하여 시스템을 더욱 모듈화한다.

데이터 저장 장치와 많은 현대 프로그래밍 언어는 이름공간을 지원한다. 저장 장치는 디렉토리(또는 폴더)를 이름공간으로 사용한다. 이를 통해 동일한 이름을 가진 두 개의 파일이 다른 디렉토리에 저장되는 한 장치에 저장될 수 있다. 일부 프로그래밍 언어(예: C++, 파이썬)에서는 이름공간을 명명하는 식별자 자체가 둘러싸는 이름공간과 연관된다. 따라서 이러한 언어에서는 이름공간이 중첩되어 이름공간 트리를 형성할 수 있다. 이 트리의 루트에는 이름 없는 **전역 이름공간**이 있다.

#### 공통 언어에서의 사용
##### C
C에서는 C99부터 익명 구조체를 이름공간으로 사용할 수 있다.

:

```c
#pragma once

const struct {
    double PI;
    double (*sin)(double);
} Math;
```


:

```c
#include <math.h>

static double _sin(double arg) {
    return sin(arg);
}

const struct {
    double PI;
    double (*sin)(double);
} Math = { M_PI, _sin };
```


:

```c
#include <stdio.h>
#include "Math.h"

int main() {
    printf("sin(0) = %d\n", Math.sin(0));
    printf("pi is %f\n", Math.PI);
}
```


##### C++
C++에서 이름공간은 이름공간 블록으로 정의된다.

```cpp
namespace abc {
    int bar;
}
```

이 블록 내에서는 식별자를 선언된 대로 정확히 사용할 수 있다. 이 블록 외부에서는 이름공간 지정자를 접두사로 붙여야 한다. 예를 들어, `namespace abc` 외부에서 `bar`를 액세스하려면 `abc::bar`로 작성해야 한다. C++는 이러한 장황함을 불필요하게 만드는 또 다른 구문을 포함한다.

```cpp
using namespace abc;
```

라인을 코드에 추가하면 접두사 `abc::`가 더 이상 필요하지 않다.

명시적으로 이름공간 내에서 선언되지 않은 식별자는 전역 이름공간에 있다고 간주된다.

```cpp
int foo;
```

이러한 식별자는 선언된 대로 정확히 사용할 수 있거나, 전역 이름공간은 이름이 없으므로 이름공간 지정자 `::`를 접두사로 붙일 수 있다. 예를 들어, `foo`는 `::foo`로도 작성할 수 있다.

C++의 이름공간 해결은 계층적이다. 이는 가상의 이름공간 `food::soup` 내에서 식별자 `Chicken`이 `food::soup::Chicken`을 참조함을 의미한다. 만약 `food::soup::Chicken`이 존재하지 않으면, `food::Chicken`을 참조한다. `food::soup::Chicken`도 `food::Chicken`도 존재하지 않으면, `Chicken`은 전역 이름공간의 식별자인 `::Chicken`을 참조한다.

C++에서 이름공간은 이름 충돌을 피하기 위해 가장 자주 사용된다. 이름공간은 최근 C++ 코드에서 광범위하게 사용되지만, 초기 버전의 언어에는 존재하지 않았기 때문에 대부분의 오래된 코드는 이 기능을 사용하지 않는다. 예를 들어, C++ 표준 라이브러리 전체는 `namespace std` 내에 정의되어 있지만, 표준화 이전에는 많은 구성 요소가 원래 전역 이름공간에 있었다. `using` 문을 사용하여 현재 스코프에 기호를 가져올 수 있다.

역호환성 이외의 이유(예: 편의성)로 헤더에서 `using` 문을 사용하는 것은 좋은 코딩 관행에 어긋나는 것으로 간주된다. 왜냐하면 이러한 `using` 문은 해당 헤더를 포함하는 모든 번역 단위로 전파되기 때문이다. 그러나 모듈은 명시적으로 `export`로 표시되지 않는 한 `using` 문을 내보내지 않으므로 `using` 문을 더 안전하게 사용할 수 있다. 예를 들어, `org.wikipedia.project.util` 모듈을 일치하는 이름공간 `org::wikipedia::project::util`로 가져온 다음 해당 이름공간의 기호에 `using` 문을 사용하여 장황한 이름공간을 단순화할 수 있다. Java 또는 Rust와 같은 다른 언어와 달리 C++ 모듈, 이름공간 및 소스 파일 구조는 반드시 일치하지는 않지만, 명확성을 위해 일치시키는 것이 관례이다(예: 모듈 `abc.def.uvw.XYZ`는 이름공간 클래스 `abc::def::uvw::XYZ`와 일치하며 파일 `abc/def/uvw/XYZ.cppm`에 상주한다).

모듈식 번역 단위를 사용할 때는 `using`을 사용하여 장황하게 중첩된 이름공간을 단순화해야 한다.


```cpp
export module org.wikipedia.project.App;

import std;

import org.wikipedia.project.fs;
import org.wikipedia.project.util;

using org::wikipedia::project::fs::File;
using org::wikipedia::project::util::ConfigLoader;
using org::wikipedia::project::util::logging::Logger;
using org::wikipedia::project::util::logging::LoggerFactory;

export namespace org::wikipedia::project {

class App {
private:
    Logger logger;
    // private fields and methods
public:
    App():
        logger{LoggerFactory::getLogger("Main")} {
        ConfigLoader cl(File("config/config_file.txt"));
        logger.log("Application starting...");
        // rest of code
    }
};

}
```


C++11은 인라인 이름공간을 도입했는데, 이는 해당 멤버가 둘러싸는 이름공간의 멤버인 것처럼 취급된다. 이는 `inline namespace`를 작성하여 선언된다. 이는 암시적인 `using namespace` 문과 유사하여, 기호의 한정자는 선택 사항이다.

인라인 속성은 전이적이다. 이름공간 `a`가 인라인 이름공간 `b`를 포함하고, `b`가 다시 다른 인라인 이름공간 `c`를 포함하면, `c`의 멤버는 `a` 또는 `b`의 멤버인 것처럼 접근할 수 있다.

인라인 이름공간의 주요 사용 사례는 ABI 호환성 및 버전 관리이다. API의 다른 버전을 별개의 인라인 이름공간(예: `v1`, `v2`)에 배치한 다음 현재 원하는 버전을 인라인으로 만들면 라이브러리 개발자는 ABI 호환성을 관리할 수 있다. 새 버전이 릴리스되면 인라인 키워드를 새 버전의 이름공간으로 이동하여 사용자가 새 버전과 자동으로 연결되도록 하면서 명시적 한정자를 통해 이전 버전에 액세스할 수 있도록 한다.


```c++
namespace mylib::utils {
    namespace v1 {
        void func() {
            // Old implementation
        }
    }

    // v2 is the currently active version
    inline namespace v2 {
        void func() {
            // New implementation
        }
    }
}

int main() {
    // Calls mylib::utils::v2::func() implicitly
    mylib::utils::func();

    // Calls mylib::utils::v2::func() explicitly
    mylib::utils::v2::func();

    // Calls mylib::utils::v1::func() explicitly
    mylib::utils::v1::func();

    return 0;
}
```


##### C#
이름공간은 C# 언어에서 많이 사용된다. 모든 닷넷 프레임워크 클래스는 더 명확하게 사용하고 혼란을 피하기 위해 이름공간으로 구성되어 있다. 또한 프로그래머는 자신의 작업을 구성하고 이름 충돌을 피하기 위해 사용자 정의 이름공간을 광범위하게 사용한다.
클래스를 참조할 때는 이름공간 뒤에 클래스 이름이 오는 완전 정규화된 이름을 지정해야 한다.

```c#
System.Console.WriteLine("Hello World!");
int i = System.Convert.ToInt32("123");
```


또는 `using` 문을 추가한다. 이렇게 하면 해당 이름공간의 모든 클래스 이름을 완전히 언급할 필요가 없다.


```c#
using System;

Console.WriteLine("Hello World!");
int i = Convert.ToInt32("123");
```


위 예제에서 `System`은 이름공간이고, `Console`과 `Convert`는 `System` 내에 정의된 클래스이다.

<code>Console</code> 및 <code>Convert</code> 클래스를 포함하는 UML 다이어그램.

C++와 달리, `using`은 이름공간의 모든 기호만 가져올 수 있다(C++의 `using namespace`, Rust의 `use *`, Java의 `import *`와 매우 유사하다). Java에서 사용되는 것처럼 개별 기호와 클래스를 가져오는 데 사용할 수 없다.


```c#
namespace Wikipedia.Project;

using System;
using System.IO;

using Microsoft.Extensions.Logging;

using Wikipedia.Project.Utility;

class App
{
    private static ILogger<Program> logger;

    public App()
    {
        ConfigLoader cl = new ConfigLoader(Path.Combine("config", "config_file.txt"));
        LoggerFactory loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.AddConsole();
        });
        logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Application starting...");
        // rest of code
    }
}
```


C++와 달리 C# 이름공간은 기호의 상대적 참조를 허용하지 않는다. 예를 들어, `Foo.Bar` 이름공간 내에서 참조되더라도 `Foo.Bar.Baz.Qux` 클래스를 `Baz.Qux`로 참조할 수 없다. `Qux` 클래스를 참조하려면 `Foo.Bar.Baz` 이름공간을 가져오거나 `Foo.Bar.Baz.Qux`를 완전 정규화해야 한다.

##### 자바
자바에서 이름공간의 개념은 자바 패키지에 구현되어 있다. 모든 코드는 패키지에 속하며, 해당 패키지는 명시적으로 이름이 지정될 필요는 없다. 다른 패키지의 코드는 적절한 식별자 앞에 패키지 이름을 붙여 액세스한다. 예를 들어, `package [[java.lang]]`의 `class String`은 `java.lang.String`으로 참조될 수 있다(완전 정규화된 클래스 이름으로 알려져 있다). C++와 마찬가지로 자바는 패키지 이름을 입력할 필요가 없도록 하는 구문(`import`)을 제공한다. 그러나 특정 기능(리플렉션 등)은 프로그래머가 완전 정규화된 이름을 사용하도록 요구한다.

C++와 달리, 자바의 이름공간은 언어의 구문 측면에서는 계층적이지 않다. 그러나 패키지는 계층적인 방식으로 이름이 지정된다. 예를 들어, `java`로 시작하는 모든 패키지는 자바 플랫폼의 일부이다.  패키지에는 언어의 핵심 클래스가 포함되어 있으며,  패키지에는 특히 리플렉션과 관련된 핵심 클래스가 포함되어 있다.

자바(및 에이다, C# 등)에서 이름공간/패키지는 코드의 의미적 범주를 표현한다. 예를 들어, C#에서 `namespace System`은 시스템(닷넷 프레임워크)에서 제공하는 코드를 포함한다. 이러한 범주의 구체성과 계층 구조의 깊이는 언어마다 다르다.

함수와 클래스 스코프는 가시성, 접근성 및 객체 생명주기와 불가분의 관계를 갖는 암시적 이름공간으로 볼 수 있다.

자바에서는 C++에서처럼 패키지를 부분적으로 한정할 수 없다. 예를 들어, `java` 이름공간을 가져온 다음 `java.util.ArrayList`를 `util.ArrayList`로 참조하는 것은 불가능하다. 기호는 완전 정규화되거나 스코프에 완전히 가져와야 한다. `import` 문은 C++에서처럼 전이적이지 않으며 의도적으로 `export`로 표시할 수도 없다. 모든 `import` 문은 파일 시작 부분에 나타나야 하며, 다른 스코프에는 작성할 수 없다. 이는 C++와 대조적이다. C++에서는 
```cpp
using namespace std;
```
를 작성하여 `std` 이름공간을 가져온 다음 `std::chrono::system_clock`을 `chrono::system_clock`으로 참조할 수 있다.


```java
package org.wikipedia.project;

import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.wikipdia.project.util.ConfigLoader;

public class App {
    private static final Logger logger = Logger.getLogger(Main.class.getName());

    public App() {
        ConfigLoader cl = new ConfigLoader(Paths.get("config/config_file.txt"));
        logger.log(Level.INFO, "Application starting...");
        // rest of code
    }
}
```


자바는 클래스 외부의 독립적인 함수를 지원하지 않으므로, 정적 클래스 메서드와 소위 "유틸리티 클래스"(private 생성자와 모든 메서드 및 필드가 정적인 클래스)는 C++ 스타일 이름공간과 동일하다. 예를 들어, `Math.PI`와 같은 상수와 `Math.sin()`과 같은 메서드를 포함하는 `java.lang.Math`가 있다.

`import` 문은 패키지의 모든 기호를 가져오는 데 사용할 수 있으며, 이를 전역 가져오기라고 하며 C++의 `using namespace`와 유사하다. 예를 들어, 
```java
import java.util.*;
```
를 작성하면 `java.util` 패키지의 모든 클래스를 가져온다. 그러나 이는 파일 내에서 기호 오염을 유발할 수 있다. 또한, 동일한 이름을 가진 클래스를 포함하는 패키지에 전역 가져오기 문을 사용하면 모호성이 발생하여 컴파일에 실패할 수 있다. 하지만 `java.lang.*`는 기본적으로 모든 자바 소스 파일에 암시적으로 가져와진다.


```java
import java.sql.*; // Imports all classes in java.sql, including java.sql.Date
import java.util.*; // Imports all classes in java.util, including java.util.Date

Date d = new Date(); // Ambiguous Date reference resulting in compilation error

// Instead, the fully-qualified names must be used:
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());
java.util.Date utilDate = new java.util.Date();
```


##### PHP
PHP 버전 5.3부터 이름공간이 도입되었다. 클래스, 함수 및 변수의 이름 충돌을 피할 수 있다.
PHP에서 이름공간은 이름공간 블록으로 정의된다.

```php
# File phpstar/foobar.php

namespace phpstar;

class FooBar
{
    public function foo(): void
    {
        echo 'Hello world, from function foo';
    }

    public function bar(): void
    {
        echo 'Hello world, from function bar';
    }
}
```

PHP 이름공간을 참조하는 방법은 다음과 같이 다양하다.

```php
# File index.php

# Include the file
include "phpstar/foobar.php";

# Option 1: directly prefix the class name with the namespace
$obj_foobar = new \phpstar\FooBar();

# Option 2: import the namespace
use phpstar\FooBar;
$obj_foobar = new FooBar();

# Option 2a: import & alias the namespace
use phpstar\FooBar as FB;
$obj_foobar = new FB();

# Access the properties and methods with regular way
$obj_foobar->foo();
$obj_foobar->bar();
```


클래스 FooBar를 포함하는 phpstar 패키지의 UML 다이어그램.

##### 파이썬
파이썬에서 이름공간은 개별 모듈에 의해 정의되며, 모듈은 계층적 패키지에 포함될 수 있으므로 이름공간 또한 계층적이다.
일반적으로 모듈이 임포트되면 모듈에 정의된 이름은 해당 모듈의 이름공간을 통해 정의되며, 완전 정규화된 이름을 사용하여 호출 모듈에서 액세스된다.

```python
# assume ModuleA defines two functions : func1() and func2() and one class : Class1
import ModuleA

ModuleA.func1()
ModuleA.func2()
a: ModuleA.Class1 = Modulea.Class1()
```


`from ... import ...` 문을 사용하여 관련 이름을 호출 모듈의 이름공간에 직접 삽입할 수 있으며, 이러한 이름은 정규화된 이름 없이 호출 모듈에서 액세스할 수 있다.

```python
# assume ModuleA defines two functions : func1() and func2() and one class : Class1
from ModuleA import func1

func1()
func2() # this will fail as an undefined name, as will the full name ModuleA.func2()
a: Class1 = Class1() # this will fail as an undefined name, as will the full name ModuleA.Class1()
```

이는 이름을 직접(정규화 없이) 가져오므로 기존 이름을 경고 없이 덮어쓸 수 있다.

특수한 형태의 문은 `from ... import *`인데, 이는 이름 지정된 패키지에 정의된 모든 이름을 호출 모듈의 이름공간에 직접 가져온다. 이 형태의 가져오기 사용은 언어 내에서 지원되지만, 호출 모듈의 이름공간을 오염시키고 이름 충돌 시 이미 정의된 이름을 덮어쓰기 때문에 일반적으로 권장되지 않는다. 하지만 파이썬에서 `from import`를 사용하면 중첩된 이름공간과 같이 장황한 이름공간을 단순화할 수 있다.


```python
from selenium.webdriver import Firefox
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement

if __name__ == "__main__":
    driver: Firefox = Firefox()
    element: WebElement = driver.find_element(By.ID, "myInputField")
    element.send_keys(f"Hello World{Keys.ENTER}")
    action: ActionChains = ActionChains(driver)
    action.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
```


파이썬은 호출 모듈에서 사용할 별칭 또는 대체 이름을 제공하는 방법으로 `import x as y`도 지원한다.


```numpy
import numpy as np
from numpy.typing import NDArray, float32

a: NDArray[float32] = np.arange(1000)
```


##### 러스트
러스트에서 이름공간은 "모듈"이라고 불리며 `mod`를 사용하여 선언된다. 모듈 내의 기호는 기본적으로 비공개이며, `pub` 키워드로 선언하여 노출하지 않는 한 외부에서 접근할 수 없다. 모듈은 내부에 하위 모듈을 가질 수 있어 중첩된 이름공간을 허용한다.

C++의 `using` 키워드와 유사하게, 러스트는 `use` 키워드를 사용하여 현재 스코프에 기호를 가져온다.

```rust
mod my_module {
    pub trait Greet {
        fn greet(&self);
    }

    pub struct Person {
        pub name: String,
    }

    impl Greet for Person {
        fn greet(&self) {
            println!("Hello, {}!", self.name);
        }
    }
}

fn main() {
    use my_module::{Person, Greet};

    let person = Person { name: String::from("Alice") };
    person.greet();
}
```



```rust
mod util;
```
을 작성하면 컴파일러에게 `util.rs` 또는 `util/mod.rs`라는 파일을 찾도록 지시한다. `use` 문에서 `crate`는 현재 "크레이트"(프로젝트)의 루트를 참조하며, `super`는 부모 모듈을 참조하는 데 사용할 수 있다.


```rust
mod util;

use std::fs::File;

use crate::util::ConfigLoader;
use crate::util::logging::{Logger, LoggerFactory};

pub struct App {
    config_loader: ConfigLoader;
}

impl App {
    pub fn new() -> Self {
        config_loader = ConfigLoader::new(File::open("config/config_file.txt"));
        config_loader.load();
        let logger: Logger = LoggerFactory::get_logger("Main");
        logger.log("Application starting...");
        // rest of code
    }
}
```


러스트의 `use` 키워드는 C++의 `using`보다 더 다재다능하다. 단일 기호 가져오기, `as`를 사용한 기호 별칭 지정 및 전역 가져오기 외에도 `use`는 중괄호(중첩될 수 있음)를 사용하여 같은 줄에서 여러 기호를 가져오고, 개별 이름공간을 가져오며, 이 모든 것을 단일 문으로 수행할 수 있다. 다음은 위에서 언급한 모든 것을 사용하는 예이다.


```rust
use std::{
    fmt::*, // imports all symbols in std::fmt
    fs::{File, Metadata}, // imports std::fs::File and std::fs::Metadata
    io::{prelude::*, BufReader, BufWriter} // imports all symbols in std::io::prelude::*, std::io::BufReader, and std::io::BufWriter
    process, // imports the std::process namespace (for example std::process::Command can be referred to as process::Command)
    time // imports the std::time namespace
};
```


##### XML 이름공간

XML에서 XML 이름공간 사양은 XML 문서의 요소 및 속성 이름이 고유하도록 허용하며, 이는 프로그래밍 언어의 이름공간 역할과 유사하다. XML 이름공간을 사용하면 XML 문서에 둘 이상의 XML 어휘에서 온 요소 또는 속성 이름이 포함될 수 있다.

##### SAP 이름공간

SAP 시스템(특히 ABAP 환경)에서 이름공간은 표준 SAP 제공 개체와 고객 또는 파트너 개발 간의 이름 충돌을 방지하는 데 사용된다.

이름공간 식별자는 “/”로 구분(예: `/MYNS/`)되며 SAP의 이름공간 등록 프로세스를 통해 예약된다. 일단 예약되면 해당 이름공간에서 생성된 개체는 고유하게 식별될 수 있으며 SAP 업그레이드 또는 가져오기로 인한 의도하지 않은 덮어쓰기로부터 보호된다.

최신 SAP 환경(예: 클라우드 및 HDI 컨테이너의 ABAP)에서는 이름공간이 개발 아티팩트 또는 번들을 의미적으로 그룹화하는 데도 사용된다.

### 이름공간 에뮬레이션
이름공간에 대한 언어 지원이 없는 프로그래밍 언어에서는 식별자 명명 규칙을 사용하여 어느 정도 이름공간을 에뮬레이션할 수 있다. 예를 들어, C 라이브러리인 Libpng는 노출된 인터페이스의 모든 함수 및 변수에 고정된 접두사를 사용하는 경우가 많다. Libpng는 다음과 같은 식별자를 노출한다.

 png_create_write_struct
 png_get_signature
 png_read_row
 png_set_invalid

이러한 명명 규칙은 식별자가 고유하며 이름 충돌 없이 더 큰 프로그램에서 사용될 수 있음을 합리적으로 보장한다. 마찬가지로 포트란으로 작성된 많은 패키지(예: BLAS, LAPACK)는 함수의 이름의 처음 몇 글자를 예약하여 함수가 속한 그룹을 나타낸다.

이 기술에는 몇 가지 단점이 있다.
* 중첩된 이름공간에는 잘 확장되지 않는다. 모든 식별자 사용이 완전 이름공간 한정되어야 하므로 식별자가 지나치게 길어진다.
* 개인 또는 조직이 일관되지 않은 명명 규칙을 사용하여 원치 않는 난독화를 초래할 수 있다.
* 식별자가 선언된 이름공간을 기반으로 하는 식별자 그룹에 대한 복합 또는 "쿼리 기반" 작업은 다루기 어렵거나 불가능해진다.
* 식별자 길이가 제한된 언어에서는 접두사 사용이 함수가 수행하는 작업을 식별하는 데 사용할 수 있는 문자 수를 제한한다. 이는 FORTRAN 77로 원래 작성된 패키지에 특히 문제가 된다. FORTRAN 77은 식별자당 6자만 제공했다. 예를 들어, BLAS 함수 `DGEMM`의 이름은 이 함수가 이중 정밀도 부동 소수점 숫자(`D`)와 일반 행렬(`GE`)에서 작동하며, 마지막 두 문자(`MM`)만이 실제로 수행하는 작업인 행렬-행렬 곱셈을 보여준다.

또한 몇 가지 장점도 있다.
* 소스 코드 파일에서 이름을 찾는 데 특별한 소프트웨어 도구가 필요하지 않다. Grep과 같은 간단한 프로그램이면 충분하다.
* 이름공간 관련 이름 충돌이 없다.
* 네임 맹글링이 필요 없으므로 잠재적인 비호환성 문제가 없다.

## 같이 보기
* 디지털 객체 식별자 (DOI)
* IP 주소
* 학명
* 듀이 십진분류법
* 도메인 네임 시스템
* 미국의회도서관 분류법
* 성표

## 각주

분류:프로그래밍 구성체