이 글의 작성자는 C/C++ 프로그래밍을 하던 사람이다. 이 글은 Python을 복습하며 작성하는 글이니, 부족한 부분이 있으면 얼마든지 피드백을 주시기 바란다.

 

네임스페이스(namespace)

다음 코드를 살펴보자.

def hello():
    a = 3
    print(a)

a = 5
print(a)
hello()
print(a)

a라는 변수가 보인다. hello 함수에서도 a에 값을 대입하고 있고, 함수 밖에서도 a에 값을 대입하고 있다. 처음으로 a에 들어가는 값은 5가 될 것 같다. 그리고 hello 함수에서 a의 값이 3으로 바뀔 것 같다.
얼핏 봐서는 5, 3, 3순으로 출력이 될 것 같다. 한번 실행해보자.

5
3
5

생각과는 다르게 마지막에 5가 출력된다. hello 함수에서 a를 3으로 바꿔준 것 같은데, 왜 다시 5로 돌아온 것일까?

결론부터 말하자면, hello 함수 안의 a와 밖의 a코드 상에서의 이름만 같은 다른 변수다. hello 함수의 a와 함수 밖의 a다른 네임스페이스에 들어있기 때문이다.
그러면 네임스페이스라는게 뭘까?

 

간단하게 이야기하면 이름을 모아두는 곳이다. 변수를 선언하는 것은 곧 객체의 이름을 짓는 것이고, 지어진 이름은 네임스페이스로 들어가게 된다.

hello 함수 안의 a와 함수 밖의 a는 다른 네임스페이스에 들어있다고 했다. 그러면 네임스페이스가 어떻게 구성되어 있길래 저 둘은 다른 네임스페이스에 들어가있다고 말하는 것일까?

총 3종류의 네임 스페이스를 알아볼 것이다.

namespace

 

빌트인 네임스페이스 (Built-in namespace)

Python 인터프리터에서 사용하는 네임스페이스이다. Python에서 기본적으로 지원하고 있는 기능들에 대한 이름이 여기에 포함되어 있다. print()나 id()가 여기에 포함된다.

Python 인터프리터가 실행되면 바로 생성되는 이름들이며, 인터프리터가 종료될 떄 까지 계속 남는다.

빌트인 네임스페이스에 들어있는 이름들은 어디서나 볼 수 있는 이름이다.

그리고 다른 네임스페이스에서는 빌트인 네임스페이스에 있는 이름을 절대로 사용할 수 없다.

 

전역(글로벌) 네임스페이스 (Global namespace)

Python 모듈에서 사용하는 네임스페이스이다. ‘모듈이 뭐야?’라는 의문이 들 수 있는데, 하나의 py코드이라고 생각하면 된다.

인터프리터가 실행하고자 하는 py코드를 읽었을 때 생성된다. hello.py 코드를 읽어서 하나의 모듈을 불러오면, hello.py를 위한 네임스페이스가 하나 생성되는 것이다.

만약 중간에 hi.py 코드도 읽어 들인다면, hi.py를 위한 네임스페이스도 새롭게 만들어진다.

다른 py 파일을 불러오는 방법은 다음 포스트에서 알아보도록 하자.

만약 hello.py에도 hello()라는 함수가 있고, hi.py에도 hello()라는 함수가 있다면? 둘은 별개의 이름으로 취급된다.

 

지역(로컬) 네임스페이스 (Local namespace)

함수 또는 메서드에서 사용하는 네임스페이스이다. hello() 함수는 hello() 함수만의 지역 네임스페이스를 가지고, 같은 py 코드 안의 hi()함수는 hi() 함수만의 지역 네임스페이스를 가진다.

그리고 특이한 점이 있다면, 전역 네임스페이스의 이름에 접근이 가능하다라는 점이다.
다음 코드는 잘 동작하는 코드이다.

def hello():
    print(a)

a = 3
hello()

hello() 함수에서 a라는 이름을 지어준 적이 없는데도 a를 출력하는 것을 확인할 수 있을것이다.

하지만 다른 지역 네임스페이스에 속한 이름에는 접근할 수 없다. 다음 코드는 작동하지 않는 코드이다.

def hello():
    print(a)

def hi():
    a = 3

hello()

a를 찾을 수 없다는 에러를 확인할 수 있을 것이다.

 

전역과 지역의 이름이 겹쳤을 때는?

그러면 맨 처음 예시를 다시 한 번 살펴보자.

def hello():
    a = 3
    print(a)

a = 5
print(a)
hello()
print(a)

네임스페이스에 대해 생각하면서 이 코드를 보면 hello() 함수가 속한 지역 네임스페이스와 전역 네임스페이스에 각각 a라는 이름이 있다는 것을 알 수 있다. 그러면 hello()에서 볼 수 있는 a란 이름은 두 개가 있다. 어떤 a를 가져다 쓸까?

전역과 지역에 있는 이름이 겹친다면, 지역 네임스페이스를 우선한다. 그래서 hello() 함수의 print(a)에서는 3이 출력되는 것이다. 그리고 전역에 있는 a는 그대로 5가 유지되는 것이다.

 

global

하지만 특정 함수에서 전역에 있는 특정 변수를 조작하고 싶을 때도 있을 것이다. 위의 코드처럼 전역에 있는 a를 3으로 바꾸고 싶어지면 어떻게 해야할까?

지역 네임스페이스에서 명확하게 ‘나는 전역에 있는 특정 변수를 사용하겠어!’ 라는 의지를 나타내고 싶다면, global을 사용하면 된다.

def hello():
    global a
	a = 3
	print(a)

a = 5
print(a)
hello()
print(a)

코드를 위와 같이 변경하면 hello()에서 사용하는 a는 전역의 a가 되고, hello() 함수에서 a의 값을 변경하여도 전역에 있는 a에 영향이 갈 것이다.

다만 이런 방식은 권장하지 않는다. 지금이야 코드가 간단해서 그렇지, 나중에 코드가 복잡해지면 a라는 변수가 어디서 변경 되었는지 찾기 힘들어지게 만드는 원흉이 될 것이다.

 

네임스페이스에 들어있는 이름 확인하기

전역/지역 네임스페이스에 어떤 이름이 무엇을 가리키고 있는지 확인을 할 수 있는 함수가 있다. 바로 globals()locals() 함수다.

이 함수들은 각각 전역/지역 함수의 이름과 객체를 딕셔너리 형태로 돌려준다.

hello() 함수에서 각각 globals()와 locals()의 실행 결과를 출력해보자.

def hello():
    a = 3
    print(globals())
    print(locals())

a = 5
hello()

실행하면 다음과 같은 결과를 얻을 수 있을것이다.

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0174AF58>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python code/proj/hello.py', '__cached__': None, 'hello': <function hello at 0x017D3580>, 'a': 5}
{'a': 3}

지역 네임스페이스 쪽은 간결하게 a에 대해서만 나와있는데, 전역 네임스페이스 쪽에는 뭔가 이상한 것들이 많이 들어있다.

 

네임스페이스는 왜 있는 것인가?

결론부터 말하자면, 프로그래머들이 자신이 작성하는 코드의 이름에만 집중할 수 있도록 도와주기 위해서이다.

지금 작성하는 코드들은 단순히 Python의 기능들을 알아보기 위한 짧은 예제코드들이다. 하지만 실전에 들어간다면, 여러분들이 작성할 코드의 양도 양이지만, 다른 코드들을 가져와야 할 일도 많이 생길 것이다.

네임스페이스가 없다고 치자. 그러면 내가 쓰는 hello라는 이름과 남의 코드의 hello라는 이름을 어떻게 구분할것인가? 남의 코드를 가져다 쓰기 전에 그 코드에는 어떤 이름들이 있는지부터 싹 다 찾아봐서 내가 쓰려고 하는 이름과 겹치지 않게 해야 할 것이다. 물론 그 이름은 한두개가 아닐 것이다.

심지어는 어느정도 작성을 하다가 특정 코드가 필요해졌는데, 하필이면 겹치는 이름이 발생해서 이름을 또 다시 재정의 해야 한다면? 여간 골치아픈 일이 아닐 수 없다.

이름 짓기를 매우 철저하게 해서 hello_mycode_py라는 식으로 이름을 지어버리는 방법도 있겠지만, 네임스페이스가 있으면 사실상 위와 같은 철저한 이름짓기를 네임스페이스가 해 준다고 보면 된다.

그리고 이러한 네임스페이스 개념은 다른 프로그래밍 언어에도 들어있는 개념이니, 잘 기억해두면 다른 언어를 배울 때에도 도움이 될 것이다. (물론 완전히 똑같지는 않을 것이다)

 

Categories:

Updated:

Comments