알고리즘

[Python] Closure & Decorator

minari 2021. 11. 21. 16:58

✔️ Nested Function (중첩 함수)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Nested function
def print1(msg):
    def printer():
        print(msg)
    printer() # call -> print()
    
# Closure
def print2(msg):
    def printer():
        print(msg) # 외부에서 정의된 msg를 함수에서 사용
    return printer # 내부에서 정의한 함수를 return
 
print1("Hello1")
ex = print2("Hello2")
ex() # ex()를 call해야 printer()가 실행된다.
cs
중첩 함수 print()는 부모 함수 print1() 안에서만 사용할 수 있다.

 

✔️ Closure

'폐쇄' 전역 값의 사용을 피할 수 있으며, 데이터를 숨길 수 있다.

Nested 구조를 갖춰야하며

부모 함수의 변수나 정보를 중첩함수가 내부에서 사용해야하며

부모 함수는 중첩 함수를 return 해야 한다. 

1
2
3
4
5
6
7
8
9
def add_number(num):
    def adder(number):
        print('adder is a closure')
        return num+number
    return adder
 
a_10 = add_number(10)
= a_10(21)
print(a)
cs

 🔳 출력 결과

  adder is a closure ⇽ line8
  31 ⇽ line9

 

✔️ Decorator

 - 함수를 인자로 받아 새로운 함수를 만들어 반환하는 함수

 - 함수 실행 전 특정 동작을 하게 하는 걸 간단하게 할 수 있게 만드는 것

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def NewDecorator(func):
    # @wraps(func)
    def NewAdd(*args, **kwargs):
        print('Before call')
        result = func(*args, **kwargs)
        print('After call')
        return result
    return NewAdd
 
@NewDecorator # 기본이 되는 함수 형식을 사용하겠다! 는 의미
def add1(a, b):
    print('Add1')
    return a + b
    
sum = add1(13# ‘Before call’ ‘Add’ ‘After call’ 4
print(sum)
print(add1.__name__) # NewAdd
 
def add2(a, b):
    print('Add2')
    return a + b
 
add2 = NewDecorator(add2)
print(add2(13))
cs

🔳 출력 결과

  Before call ⇽ line15 - 4
  Add1 ⇽ line15 - line5 - 12
  After call ⇽ line15 - 6
  4 ⇽ line16
  NewAdd ⇽ line17


  Before call ⇽ line24
  Add2 ⇽ line24
  After call ⇽ line24
  4 ⇽ line24

 

@decorator 와 add = NewDecorator(add)는 똑같이 decorator 함수를 실행시키는 코드이다

 

 

📌 class 에도 Decorator를 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ClassDecorator(object):
    def __init__(self, f):
        print('__init__')
        self.f = f
    def __call__(self*args, **kwargs):
        print('__call__')
        return self.f(*args, **kwargs)
    
@ClassDecorator # 해당 클래스를 Decorator로 쓰고 있다! 는 의미
def Fn(a, b):
    print("inside Fn()")
    return a + b
 
print(Fn(12))
cs

🔳 출력 결과

  __init__ ⇽ line 14
  __call__ ⇽ line 14
  inside Fn() ⇽ line 14 - 7 - 11 
  3 ⇽ line 14

 

📌 Property decorator

Built-in decorator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class P1:
    def __init__(self,x):
        self.set_x(x)
    def get_x(self):
        return self.x
    def set_x(self, x):
        if x < 0self.x = 0
        elif x > 1000self.x = 1000
        elseself.x = x
        
p1 = P1(1001); print(p1.get_x()) # 1000
p1 = P1(-1); print(p1.get_x()) # 0
p1 = P1(15); print(p1.get_x()) # 15
# 이런 식으로 set할 때 확인할 수 있는 기능, setter
 
p1.x = 1001print(p1.get_x()) # 1001
# set_x가 동작하지 않는다
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class P2:
    def __init__(self, x):
        self.x = x
    
    @property # getter
    def x(self):
        return self._x # private member로 값을 저장한다
 
    @x.setter
    def x(self, x):
        if x < 0:
            self._x = 0
        elif x > 1000:
            self._x = 1000
        else:
            self._x = x
        
p2 = P2(1001)
print(p2.x) # 1000
 
p2.x = -12
print(p2.x) # 0
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class C:
    def __init__(self):
        self._x = None
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, x):
        self._x = x*2
    @x.deleter
    def x(self):
        del self._x
        
class C2:
    def __init__(self):
        self._x = None
    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value*2
    def delx(self):
        del self._x
    x = property(getx, setx, delx)
    
c2 = C2()
c2.x = 10
print(c2.x) # 20
cs