2015년 12월 22일 화요일

파이썬 데코레이터(@ : decorator) 요약

먼저 Python의 Decorator를 알아 보자.
 - Function, Method 그리고 Class 정의를 수정하기 위해 사용되어 지는 일종의 호출이다.
 - 원조 오브젝트를 가지고 수정된 오브젝트를 반환한다.
 - 자바의 Annotations에서 영감을 받았으며, 유사한 Syntax 를 가지고 있다.
 - “@“ 예약 문자를 통해 문법적인 편의를 제공한다.

용도는 데코레이터를 통해서 정의될 객체의 꾸밈을 할 수 있다는 것이 포인트이다.
본문은 예제를 통해서 데코레이터에 대한 이해를 돕는 것을 목표로한다.

냉장고에 사과를 넣는 것을 보자.
1. 문을 연다.
2. 사과를 넣는다.
3. 문을 닫는다.

이때, 냉장고 기능(1,3)을 미리 정의 하고, 행동 기능(2)를 만들때 냉장고 기능으로 데코레이팅하는 것이다.

데코레이터를 클래스로 정의한 예제이다.

class 냉장고:
    def __init__(self, f):
        print ('Decorator was started.')
        self.func = f;

    def __call__(self,q):
        print ('문을 연다.')
        self.func(q);
        print ('문을 닫는다.')

def 물건넣기(q):
    print('%s를 넣는다' % q)

먼저 새로운 객체(냉장고물건넣기) 사용 예제이다.

냉장고물건넣기 = 냉장고(물건넣기)
냉장고물건넣기(‘사과')

Decorator was started.
문을 연다.
사과를 넣는다
문을 닫는다.

데이코레이터를 함수의 관계로 표현한 것이다.
함수들의 플로우는 객체를 통해서 디자인 형태로 남을 수 있다.

데코레이터를 사용한 예제이다.

@냉장고
def 물건넣기(q):
    print('%s를 넣는다' % q)
물건넣기(‘사과')

Decorator was started.
문을 연다.
사과를 넣는다
문을 닫는다.

데코레이터는 함수 형태로도 가능하다.

def 박스(f):
    print ('Decorator was started.')
    
    def new_func(q):
        print ('뚜껑을 연다.')
        f(q);
        print ('뚜껑을 닫는다.')
    return new_func

@박스
def 물건찾기(q):
    print('%s를 찾아서 뺀다.' %q)

Decorator was started.

물건찾기(‘장난감')

뚜껑을 연다.
장난감를 찾아서 뺀다.
뚜껑을 닫는다.

객체지향 요소가 강한 파이썬에서 편리하게 사용할 수 있었다.


데코에 대한 이해가 되었다면, 실제 사례를 보자.

ebaysdk 에서 실제로 구현된 python 2에 대한 유니코드 호환을 위해 데코레이터를 사용한 예제이다.

def python_2_unicode_compatible(klass):
    """
    A decorator that defines __unicode__ and __str__ methods under Python 2.
    Under Python 3 it does nothing.
    To support Python 2 and 3 with a single code base, define a __str__ method
    returning text and apply this decorator to the class.
    """
    if sys.version_info[0] < 3:
        if '__str__' not in klass.__dict__:
            raise ValueError("@python_2_unicode_compatible cannot be applied "
                             "to %s because it doesn't define __str__()." %
                             klass.__name__)
        klass.__unicode__ = klass.__str__
        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
    return klass

@python_2_unicode_compatible
class ResponseDataObject(object):
    ...

클래스의 __unicode__에 Unicode를 넣고, __str__에 'utf-8'로 encode 해서 저장한다.
 - Python3 에서는 기본적으로 String을 Unicode(유니코드)를 사용한다.
 - Python2 에서는 String을 Encoding 된 byte(바이트) 코드로 사용된다.


커버 사진


0 개의 댓글:

댓글 쓰기