728x90
1. 파이썬 변수 범위 - global
먼저 global에 대해 알아보겠습니다.
파이썬에서 global은 지역볌수를 전역변수로 참조하는 키워드입니다.
아래 예제를 통해 자세히 알아보겠습니다.
b = 20
def func1(a):
print(a) #출력: 2
print(b) #출력: 20 -> 전역변수 20 출력
func1(2)
c = 30
def func2(a):
print(a)
print(c)
c = 40 # 지역변수에 전역변수와 동일한 변수가 있을 경우 에러발생
# func2(5) #출력: UnboundLocalError: local variable 'c' referenced before assignment
def func3(a):
global c # 전역 참조 -> 지역변수에 전역변수와 동일한 변수가 있어도 에러가 발생하지 않음
print(a) #출력: 10
print(c) # 출력: 30
c=40
func3(10)
print("전역 c=",c) #출력: 전역 c= 40
2. 클로저
클로저란 외부에서 호출된 변수값, 상태(레퍼런스)를 복사 후 저장하여 나중에 접근(엑세스)할 수 있게 해주는 기능입니다.
쉽게 말해서 함수가 끝나도 지역변수의 값이나 상태등을 기억한다는 것입니다.
클로저를 사용하는 이유는 아래와 같습니다.
1) 서버 프로그래밍을 할 때 동시성을 제어하는 것이 필요합니다. 동시성을 제어하지 못한다면 메모리공간에 여러 자원이 접근했을 때 교착상태(dead lock)에 빠질 수 있습니다.
2) 메모리를 공유하지 않고 메시지 전달로 처리하기 위함입니다.
3) 클로저는 공유하되 변경되지 않는 구조를 적극적으로 사용합니다. 이는 함수형 프로그래밍으로 이어집니다.
4) 클로저는 불변자료구조 및 원자성 등을 통해 멀티스레드 프로그래밍 강점을 가질수 있습니다. 파이썬은 멀티쓰레드가 되지 않지만 코루틴을 사용하여 비슷한 효과를 가질 수 있습니다.
먼저 클래스를 사용하여 평균값을 구해보겠습니다.
class Averager():
def __init__(self):
self._series = []
def __call__(self, v):
self._series.append(v)
print(f"{self._series} / {len(self._series)}")
return sum(self._series) / len(self._series)
averager = Averager()
print(dir(averager))
#출력: ['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
# '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
# '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
# '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
# '__str__', '__subclasshook__', '__weakref__', '_series']
print(averager(10))
# 출력:
# [10] / 1
# 10.0
print(averager(30))
#출력:
# [10, 30] / 2
# 20.0
print(averager(50))
#출력:
# [10, 30, 50] / 3
# 30.0
위와 동일한 기능을 클로저를 사용해서 구현해보겠습니다.
def closure_ex1():
# 자유변수
#클로저 영역
series = []
def averager(v):
series.append(v)
print(f"{series} / {len(series)}")
return sum(series) / len(series)
return averager # 함수를 결과로 반환
cls1 = closure_ex1()
print(cls1) # 출력:<function closure_ex1.<locals>.averager at 0x000001A8D286F940>
print(cls1(10))
#출력:
# [10] / 1
# 10.0
print(cls1(20))
# 출력:
# [10, 20] / 2
# 15.0
print(cls1(30))
#출력:
# [10, 20, 30] / 3
# 20.0
print(dir(cls1))
#출력:['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__',
# '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__',
# '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
# '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__',
# '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
print(dir(cls1.__code__))
#출력: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
# '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
# '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
# '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename',
# 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names',
# 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames', 'replace']
print(cls1.__code__.co_freevars) # 출력: ('series',) -> 자유변수
print(cls1.__closure__[0].cell_contents) # 출력: [10, 20, 30] -> 3번 호출했을때 매개변수의 값을 모두 가지고 있음
잘못된 클로저의 사용예제는 아래와 같습니다.
def closure_ex2():
# 자유변수
cnt = 0
total = 0
def averager(v):
cnt += 1
total +=v
return total / cnt
return averager
cls2 = closure_ex2()
# print(cls2(10)) # 에러발생 : UnboundLocalError: local variable 'cnt' referenced before assignment
자유변수는 averager함수에서는 전역변수에 속하게 됩니다. 따라서 전역변수와 지역변수의 변수명이 동일하여 참조 오류가 발생합니다.
이를 해결하기 위해서는 아래와 같이 처리하면 됩니다.
def closure_ex3():
# 자유변수
cnt = 0
total = 0
def averager(v):
nonlocal cnt,total # nonlocal 키워드는 지역변수를 자유변수로 변경해 준다
cnt += 1
total +=v
return total / cnt
return averager
cls3 = closure_ex3()
print(cls3(15)) # 출력: 15.0
print(cls3(25)) # 출력: 20.0
print(cls3(35)) # 출력: 25.0
'PYTHON Programming > Python' 카테고리의 다른 글
[Python] 파이썬 시퀀스 (0) | 2024.07.25 |
---|---|
[Python] 일급함수- 장식자(데코레이터) (0) | 2024.05.28 |
[python] 일급함수(First-class function) (0) | 2024.05.28 |
[python] 구글 스프레드 시트 연동 및 관리(gspread) (0) | 2024.05.23 |
[python] 정렬함수(sort() vs sorted()) (0) | 2024.05.23 |