[python] NameSpace(네임스페이스)

gunny·2024년 4월 11일
0

Python

목록 보기
22/29

Python NameSpace

  • python에서 어떤 것을 객체로 표현할 때, 이 객체들의 데이터 타입으로 나눠보면 문자(string), 숫자(int/float), 불리언(boolean), 리스트(List), 딕셔너리(Dictionary) 등 다양하다.
    그리고 이러한 것에 이름을 지어줄 수 있다.

python_string = 'Python Namespace'
python_number = 0
python_boolean = True
python_list = ['python', 'Namespace']
  • 함수도 객체이므로 위 데이터 타입처럼 명명할 수 있다.
def python_function():
	return 'python function'
    
PythonFunction = python_function
print(python_function())
print(PythonFunction())

#output
python function
python function
  • PythonFunction = python_function 해당 부분은 함수를 호출할 때와 다르게 괄호를 사용하지 않았는데, 이는 함수를 PythonFunction에 할당했다는 의미이다.
def python_function():
	return 'python function'
   
print(python_function)
print(python_function()

#output
<function python_function at 0x107bc1000>
python function

  • 즉, python에서는 모든 것을 객체로 표현하고, 이에 이름을 붙여서 사용한다.

그렇다면 본론으로 와서 python의 NameSpace를 알아보자면, Namespace는 name들의 공간이라고 볼 수 있다.

python 튜토리얼에서는 https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces

네임스페이스는 이름에서 객체로의 매핑입니다.
대부분의 네임스페이스는 현재 Python 사전으로 구현되어 있지만 일반적으로 어떤 방식으로든 눈에 띄지 않으며(성능 제외) 향후 변경될 수 있습니다. 네임스페이스의 예는 다음과 같습니다.
내장 이름 세트(abs() 및 내장 예외 이름과 같은 함수 포함); 모듈의 전역 이름 함수 호출의 로컬 이름. 어떤 의미에서는 객체의 속성 집합도 네임스페이스를 형성합니다.
네임스페이스에 대해 알아야 할 중요한 점은 서로 다른 네임스페이스의 이름 간에는 전혀 관계가 없다는 것입니다.
예를 들어, 두 개의 서로 다른 모듈은 둘 다 혼동 없이 최대화 기능을 정의할 수 있습니다. 모듈 사용자는 모듈 이름 앞에 모듈 이름을 붙여야 합니다.

python의 NameSpace는 '이름(변수명)'과 '객체'를 매핑한 것이라고 볼 수 있다.

python_string = 'Python Namespace'
PythonString = python_string

print(python_string) # Python Namespace
print(PythonString) # Python Namespace

print(id(python_string)) # 4424617056
print(id(PythonString)) # 4424617056
  • 위의 코드에서 보면 python_string, PythonString 이라는 변수를 할당했지만 이들 자체가 '문자'는 아니다. 단순히 문자인 객체를 가르킨다.
    그래서 같은 객체를 다른 변수명으로 참조해도 문제가 되지 않는다.
    같은 namespace에 존재하는 name들이 같은 객체를 가리키고 있는 것이다.
    id(python_string) : 4424617056
    id(PythonString)) : 4424617056

캡슐화(Encapsulation) & 스코핑(scoping)

객체 지향 프로그래밍에서의 캡슐화는 변수, 함수들을 한 클래스에 담는 것이다.
python 관점에서 캡슐화를 살펴보면 namespace와 scope

하나의 python module은 독자적인 namespace를 가진다고 할 때, python module은 같은 이름을 가진 함수를 만들 수 없다.
하지만 namespace를 따로 가지고 있는 python module을 만든다면 같은 이름을 가진 함수를 만들어도 상관없다.

def python_function():
    python_str = 'Python NameSpace'
    print(python_str)
    
python_function()
print(python_str)

#output
Python NameSpace
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/geonheekim/Desktop/python_study/test_1.ipynb Cell 3 line 6
      3     print(python_str)
      5 python_function()
----> 6 print(python_str)

NameError: name 'python_str' is not defined
  • python_string 함수 내에서는 python_str이 참조되지만,
    python_string 함수를 벗어난 밖에서는 python_str을 찾을 수 없다.
    이는 python_str은 python_string 함수의 namespace에서만 존재하고 그 안에서만 사용될 수 있다.
  • python_function 함수 안의 namespace를 local space라고 생각하고 그 밖을 global space라고 보면, 위의 예서는 global space에서 local space에 존재하는 python_str를 찾았기 때문에 에러가 발생한다.
    (global space에서 local space에 접근하는 것은 불가하지만,
    local space에서 global space에 접근하는 것이 가능)
def python_function():
    print(python_str)
    
python_str = 'Python NameSpace~~'
python_function()

예를 들면, python_function에서 python_str을 밖으로 빼놨을 때,
global space로 python_str을 이동시키고, python_function 함수 내에서 python_str을 참조할 때, 잘 참조가 되는 거승ㄹ 볼 수 있다.
local space에서 global space에 접근하는 것은 가능하다.

클래스에서도 MyMac 클래스에 할당한 folders에 접근 할 때
MyMac.folders는 가능하지만 folders는 그냥 접근할 수 없다.
global space에서 folders가 없기 때문이다.

class MyMac:
    def __init__(self):
        self.folders = 10

my_mac = MyMac()
print(MyMac.folders)
print(folders)

#output
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/Users/geonheekim/Desktop/python_study/test_1.ipynb Cell 3 line 6
      3         self.folders = 10
      5 my_mac = MyMac()
----> 6 print(MyMac.folders)
      7 print(folders)

AttributeError: type object 'MyMac' has no attribute 'folders'

LEGB(Local > Encolsing > Global > Built-in)

local space에서는 global space를 참조하지만 반대는 그렇지 않듯이 namespace끼리의 의존관계가 존재하는데 이를 LEGB 라고 줄여서 말한다.
L>E>G>B 이렇게 참조가 가능하다는 것인데,

같은 낮은 레벨은 local, 가장 높은 레벨은 built-in 영역이다.
낮은 레벨의 영역은 위 레벨 영역을 참조할 수 있지만 그 반대는 되지 않는다.
global에서 local을 참조할 수 없듯이, built-in에서는 아무 영역도 접근할 수 없는 것이다.

  • Local : 함수 내에서 할당된 이름
  • Enclosing : 클로져(함수 내 함수)에 할당된 이름
  • Global-to-level-module : python file의 시작점에 할당된 이름
  • Built-in-python : 내장 영역에 할당된 이름(open, import, print, return, Exception)

이다.

python_string = 'python NameSpace'

def return_something(subject):
    result = python_string + subject
    return result

class MyMac:
    folders = 10
    
    def describe_mac(self):
        result_str = str(self.foders) + 'folders'
        return 'There are ' + result + 'on my laptap'
  • Local : subject, result, folders, describe_mac, self, result_str,
  • Enclosing :
  • Global-to-lelvel-module : python_string, return_something, MyMac
  • Built-in-python : def, return, class, return

import

  • python module은 각각의 global namespace를 가지고 있어 한 module 내에서는 같은 이름을 가진 함수를 만들 수 없지만, 다른 module에서는 같은 이름을 지어도 문제가 되지 않는다.
    다른 module을 import 하는 것은 namespace끼리의 참조가 생기는 것이다.
importTest.py

python_string = "python namespace1"
python_number = 1
test.py

import importTest

print(importTest.python_string)
print(importTest.python_number)

#output
python namespace1
1

test.py에서 import importTest를 하면 importTest.py내 존재하는 python_string, python_number에 접근할 수 있지만
바로 python_string, python_number로 사용할 수 없다.
test.py의 Global space에서는 importTest 라는 모듈로 할당된 것이기 때문에 importTest.python_string, importTest.python_number 처럼만 사용 가능하다.

물론 importTest에서 특정한 이름만 가져올 수도 있다.

test.py

from importTest import python_string

print(python_string)
print(python_number)

#output
python namespace1
Traceback (most recent call last):
  File "/Users/geonheekim/Desktop/python_study/test.py", line 4, in <module>
    print(python_number)
NameError: name 'python_number' is not defined

importTest에서 python_string에 바로 접근할 수 없지만
특정 이름만 가져올 경우에는 바로 pythons_string에 접근할 수 있다.

  • 그러나 Global namespace에 바로 이름을 가져오는 방법 있는데,
    from importTest import * 을 사용하는 것이다.
    importTest에 있는 모든 이름을 Global space에 가져오는 방법으로 위에서 importTest.python_string, importTest.python_number 처럼 접근하지 않아도 바로 이름에 접근할 수 있다.
test.py

from importTest import *

print(python_string)
print(python_number)

#output
python namespace1
1

기본적으로 from importTest import *을 통해 importTest에 존재하는 모든 이름을 가져올 수 있지만 이를 제어하는 방법도 있다.

importTest.py

__all__ = ["python_string"]

python_string = "python namespace1"
python_number = 1

위 처럼 __all__ 안에 python_string 만 둔다면 다른 module에서 importTest.py를 import 할때 python_string만 할당시킬 수 있다.

test.py

from importTest import *

print(python_string)
print(python_number)

#output

python namespace1
Traceback (most recent call last):
  File "/Users/geonheekim/Desktop/python_study/test.py", line 4, in <module>
    print(python_number)
NameError: name 'python_number' is not defined

참고 사이트

profile
꿈꾸는 것도 개발처럼 깊게

0개의 댓글