코딩/Python

[Python] 내장함수 globals() 활용하기

작은코딩 2022. 4. 24. 18:00

🎈 globals() 함수란?

파이썬 내장 함수인 globals() 함수를 간단하게 설명하면 전역 변수의 상태를 dictionary 형태로 보여주는 함수이다. 

 

Python 공식문서를 살펴보면 다음과 같이 설명되어있다.

공식 문서의 내용에서는 딕셔너리를 돌려준다고 하는데 실제 함수 호출을 하면 어떤 식으로 작동하는지 알아보자.


name, age, hobby 변수에 str, int, list 타입의 데이터를 저장하고 globals() 함수를 프린트해보았다.

실행 결과 전역 변수들의 정보를 확인할 수 있는데 현재 모듈에 대한 정보 다음으로 내가 설정한 변수 정보도 딕셔너리 형태로 잘 반환되는 걸 확인할 수 있다. 


🎈 globals() 함수를 어떻게 사용할 수 있을까?

다양한 사용법이 있을 수 있지만 여기서는 for 반복문과 문자열 포매팅을 활용한 전역 변수를 만들고 수정하는 방법에 대해서 다뤄보겠다.

 


🎈 globals() 함수 활용하기

💎 for문으로 전역 변수 만들기

다음과 같은 list 자료가 주어진다고 했을 때 각 원소를 따로 변수에 저장해야 한다고 가정해보자.

board = [[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]]

 

len(board)의 값이 작다면 이렇게 수기로 저장할 수 있지만 100개 혹은 그 이상의 자료가 들어온다고 생각하면 globals() 함수를 이용할 수 있다.

b_list1 = [0,0,0,0,0]
b_list2 = [0,0,1,0,3]
b_list3 = [0,2,5,0,1]
b_list4 = [4,2,4,4,2]
b_list5 = [3,5,1,3,1]

# 자료가 더 많아진다면 수작업으로 변수를 저장하긴 어렵다

 

앞서 말했듯이 globals() 함수는 딕셔너리 자료를 반환한다. key는 변수 명, value는 변수에 저장된 데이터라는 걸 알 수 있는데 이런 딕셔너리 자료구조의 성격을 이용해서 전역 변수를 추가하거나 value에 접근해서 데이터를 수정할 수 있다.

board = [[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]]

for index, value in enumerate(board):
    globals()[f"b_list{index + 1}"] = value

print(globals())

코드 해석>>

1. enumerate() 함수를 사용해서 list의 인덱스와 원소를 for문의 index, value 변수에 저장한다.

2. Dictionary[key] = value // 딕셔너리 성격을 이용. globals() 함수로 전역 변수 딕셔너리를 가져와서 문자열 포매팅 + index로 key 값을 넣어주고 value를 저장한다.

3. globals() 함수를 프린트해서 결과를 확인해보자

 

결과>>

생각한 대로 결과가 잘 나왔는데 이상한 친구들이 보인다..

index와 value

for문을 사용할 때 임시 변수를 만들어서 사용하는 줄 알았는데 사실은 전역 변수였단 사실,, 

실제로 for문이 끝난 후 index와 value를 프린트해보니 반복문의 가장 마지막에 저장된 데이터가 콘솔에 찍히는 걸 확인할 수 있다. 

 

for문에서 전역 변수를 사용하다니,,, 앞으로는 변수명에 신경을 써야겠다.


💎 globals() 함수로 만든 전역 변수 활용하기

<직접 수정하기>

실행 코드
결과

globals() 함수로 만든 전역 변수는 확인되지 않은 참조라고 빨간줄이 뜨긴 하지만 문제없이 사용할 수 있다.

 

하지만 많은 변수를 한번에 수정을 해야된다면? 변수별로 조건을 달리해야 한다면?

for문과 globals() 함수를 사용해서 해결할 수 있다.


<반복문을 이용해 수정하기>

먼저 상황을 가정해보자. 

각각의 b_list 변수에 담긴 list의 첫 번째 원소가 0이 아니라면 0으로 바꿔주는 코드를 작성해보자. 

board = [[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]]

def solution(board):
    for index, value in enumerate(board):
        globals()[f"b_list{index + 1}"] = value


    for key, value in globals().items():
        if key[:6] == "b_list":
            if value[0] != 0:
                value[0] = 0
        else:
            pass


solution(board)
print(globals())

이 방법을 사용할 때 주의사항이 있는데 전역 공간이 아닌 로컬 공간에서 작업을 해야 한다.

이유는 for문을 실행할 때 전역 변수를 만들게 되는데 이때 globals()로 호출되는 딕셔너리의 크기가 달라지기 때문. 따라서 로컬 환경을 만들어서 실행할 수 있도록 하자.

전역 공간에서 작업을 진행하면 이런 에러를 만나게 된다.

 

코드 해석>>

1. 딕셔너리 함수인 items()를 이용해서 for문의 key(전역 변수)와 value(데이터) 변수에 저장

2. key(전역 변수)가 "b_list"로 시작하는 경우 value의 첫 번째 원소를 확인.

3. 첫 번째 원소가 0이 아니라면 0으로 바꿔준다.

 

결과>>

4, 3이었던 값이 0으로 바뀐걸 확인할 수 있다.


🎈 포스팅을 마치며

전역 변수를 직접 컨트롤하는 건 대형 프로젝트에서는 기피되는 행동이라고 알고 있다. 대형 프로젝트에서는 당연히 사용되는 전역 변수도 많을 거고 globals() 함수를 호출하는 매 과정이 비효율적일 수도 있다. 

(변수 명이 겹치지 않게 관리하는 것도 일,,)

 

그래도 특정한 상황에서는 globals() 함수를 이용한 알고리즘이 필요할 거 같아서 기록을 남겨놓는다.

 


<22.04.24 추가>

포스팅을 마치고 자료를 정리하던 중 수정한적 없는 board 변수가 수정된걸 확인했다.

이게 무슨일인가 싶어 디버깅을 찍어보니,,,

 

 

b_list4, b_list5가 수정될 때 board도 같이 수정되는걸 확인할 수 있는데 globals()함수를 사용하면서 서로 매핑되는 상황이 만들어진거 같다.

이 현상에 대해서는 추가적인 공부가 필요할듯,,,

 

주의사항이 늘어났다.