python/기본

Decorator / contextmanager

wefree 2022. 4. 29. 20:24
def add_num(a, b):
    return a + b


print('start')
r = add_num(1, 2)
print('end')

print(r)


####################################################################
# AOP 처럼 ...
def print_info(func):
    def wrapper(*args, **kwargs):
        print('start')
        result = func(*args, **kwargs)
        print('end')
        return result

    return wrapper


def add_num(a, b):
    return a + b


# 첫번째 사용 방법
f = print_info(add_num)
r = f(1, 2)
print(r)

'''
start
end
3
'''


# 두번째 사용 방법
@print_info
def add_num_deco(a, b):
    return a + b


r = add_num_deco(1, 2)
print(r)


####################################################################

def deco_1(func):
    def wrapper(*args, **kwargs):
        print('1-START')
        result = func(*args, **kwargs)
        print('1-END')
        return result

    return wrapper


def deco_2(func):
    def wrapper(*args, **kwargs):
        print('2-START')
        result = func(*args, **kwargs)
        print('2-END')
        return result

    return wrapper


# deco_1(deco_2(deco_test))(a, b) 로 실행된다고 생각하면 될 듯?
@deco_1
@deco_2
def deco_test(a, b):
    return a + b


r = deco_test(1, 2)
print(r)

'''
1-START
2-START
2-END
1-END
3
'''

 

Python Clousure 에 나오는 functools.partial() 을 이용하면 아래처럼도 작성할 수 있다.

import functools


def add_num(a, b):
    return a + b


def print_info(f):
    print('start')
    result = f()
    print('end')
    return result


if __name__ == '__main__':
    f = functools.partial(add_num, 1, 2)
    r = print_info(f)
    print(r)

 

=====================================================================================

 

class 의 __enter__(), __exit__() 를 이용할 수 있다.

 

class CustomOpen(object):
    def __init__(self, filename):
        self.file = open(filename)

    def __enter__(self):
        return self.file

    def __exit__(self, ctx_type, ctx_value, ctx_traceback):
        self.file.close()

with CustomOpen('file') as f:
    contents = f.read()

 

 

=====================================================================================

 

 

contextlib.contextmanager  + yield 를 이용해 작성할 수도 있다.

import contextlib


@contextlib.contextmanager
def print_info(pre, post):
    print(pre)
    yield
    print(post)


@print_info("start", "end")
def add_num(a, b):
    return a + b


if __name__ == '__main__':
    r = add_num(1, 2)
    print(r)

 

위의 코드는 with 문으로 작성될 수 있다.

import contextlib


@contextlib.contextmanager
def print_info(pre, post):
    print(pre)
    yield
    print(post)


def add_num(a, b):
    return a + b


if __name__ == '__main__':
    with print_info("start", "end"):
        r = add_num(1, 2)
    print(r)

 

참고 코드

import contextlib

@contextlib.contextmanager
def open_file(name):
    f = open(name, 'wb')
    yield f
    f.close()
    
with open_file('some_file') as f:
    f.wirte('Hola')

 

https://github.com/gto76/python-cheatsheet#context-manager 참고

class MyOpen:
    def __init__(self, filename):
        self.filename = filename
    def __enter__(self):
        self.file = open(self.filename)
        return self.file
    def __exit__(self, exc_type, exception, traceback):
        self.file.close()

with open('test.txt', 'w') as file:
    file.write('Hello World!')
        
with MyOpen('test.txt') as file:
    print(file.read())