Ansible로 배포 스크립트를 만드는데 일부 작업에서 사용하는 모듈과 스크립트들이 종종
prompt로 패스워드나 이런저런 의사를 물어보는 경우가 있다.
한두번이야 대충 적당히 입력해 주겠는데 배포해야할 서버가 늘어날수록 여간 귀찮은게 아니다.
그래서 자동입력을 어떻게 해야하나 찾아보니 expect란 애를 쓰면 해결이 된다고 한다.
누운 상태에서 나의 양 다리로 상대의 한쪽 다리를 얽어매어 방어하는 형태의 가드다. 하프 가드는 Top포지션(위에서 공격해 들어오는 사람)이나 Bottom포지션(아래에서 방어하는 사람)중 누가 절대적으로 유리하다 할 수 없어서 더욱 재미있는 가드 중에 하나라고 한다. 그리고 그만큼 기술 종류도 많다고 한다. 여기저기 찾아보니 오래한 사람일수록 하프 가드를 선호 한다는 이야기도 있다.
요즘 나도 하프가드를 많이 쓴다. 씁쓸한건 나의 경우 재미 보단 내 오픈가드가 워낙 취약해서 그렇다. 내 오픈가드가 워낙 잘 뚫리다보니 눈치껏 오픈가드가 뚫릴거 같으면 재빨리 하프가드로 전환 한다. 나도 좀 남들처럼 멋지게 오픈가드 스윕 해보고 싶은데……
하프가드 기본
하프가드 기본 강좌
하프가드 주의사항
하프가드 스윕
하프가드 스윕 1번 : 언더 훅으로 백 포지션 잡기, 가장 처음 배운거, 옥토퍼스 가드로 전환이 가능한데 그건 나중에…..
하프가드 스윕 2, Shaolin Sweep이라는데 이름은 확실치 않음, 하프가드 시저라고 하는 부분도 있는데?, 요즘 내가 자주 써먹는 스윕
어쩌다 python-django 로 웹 어플리케이션 하나를 만들게 되었는데 이거 은근 신세계다. django 같은 프레임워크야 뭐 많으니까 놀랄게 없더라도 python의 decorator는 나에게 뭔가 신세계를 보여줬다. java-spring에서 그렇게 복잡했던 AOP가 decorator를 쓰면 그냥 별 고민 없이 끝나버린다. 이걸 AOP라고 해도 될런지 모르겠지만 말이다. 여튼 decorator에 감탄한 나머지 까먹기 전에 decorator 파트만 정리해본다.
그런데 데코레이션을 붙이는 순강 망한다. __doc__이 안나온다. 실제로 django api application을 만들면서 api endpoint 메소드들을 decorator로 신나게 감쌌더니 Sweager UI에서 doc 처리하지 못해 공백 API 가이드만 한가득 나왔다.
생각해보면 당연한 일이다. 실행시간에 실제로 접근하는 메타데이터는 func가 아니라 데코레이터가 만들어준 wrapper의 메터데이터니 제대로 나올리가 없다. 그렇다. 우린 망했다.
그렇다고 진짜 망한건 아니다. decorator에 @wraps 달아주면 모든것이 해결된다. 모든 decorator에는 반드시 @wraps를 달아주자. 그것이 모두가 행복해지는 길이다. 이유는 찾아보기 귀찮아서 생략. (대충 소스 보니 func의 __doc__ 같은 meta 정보를 wrapper에 복사해 넣는거 같은데 확실한건 아님!)
x와 y를 더합니다.
:param x:
:param y:
:return:
func before
3
func after
x와 y를 더합니다.
:param x:
:param y:
:return:
hello, decorator!
func2 before
3
func2 after
class로도 decorator 선언이 가능하다고도 합니다.
class로 만드는게 뭔가 낙타표기도 되고 그래서 뭔가 그 뭔가 멋져보이는거 같은데 여기엔 치명적인 단점이 있다. @wraps를 붙일수가 없다. 그나마 parameter를 가지는 데코레이터의 경우 __call__ 시점에서 wrapper를 만들면서 @wraps를 붙여줄수 있는데 parameter가 없는 데코레이터의 경우 wraps를 붙일 방법이 보이질 않는다. 이거 저거 찾아보니 결국 __doc__, __name__들을 복사해 넣는데 이럴거면 그냥 function으로 데코레이터 만들란다.
from functools import wraps
# 그냥 Class 데코레이터, @wraps를 붙일만한데가 보이지 않는다.
class Decorator:
def __init__ (self, func):
self.func = func
def __call__ (self, *args, **kwargs):
print("%s %s" % (self.func.__name__, "before"))
result = self.func(*args, **kwargs)
print("%s %s" % (self.func.__name__, "after"))
return result
# 파레매터를 가지는 Class 데코레이터, __call__에서 @wraps를 넣어준다.
class DecoratorWithParam:
def __init__ (self, param):
self.param = param
def __call__ (self, func):
@wraps(func)
def decorator(*args, **kwargs):
print(self.param)
print("%s %s" % (func.__name__, "before"))
result = func(*args, **kwargs)
print("%s %s" % (func.__name__, "after"))
return decorator
@Decorator
def func(x, y):
"""
x와 y를 더합니다.
:param x:
:param y:
:return:
"""
print(x + y)
return x + y
@DecoratorWithParam("hello, decorator!")
def func2(x, y):
"""
x와 y를 더합니다.
:param x:
:param y:
:return:
"""
print(x + y)
return x + y
print(func.__doc__)
func(1,2)
print(func2.__doc__)
func2(1,2)
---- 출력 ----
None # 아, 이거 짜증나네
func before
3
func after
x와 y를 더합니다.
:param x:
:param y:
:return:
hello, decorator!
func2 before
3
func2 after