Python(파이썬) 기본 - 29. 변수 scope

아래 내용은 공부한 것을 정리하므로 틀린 내용이 포함되어 있을 수 있습니다.

  • Java & C#, Javascript, Python 변수 스코프가 조금씩 차이가 있음. 주의요망

1. javascript와 Python 차이

  • 코드로써 차이를 확인하겠습니다.
  • Javascript ES 6 let 키워드를 사용한 코드 입니다.
  • if 바깥에서도 a 변수 불가능
  • C#이나 Java의 변수 scope와 유사합니다.
      function abc(){
      	if(true){
      		let a = 5
          }
      	console.log(a)
      }
      abc()
        
      VM3146:5 Uncaught ReferenceError: a is not defined
          at abc (<anonymous>:5:14)
          at <anonymous>:1:1
    
  • Javascript ES 5 var 키워드를 사용한 코드 입니다.
  • if 바깥에서도 a 변수 접근 가능
      function abc(){
      	if(true){
      		var a = 5
          }
      	console.log(a)
      }
      abc()
      5 //결과
      console.log(a)
      VM482:1 Uncaught ReferenceError: a is not defined
          at <anonymous>:1:13
    
  • Javascript ES 5 var와 let 모두 사용하지 않고 그냥 선언한경우
  • if 바깥 뿐만아니라 함수 실행 후에는 함수 바깥에서도 접근 가능
      function abc(){
      	if(true){
      		a = 5
          }
      	console.log(a)
      }
      console.log(a)
      Uncaught ReferenceError: a is not defined
          at <anonymous>:1:1
        
      abc()
      5 //결과
      
      console.log(a) // 함수 실행 후 외부에서도 a 접근 가능, 전역 window에 a가 할당되었기 때문
      5
    
  • 이 사례만 본다면, 파이썬은 Javascript var 키워드의 스코프와 가장 유사합니다.
  • 같은 로직의 함수의 파이썬 변수를 보겠습니다.
  • if 바깥에서는 접근 가능, 함수 밖에서는 불가능 입니다.
      >>> def abc():
      ...     if True:
      ...             a = 5
      ...     print(a)
      ... 
      >>> abc()
      5
      >>> a
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      NameError: name 'a' is not defined
    
      >>> def test():
      ...     a= [1, 3, 5]
      ...     for i in a:
      ...             print("i:",i)
      ...     print(i)
      ... 
      >>> test()
      i: 1
      i: 3
      i: 5
      5  
    

2. LEGB Rule

  • 파이썬 변수 scope 룰을 LEGB 룰이라고 불리기도 합니다.
  • 변수가 값을 찾을 때, Local -> Enclosed -> Global -> Built-in

  • local - 가장 가까운 함수안 범위 입니다.
  • Enclosed - 파이썬은 함수 안에 함수가 정의 될수 있는데, 가장 가까운 함수가 아닌 두번째 이상의 함수 가까운 함수범위입니다.
  • Global - 함수 바깥의 변수 또는 import된 module
  • Built-in - 파이썬안에 내장되어 있는 함수 또는 속성들입니다.
      >>> a = 5    # Global
      >>> b = 10   # Global
      >>> def outer():
      ...     a = 10  # outer함수의 local이며, inner함수의 Enclosed
      ...     def inner():
      ...             c=30 # inner 함수의 local
      ...             print(a, b, c)
      ...     inner()
      ...     a = 22  # outer함수의 local이며, inner함수의 Enclosed
      ...     inner()
      ... 
      >>> outer()
      10 10 30  
      22 10 30
        
    
  • 똑같은 변수가 local과 global에 선언되어 있을 경우, LEGB rule에따라 local우선 사용
      >>> i = 1
      >>> def foo():
      ...     i = 5
      ...     print(i," in foo()")
      ... 
      >>> print(i, " in global")
      1  in global
      >>> foo()
      5  in foo()
    

    3. locals()와 globals()

  • 로컬변수를 확인하는 locals()
  • 글로벌변수를 확인하는 globals()
      >>> glob = 1
      >>> def foo():
      ...     loc = 5
      ...     print('loc in foo():' , 'loc' in locals())
      ... 
      >>> foo()
      loc in foo(): True
      >>> print('loc in global:', 'loc' in globals()) 
      loc in global: False
      >>> print('glob in global:', 'foo' in globals())
      glob in global: True
    
  • globals()로 import 모듈도 global 변수 임을 확인
      >>> 'math' in globals()
      False
      >>> import math
      >>> 'math' in globals()
      True
      >>> from math import factorial
      >>> 'factorial' in globals()
      True
    

    4. global 키워드

  • global 변수를 사용함으로써 실수할 수 있는 예
  • set_count(5)를 실행함으로써 global변수를 바꿀 수 있을 듯 보이지만..local에서 새롭게 변수를 할당하게 됩니다. 그러므로 show_count()는 계속 0입니다.
      >>> count = 0
      >>> def show_count():
      ...     print("count = ", count)
      ... 
      >>> def set_count(c):
      ...     count = c
      ... 
      >>> show_count()
      count =  0
      >>> set_count(5)
      >>> show_count()
      count =  0
    
  • 위 해결책으로 global 키워드를 사용합니다.
  • global 키워드는 함수 내부에서 로컬변수가 아닌 글로벌 변수를 사용하게 해줍니다.
     >>> count = 0
     >>> def show_count():
     ...     print("count = ", count)
     ... 
     >>> def set_count(c):
     ...     global count
     ...     count = c
     ... 
     >>> set_count(5)
     >>> show_count()
     count =  5