본문 바로가기
파이썬/기초문법

Python namespace에 대한 이해 / Python 네임스페이스

by 행복론자 2020. 4. 15.

 

Python namespace란 무엇이고 왜 필요할까?

 

 

1. Python name?

Python에는 모든 것이 객체로 표현되지만 이 객체들 데이터 타입으로 나눠보면 문자, 숫자, 불리언(Boolean), 리스트 등이 있습니다.

이 모든 것들에 대해 이름을 지어줄 수 있습니다.

예를 들면 아래처럼 문자, 숫자, 불리언, 리스트를 각각 

my_string, my_number, my_boolean, my_list처럼 명명할 수 있습니다. 

my_string  = 'spam and eggs'
my_number  = 42
my_boolean = True
my_list    = ['spam', 'eggs']

 

 

마찬가지로 지난글(2020/04/09 - [Python/Basic] - Python First Class Function 일급 함수)에서 언급한 것처럼 

함수도 객체이므로 위 데이터 타입들처럼 명명할 수 있습니다.

def spam():
    return 'SPAM SPAM SPAM'

eggs = spam

print(spam())  # SPAM SPAM SPAM
print(eggs())  # SPAM SPAM SPAM

 

 

eggs = spam 부분을 보면 함수를 호출 할 때와 다르게 괄호를 사용하지 않았는데 이는 함수를 eggs에 할당했다는 의미입니다. 이 차이를 아는 것이 중요합니다.

def spam():
    return 'SPAM SPAM SPAM'

print(spam)    # <function spam at 0x123456789>
print(spam())  # SPAM SPAM SPAM

 

 

다시 정리하자면 Python에서는 모든 것이 객체이고 이에 이름을 붙여서 사용할 수 있습니다.

 

 

2. Python namespace란? 

Python에서 namespace란 name들의 공간입니다. 

공식 파이썬 튜토리얼 문서를 보면 namespace를 다음과 같이 정의합니다.

 

namespace란 이름(변수명)과 객체를 연결한 것

 

퍼온 이미지1, 출처는 하단에 있습니다.

 

 

아래 예시에서 spam, eggs이라는 이름(변수)을 할당했다고 이들 자체가 '문자'는 아닙니다. 

이름은 단순히 객체(문자)를 가리킨다고 봐야합니다.

그래서 같은 객체를 다른 변수명으로 참조해도 문제가 되지 않습니다.

다만 같은 namespace에 존재하는 name들이 같은 객체를 가리키고 있는 것입니다. 

spam = 'spam and eggs'
eggs = spam

print(spam)  # spam and eggs
print(eggs)  # spam and eggs

print(id(spam))  # 4476916512
print(id(eggs))  # 4476916512

 

 

3. 캡슐화와 스코핑 

객체지향프로그래밍에서는 흔히 캡슐화라는 것이 존재합니다.

변수, 함수들을 한 클래스에 담기는 것인데 Python에서 캡슐화라고 한다면 namespace와 scope를 빼놓고 이야기하기 어렵습니다.

 

간단하게 생각해서 Python module이라고 하면 독자적인 namespace를 가진다고 생각해보겠습니다.

그런 의미에서 한 Python module에서 같은 이름을 가진 함수를 만들 수 없습니다. 하지만 namespace를 따로 갖고 있는 다른 Python module을 만든다면 같은 이름의 함수를 만들어도 상관 없습니다. namespace가 분리되어 있기 때문입니다.

 

비슷하게 같은 Python module 내에서라도 함수는 자신만의 namespace를 가집니다.

def spam():
    eggs = 'spam and eggs'
    print(eggs)

spam()       # spam and eggs
print(eggs)  # raises a NameError exception

 

 

spam 함수 안에서는 eggs가 참조 되지만 spam 함수를 벗어난 밖에서는 eggs라는 이름을 찾을 수 없습니다.

eggs는 spam 함수만에 namespace에서만 존재하고 그 안에서만 사용될 수 있기 대문입니다.

 

spam 함수 안에 namespace를 local space라고 생각하고 그 밖을 global space라고 보면 

위에 예에서는 global space에서 local space에 존재하는 eggs를 찾기 때문에 에러가 발생했습니다.

하지만 그 반대는 그렇지 않습니다. 무슨 말이냐면 

global space에서 local space에 접근하는 것은 불가했지만

local space에서 global space에 접근하는 것은 가능합니다.

 

예를 들면 spam에서 eggs를 밖으로 빼놨습니다. global space로 eggs를 이동시키고 spam함수 내에서 eggs를 참조하지만 아무런 문제가 없습니다. 

local space에서 global space에 접근하는 것은 가능하기 때문입니다. 

def spam():
    print(eggs)

eggs = 'spam and eggs'
spam()  # spam and eggs

 

 

같은 원리지만 class에서는 조금 헤깔릴 수 있습니다.

class Meal:
    def __init__(self):
        self.eggs = 2


my_meal = Meal()
print(my_meal.eggs)    # 2
print(eggs)            # raises a NameError exception

 

 

eggs를 접근할 때 my_meal.eggs는 되지만 그냥 eggs는 접근할 수 없습니다.

print(eggs)라고 하면 global space에서 eggs라는 변수가 있나 찾아보지만 eggs는 없기 때문입니다.

 

 

4. LEGB

local space에서는 global space를 참조했지만 반대는 그렇지 않듯이 namespace끼리의 의존관계가 있습니다. 

이를 LEGB라고 표현하는데 L > E > G > B 이렇게 참조가 가능합니다. 

하나씩 살펴보면, 

Local – 함수 내에서 할당된 이름 

Enclosing – 클로져(함수 내 함수)에 할당된 이름

Global – top-level module (Python file의 시작점)에 할당된 이름

Built-in – Python 내장 영역에 할당된 이름(open, import, print return, Exception 등)

 

 

위에서 알 수 있는 사실은

- 가장 낮은 레벨은 Local 영역, 가장 높은 레벨은 Built-in 영역입니다. 

- 낮은 레벨의 영역은 위 레벨 영역을 참조할 수 있습니다.

- 그 반대는 안됩니다. Global에서 Local을 참조할 수 없듯이 Built-in에서는 아무 영역도 접근할 수 없습니다.

퍼온 이미지2, 출처는 하단에 있습니다.

 

 

위 예시를 색깔별로 표현해보면 이렇습니다. 

퍼온 이미지3, 출처는 하단에 있습니다.

 

 

5. Imports

Python module는 각각의 Global namespace를 가지고 있습니다. 그래서 한 module 내에서는 같은 이름을 가진 함수를 만들 수 없었지만 다른 module에서는 같은 이름을 지어도 문제되지 않습니다. 

 

다른 module을 import한다는 것은 namespace끼리의 참조가 생기는 것입니다.

예를 들어,

 

spam.py

my_string  = 'spam and eggs'
my_number  = 42

 

 

main.py

import spam

print(spam.my_string)  # spam with eggs
print(spam.my_number)  # 42

 

main.py에서 import spam을 하면 spam.py 내 존재하는 my_string, my_number에 접근할 수 있지만

my_string, my_number처럼 사용할 수는 없습니다.

main.py의 Global space에서는 spam이라는 모듈로 할당된 것이기 때문에 spam.my_string, spam.my_number처럼만 사용할 수 있습니다. 

 

 

물론 spam.py에서 특정한 이름만 가져올 수도 있습니다.

main.py

from spam import my_string

print(my_string)  # spam with eggs
print(my_number)  # raises a NameError

 

 

spam에서 my_string만 가져오면 my_number에는 접근할 수 없습니다.

이렇게 특정한 이름만 가져올 경우에는 (from xx import xx) 바로 이름에 접근할 수 있습니다. 

 

 

From spam import *

Global namespace에 바로 이름을 가져올 수 있는 방법도 있습니다.

From spam import *라고 하면 spam에 있는 모든 이름을 Global space에 가져오는 방법으로 

위에서 spam.my_string, spam.my_number처럼 접근하지 않고 바로 이름에 접근할 수 있습니다. 

from spam import *

print(my_string)  # spam with eggs
print(my_number)  # 42

 

 

기본적으로 From spam import *을 통해 spam에 존재하는 모든 이름들을 가져올 수 있지만

이를 제어할 수 있는 방법도 있습니다.

 

spam.py

__all__ = (
  'my_string',
)

my_string  = 'spam and eggs'
my_number  = 42

 

 

__all__ 안에 my_string만 둔다면 다른 module에서 spam을 import할 경우 my_string만 할당시킬 수 있습니다.

spam.py를 이렇게 만들어 두고 main.py를 보겠습니다.

main.py

from spam import *

print(my_string)  # spam with eggs
print(my_number)  # raises a NameError

 

 

 

이미지 및 영문의 원글 출처 : https://blog.confirm.ch/python-namespaces/

 


같이 읽어보면 좋은 글

2022.12.27 - [파이썬/가상화폐] - [전자책] 바이낸스 코인선물자동매매 시스템 개발 방법을 담은 책이 출시되었습니다.

 

[전자책] 바이낸스 코인선물자동매매 시스템 개발 방법을 담은 책이 출시되었습니다.

🎁 바이낸스 자동매매 시스템 개발 방법을 담은 책이 출시되었습니다. "나 대신 일해주는 코인선물자동매매 프로그램 개발, 노하우 및 소스를 모두 공개합니다" ✔️ Q: 무슨 내용인가요? Python

jsp-dev.tistory.com

 

2022.11.05 - [파이썬/가상화폐] - [공지] 코인거래소별 프리미엄 체크봇 개발 가이드와 풀소스 전자책 | binance bybit | 업비트 김치프리미엄

 

[공지] 코인거래소별 프리미엄 체크봇 개발 가이드와 풀소스 전자책 | binance bybit | 업비트 김치프

https://kmong.com/gig/417785 거래소별 코인 프리미엄 알림봇 개발 가이드를 드립니다 | 36000원부터 시작 가능한 총 평점 5점의 3개 총 작업 개수 완료한 총 평점 5점인 JSDEV의 전자책, 투잡·재테크 전자

jsp-dev.tistory.com

 

2022.10.19 - [부업] - 비전공자를 위한 Python 기초책, 읽다보면 알게되는 파이썬 전자책!

 

비전공자를 위한 Python 기초책, 읽다보면 알게되는 파이썬 전자책!

✅전자책 링크 https://url.kr/ld89h7 * 프로그래밍을 배울까..? 망설인 적 있으신가요? 프로그래밍을 배워야 한다는 이야기는 수도 없이 들어봤지만 항상 망설이게 만드는 이유가 있습니다. “어렵지

jsp-dev.tistory.com

 

반응형
이 포스팅은 쿠팡파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글