Python 함수의 변수와 스코프

스폰서 링크
python post logo 파이썬
스폰서 링크

이 글의 소스 샘플은 [Google Colab에서 Python 코드 실행하기] 글에서 언급한 환경을 이용하면 Python 프로그램을 PC에 설치하지 않더라도 Chrome, IE, Edge의 Browser에서 쉽게 Python프로그램을 실행하고 따라할 수 있습니다.

스폰서 링크

변수명 규칙

  • 변수명은 영문 대소문자로 작성합니다. ( A-Z, a-z )
  • 숫자를 포함시킬 수 있습니다. ( 0-9 )
  • 언더바를 포함시킬 수 있습니다. ( _ )
  • 변수명의 첫 글자를 숫자로 작성할 수 없습니다.

로컬(지역) 변수

다른 언어들과 마찬가지로 파이썬의 변수에는 유효 범위가 있습니다. 이것을 스코프라고 부릅니다. 로컬 변수는 이 스코프가 가장 작은 변수입니다.

def myfunc():
    a = 'Python'
    print ( 'a:' , a)

함수 안에서 정의된 변수 a는 해당 함수의 블록 안에서만 사용할 수 있는 것으로, 로컬 변수입니다. 함수의 스코프는 함수를 선언한 뒤, 들여쓰기가 된 부분들로 제한되기 때문에 아래와 같은 예시에서는 에러가 발생합니다.

def myfunc():
    a = 'Python'
    print('a:', a)

#함수 호출
myfunc() 

#함수 안의 변수 a 출력
print(a)
a: Python
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-b092c5cc86e6> in <module>()
      7 
      8 #함수 안의 변수 a 출력
----> 9 print(a)

NameError: name 'a' is not defined

함수를 호출한 결과는 정상적으로 출력되지만 함수 안의 변수를 출력하려고 하자 ‘a’가 정의 되지 않았다는 에러 메시지가 출력됩니다. 로컬 변수는 선언된 영역 밖에서는 사용할 수 없는 것을 확인할 수 있습니다.

또한, 같은 이름의 글로벌 변수가 스코프 밖에 존재하더라도 로컬 변수는 함수 내에서만 유효합니다.

def myfunc():
    a = 'Python'
    print('a:', a)

a = 'Ruby'
myfunc()
print('a:', a)
a: Python
a: Ruby

함수를 실행시켰을 때만 함수 안의 변수 ‘a’의 값이 출력되는 것을 확인할 수 있습니다.

글로벌(전역) 변수

글로벌 변수 역시 다른 언어와 비슷합니다. 어디에서나 사용할 수 있는 광범위한 스코프를 가진 변수입니다. 로컬 변수와는 달리 선언만 되어있으면 어느 위치에서든 참조할 수 있습니다.

global문

함수 안에서 변수를 선언하면 일반적으로 로컬 변수가 됩니다. 글로벌 변수는 자유롭게 참조할 수 있지만 값을 변경하기 위해 함수 안에서 ‘글로벌 변수 명 = 변경하고 싶은 값’의 형태로 지시하면 글로벌 변수와 같은 이름을 가진 로컬 변수가 선언되기 때문에 변경할 수는 없습니다. 하지만, 글로벌 변수의 값을 함수 내에서 변경하고 싶을 때에도 방법은 있습니다. 글로벌 변수의 값을 수정하기 전에 ‘global 글로벌 변수명’을 추가해주면 됩니다.

글로벌 변수 값을 함수 안에서 수정하려면 ‘global 변수명’이라는 코드를 넣어줍니다. 사용하고 싶은 글로벌 변수가 복수개일 때는 ‘,’로 구분하여 global 키워드 옆에 변수명을 나열해줍니다. 

def fun():
    global a, b
    a = 'glo_var'
    b = 'bal_var'
    print ('a=', a, 'b=', b)

a = 'before_edit'
b = 'python'
print (a, b)

fun()
print (a,b)
before_edit python
a= glo_var b= bal_var
glo_var bal_var

실행 결과를 보면, 함수가 실행되어 그 안에서 a, b의 값을 변경하기 전까지는 함수 밖에서 정의한 값인 ‘before_edit’, ‘python’이 출력됩니다. 그 후, 함수를 실행시킨 뒤 a, b의 값을 한 번 더 출력하면 함수 내에서 변경한 값이 출력됩니다. 아래는 global문을 넣지 않았을 경우의 예시입니다.

def fun():
    a = 'glo_var'
    b = 'bal_var'
    print ('a=', a, 'b=', b)

a = 'before_edit'
b = 'python'
print (a, b)

fun()
print (a,b)
before_edit python
a= glo_var b= bal_var
before_edit python

위쪽의 예시와는 달리 함수 실행 전후의 변수 값이 동일한 것을 확인할 수 있습니다.

스코프의 종류

각 오브젝트는 스코프를 가지고 있습니다. 오브젝트의 선언 위치에 따라 달라지는 스코프는 아래와 같은 몇 가지 종류로 나뉩니다.

로컬 스코프

주로 함수와 같은 오브젝트들 안에서 선언된 로컬 변수가 가지는 스코프입니다.

인클로징 스코프

함수 안의 함수, 즉 중첩된 두 함수 중 바깥 함수에 선언된 변수가 가지는 스코프입니다.

 def enclosing_scope(): 
  enclosing_var = 2 
  def inner_func(): 
    inner_var = 3 
    print(enclosing_var * inner_var)
  inner_func()
 
enclosing_scope()
6

함수 enclosing_scope()에 변수 enclosing_var를 선언한 후, 다시 변수 inner_var와 print문을 가진 함수 inner_func()을 선언한 뒤, enclosing_scope() 안에서 inner_func()을 호출합니다. 바깥의 함수인 enclosing_func()을 실행시키면 inner_func()의 계산결과가 출력됩니다. (enclosing_var+inner_var)

인클로징 함수 안에서 선언된 함수는 인클로징 함수 밖에서 호출할 수 없습니다. enclosing_func() 밖에서 inner_func()을 호출하면 아래와 같은 에러메시지가 출력됩니다. 마찬가지로 inner_var도 사용할 수 없습니다.

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-16-c99091499c1c> in <module>()
      8 
      9 enclosing_scope()
---> 10 inner_func()

NameError: name 'inner_func' is not defined

글로벌 스코프

함수 같은 오브젝트의 바깥에 선언된 글로벌 변수가 가지는 스코프입니다.

빌트인 스코프

주로 파이썬을 설치하기만 하면 사용할 수 있는 내장 함수들이 가지고 있는 광범위한 스코프입니다. 어디에서든지 사용할 수 있습니다.

이름 해석(Name Resolution)

변수명이나 함수명과 같은 ‘이름’을 사용하려고 할 때, 그 이름이 어떤 오브젝트를 참조하는지 결정하는 처리를 ‘이름 해석(Name Resolution)’이라고 합니다. 이름 해석에 의해 검색되는 스코프 역시 변화하며 우선 순위를 가집니다.

소스가 실행될 때 어떤 이름이 발견되면, ‘로컬 스코프→인클로징 스코프 → 글로벌 스코프→빌트인 스코프’의 순서로 이름을 검색합니다. 로컬 스코프에 해당하는 이름이 있으면 그 값을 이용하지만 발견되지 않으면 인클로징 스코프로 넘어가서 이름을 검색합니다. 최종적으로 빌트인 스코프까지 검색을 하였음에도 이름을 찾지 못하면 ‘NameError’가 발생하게 됩니다.

네임스페이스

이름 해석을 수행하기 위해서 네임스페이스를 사용합니다. 네임스페이스는 객체를 이름에 따라 사전 구조로 구분 지어주며 이름과 실제 값끼리 연결 지어주기도 합니다.

로컬 네임스페이스

함수가 호출되는 타이밍에 생성되어 처리가 끝날 때 삭제됩니다. 아래와 같이 임의의 함수 안에서 로컬 변수를 출력하는 소스를 실행시키는 예시로 현재 할당된 로컬 변수의 이름과 값을 확인할 수 있습니다.

def fun():
  local_ns=2
  print(locals())

fun()
{'local_ns': 2}

글로벌 네임스페이스

모듈을 가져올 때 생성되며, 대부분 인터프리터 종료 시에 삭제됩니다. 아래와 같이 임의의 글로벌 변수를 지정한 후 글로벌 변수를 출력하면 내장된 글로벌 변수들이 나열된 후, 가장 마지막에 직접 선언한 글로벌 변수가 출력되는 것을 확인할 수 있습니다.

global_ns = 1
print(globals())

{'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': <module 'builtins' (built-in)>, '__builtins__': <module 'builtins' (built-in)>, '_ih': ['', 'global_ns = 1\nprint(globals())'], '_oh': {}, '_dh': ['/content'], '_sh': <module 'IPython.core.shadowns' from '/usr/local/lib/python3.7/dist-packages/IPython/core/shadowns.py'>, 'In': ['', 'global_ns = 1\nprint(globals())'], 'Out': {}, 'get_ipython': <bound method InteractiveShell.get_ipython of <google.colab._shell.Shell object at 0x7f7a5ffab290>>, 'exit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f7a5ffcb5d0>, 'quit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f7a5ffcb5d0>, '_': '', '__': '', '___': '', '_i': '', '_ii': '', '_iii': '', '_i1': 'global_ns = 1\nprint(globals())', 'global_ns': 1}

빌트인 네임스페이스

Python 인터프리터 기동시 작성되며 인터프리터 종료시 삭제됩니다. 파이썬 버전에 따라서 구성이 다를 수 있습니다.

print(dir(__builtins__))
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'dreload', 'enumerate', 'eval', 'exec', 'execfile', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'runfile', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
제목과 URL을 복사했습니다