1. 학습목표

2. 학습내용
# Decorator & Closure
# 일급함수(일급객체)를 지원하기때문에 decorator와 closure를 쓸 수 있음!
# 파이썬 변수 범위(global)
# 예제1
def func_v1(a):
print(a)
print(b)
# 예외 에러 발생
# func_v1()
"""
Traceback (most recent call last):
File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 11, in <module>
func_v1()
TypeError: func_v1() missing 1 required positional argument: 'a'
"""
# 예제2
b = 10
def func_v2(a):
print(a)
print(b)
# func_v2(5)
"""
5
10
"""
# 예제3
b = 10
def func_v3(a):
print(a)
print(b)
b = 5 # b라는 변수에 값을 할당 전에 출력하려고 해서 에러 발생! 지역변수가 글로벌변수 보다 먼저!
# func_v3(5)
"""
5
Traceback (most recent call last):
File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 43, in <module>
func_v3(5)
File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 40, in func_v3
print(b)
UnboundLocalError: local variable 'b' referenced before assignment
"""
# 실행의 흐름 확인하기
from dis import dis
# print ('EX1-1 -', dis(func_v3))
"""
39 0 LOAD_GLOBAL 0 (print)
2 LOAD_FAST 0 (a)
4 CALL_FUNCTION 1
6 POP_TOP
40 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 1 (b)
12 CALL_FUNCTION 1
14 POP_TOP
41 16 LOAD_CONST 1 (5)
18 STORE_FAST 1 (b)
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
EX1-1 - None
"""
# Closure(클로저)
# 반환되는 내부 함수에 대해서 선언된 연결 정보를 가지고 참조하는 방식
# 반환 당시 함수 유효범위를 벗어난 변수 또는 메소드에 직접 접근이 가능한다
a = 10
# print('EX2-1 -', a+10)
# EX2-1 - 20
# print('EX2-2 -', a+100)
# EX2-2 - 110
# 결과를 누적할 수 있을 까?
# print('EX3-1 -', sum(range(1,51)))
# EX3-1 - 1275
# print('EX3-2 -', sum(range(51,101)))
# EX3-2 - 3775
# 클래스를 이용해서 누적하기
class Averager():
def __init__(self):
self._series = []
def __call__(self, v):
self._series.append(v)
print('class >>> {}/{}'.format(self._series, len(self._series)))
return sum(self._series) / len(self._series)
# 인스턴스 생성
avg_cls = Averager()
# 누적 확인
# 누적이 가능한 이유는 메소드 밖의 변수(클로저 영역의 변수)에 저장하고 있기 때문!!!
# print('EX3-1 -', avg_cls(15))
"""
class >>> [15]/1
EX3-1 - 15.0
"""
# print('EX3-2 -', avg_cls(35))
"""
class >>> [15, 35]/2
EX3-2 - 25.0
"""
# print('EX3-2 -', avg_cls(50))
"""
class >>> [15, 35, 50]/3
EX3-2 - 33.333333333333336
"""
# 클로저(closure) 사용함
# 전역변수 사용 감소
# 디자인 패턴 적용
def closure_avg1():
# Free Variable : 외부 함수와 내부 함수 사이의 영역을 free variable이라고 함
series = []
# 클로저 영역
# 클로저 영역을 사용하면 함수형 프로그래밍이나 마우스 클릭수 저장하기 등에 사용용
# 변수에 대한 은닉화도 가능
# 클로저 사용시에 조심할 부분들은 있음! 자원 낭비 조심! 꼭 필요한 곳에 사용하도록!
# 클로저 영역의 변수는 함수의 실행이 종료되어도 접근이 가능한 것이 포인트..!
def averager(v):
series.append(v)
print('def >>> {}/{}'.format(series, len(series)))
return sum(series) / len(series)
return averager
avg_closure1 = closure_avg1()
# print('EX4-1 -', avg_closure1)
# EX4-1 - <function closure_avg1.<locals>.averager at 0x102de1bf8>
# print('EX4-2 -', avg_closure1(15))
"""
def >>> [15]/1
EX4-2 - 15.0
"""
# print('EX4-2 -', avg_closure1(35))
"""
def >>> [15, 35]/2
EX4-2 - 25.0
"""
# print('EX4-2 -', avg_closure1(40))
"""
def >>> [15, 35, 40]/3
EX4-2 - 30.0
"""
# print('EX5-1 -', dir(avg_closure1))
"""
EX5-1 - ['__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('EX5-2 -', dir(avg_closure1.__code__))
"""
EX5-2 - ['__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_stacksize', 'co_varnames']
"""
# print('EX5-3 -', avg_closure1.__code__.co_freevars)
# EX5-3 - ('series',)
# print('EX5-4 -', dir(avg_closure1.__closure__[0]))
"""
EX5-4 - ['__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__', 'cell_contents']
"""
# print('EX5-4 -', dir(avg_closure1.__closure__[0].cell_contents))
"""
EX5-4 - ['__add__', '__class__', '__contains__',
'__delattr__', '__delitem__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__',
'__gt__', '__hash__', '__iadd__', '__imul__',
'__init__', '__init_subclass__', '__iter__',
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__reversed__',
'__rmul__', '__setattr__', '__setitem__',
'__sizeof__', '__str__', '__subclasshook__',
'append', 'clear', 'copy', 'count', 'extend', 'index',
'insert', 'pop', 'remove', 'reverse', 'sort']
"""
# 클로저를 잘못한 사용한 예제들
def closure_avg2():
# Free Variable
cnt = 0
total = 0
# 클로저 영역
def averager(v):
cnt += 1
total += v
return total/cnt
return averager
avg_closure2 = closure_avg2()
# print('EX5-5 -', avg_closure2(15))
"""
/Users/marie/PycharmProjects/untitled1/venv/bin/python /Users/marie/PycharmProjects/untitled1/fc_lecture.py
Traceback (most recent call last):
File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 245, in <module>
print('EX5-5 -', avg_closure2(15))
File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 238, in averager
cnt += 1
UnboundLocalError: local variable 'cnt' referenced before assignment
"""
def closure_avg3():
# Free Variable
cnt = 0
total = 0
# 클로저 영역
def averager(v):
nonlocal cnt, total
# free variable가 동일한 이름의 지역 변수가 있으면 지역 변수가 우선!
# 그럴때 클로저를 쓰고 싶다면! nolocal 키워드로 클로저 변수로 쓸 변수의 이름을 지정하세욤!
cnt += 1
total += v
print('def2>>> {} / {}'.format(total, cnt))
return total/cnt
return averager
avg_closure3 = closure_avg3()
# print('EX5-6 -', avg_closure3(15))
"""
def2>>> 15 / 1
EX5-6 - 15.0
"""
# print('EX5-7 -', avg_closure3(35))
"""
def2>>> 50 / 2
EX5-7 - 25.0
"""
3. 느낀 점