2017년 12월 3일 일요일

[clojure][designpattern] 클로저 디자인패턴 - 전략패턴

clojure design pattern 출처::http://clojure.or.kr/docs/clojure-and-gof-design-patterns.html
2. 전략패턴(Strategy Pattern)
요약 : 이름 정렬 , 유료고객은 먼저.

(def users [{:subscription true :name "Y"} {:subscription true :name "Z"} {:subscription false :name "Z"}])

(sort (comparator (fn [u1 u2]
                    (cond
                      (= (:subscription u1) (:subscription u2))
                      (neg? (compare (:name u1) (:name u2)))

                      (:subscription u1)
                      true

                      :else
                      false)))
      users)
위 소스는 comparator를 만들고 하는 것이 아주 비슷하다.
아래 소스를 봐보자.
(sort-by (juxt (complement :subscription) :name) users) ;; forward sort
(sort-by (juxt :subscription :name) #(compare %2 %1) users) ;; reverse sort
워워 하나씩 보자.
(sort-by count ["aaa" "bb" "c"])

("c" "bb" "aaa")
juxt 이녀석은 뭘까? (juxtaposition : 병렬, 병치)
((juxt a b c) x) == [(a x) (b x) (c x)]
(for [user users]
  ((juxt :subscription :name) user))
;; ([true "Y"] [true "Z"] [false "Z"])


(for [user users]
  ((juxt (complement :subscription) :name) user))
;; ([false "Y"] [false "Z"] [true "Z"])

complement (보수 말하는건가) : 함수를 받아서 true/false의 반대값을 내보냄
(def odd?? (complement even?))
(odd?? 3)
true 
이걸 먼저 알아보자
(sort-by (juxt (complement :subscription) :name) users) ;; forward sort
user=> ((complement :subscription ) {:subscription "HI"})
false
user=> ((complement :a ) {:b "HI"})
true

두 줄로 만들어지는 것이 신기하다. juxt는 엄청난 함수 인 것 같다. 나중에 쓸일이 많을 것 같다.

2017년 11월 30일 목요일

[clojure][design pattern] 클로저 - 커맨드패턴

clojure design pattern 출처::http://clojure.or.kr/docs/clojure-and-gof-design-patterns.html#command


커맨드패턴(Command Pattern)

보면 알겠지만 커맨드(명령)을 login/logout명령으로 나눠서 따로 구현했다.
구현할 때 Command 인터페이스를 구현하여 execute(실행해라!)모든 명령을 이 인터페이스가 있는 녀석으로 구현하면
뭐든 간에 execute만 실행하면 될 것이다.

(defn login [id pass] (println "id: " id ", pass: " pass))

(defn logout [id] (println "logout: " id))

(defn execute [command]
  (do
    (println "logging")
    (command)))

;; 익명인터페이스와 동급

(execute #(login "name" "123"))  

(execute #(logout "idid"))

(defn execute [command & args]
  (apply command args))

(execute login "id" "password") 
apply를 사용하는 이유는 [command & args]에서 args는 리스트형태(?)로 반환하기 때문에 이 리스트 괄호를 깨부시고 안에 들어가서 적용(apply)해야 한다.

(defn wrong-execute [command & args]
  (command args))
(wrong-execute login "id" "password")

ArityException Wrong number of args (1) passed to: user/login  clojure.lang.AFn.throwArity (AFn.java:429)
보는바와 같이 login에는 잘못된 숫자의 매개변수가 들어간 것이다.
아마
(login ["id" "password"])
요래 들어갔을 것이다. 이렇게 실행해보자.
user=> (login ["id" "password"])
ArityException Wrong number of args (1) passed to: user/login  clojure.lang.AFn.throwArity (AFn.java:429)
똑같다 이제 apply를 해보자
user=> (apply login ["id" "password"])
id:  id , pass:  password
nil
아까 apply를 이용하면 괄호들을 깨부수고 안으로 들어(?)간다고 했다.
(apply login ["id" "password"]) == (login "id" "password")
요래 들어가는 것!!! (apply를 꼭 써야 한다.)
============================

이게 왜 중요하다는 거지?

일단 커맨트패턴이 뭔지보자. (자바의 눈으로)

execute()하나를 함께 쓰기 위해서 Command라는 인터페이스를 각각 구현하는 것이다.
그러면 login/logout을 하기 위해 login,logout클래스를 만들고 Command라는 인터페이스를 구현할 것이다.

자 그렇다면 로그인을 위한 Command 인터페이스를 클래스로 구현했다. 그리고 이제 이 클래스를 사용할 것이다.
아니!
정확히는 이 클래스에 있는 Command 안에 execute을 사용할 것이다.

이 커맨드들을 어딘가에 뒀다가 가져오려면 리턴도 되야하고 매개변수로 넣어지기도 해야 할것이다.
클래스는 그럴 수 없다.(뭔줄알고!!) 메소드를 넣을 수도 없다. 인터페이스를 넣는 것이다.
execute를 사용하기 위해!!

클로저의 눈으로 보자.
일단 클로저에서는 함수를 그냥 넘기기 때문에 개념이 아예 다르다.
그냥... 뭔 만들고 넣고 하는게 아니라...
함수를 보내고 받은걸 쓰면 된다.

뭐가 더 좋다가 아니라 이 두 개념을 마음대로 노닐 수 있는 내가 되었으면 좋겠다.

2017년 11월 16일 목요일

[clojure] loop: doseq,dotimes, while, loop, recur 정리

출처 : Clojure Loop

doseq

foreach 문과 비슷하다. 각각의 요소(element)를 돈다(iterate). 중요한 것은 lazy sequence를 강제(force) 평가(evaluation)한다.

(doseq [n (range 10)]
  (println n))
0
1
~
9

dotimes

일반 for문과 비슷하다. 숫자만큼 포문을 돈다.

(dotimes [i 10]
  (println i))
0
1
~
9

while

단순 while문과 비슷

(def a (atom 0))
(while (< @a 10)
  (do
    (println @a)
    (swap! a inc)))
0
1
~
9

loop/recur

loop를 이용하여 재귀를 돌 범위를 정한다. recur을 이용하여 loop의 값을 바꾼다.

(loop [i 0]
  (if (< i 10)
    (do (println i) 
        (recur (inc i)))
    i))
0
1
~
9

defn/recur

함수를 재귀

함수 이름을 부르지 않고 recur을 사용하는 이유는 tail recursion때문이다.

(defn increase [i]
  (if (< i 10)
    (do (println i)
        (recur (inc i)))
    i))
(increase 0)
0
1
~
9

[java]이클립스 JDK 패스 설정

-vm
 C:\Program Files\Java\jdk1.8.0_152\bin\javaw.exe
이런식의 내용을 eclipse.ini 에 맨 위에 넣는다.

2017년 8월 27일 일요일

Udacity Robotics Nanodegree Program 첫번째 프로젝트를 하면서 느끼는 점.

Rover Control

유다시티 강의의 첫번째 프로젝트. 로버가 저절로 길을 찾아가기이다.
Robotics 강의가 뭔지 잘 몰랐고, C++가 필요하다 하길래 C++와 나름 친숙해지고 자신감을 가지고 수강을 했다.

낭패였다

Robotics에서는 로봇을 칭할 때, 3가지가 필요하다.
  1. Perception
  2. Decision Making
  3. Action
C++ 같은 것이 중요한 것이 아니라.
  1. 상황을 인지하고
  2. 어떻게 할지 결정하고
  3. 행동을 하는 것
이것을 어떻게 해내야 할지. 고민하고 기법들을 좀 더 공부해 놓는 것이 더 도움이 될 것이었다.
파이썬을 회사에서 사용해보긴 했지만, 데이터 시각화나 수학적 계산은 다른 문제다.
여차여차 유다시티에서 하는 강의들을 따라가고 있지만 과연 얼마나 더 할 수 있을지는 미지수다.
주말마다 이것 때문에 어딜 나가지 못한다...
정말 이번에 느낀 것은... 선형대수가 정말 중요하다는 점!
계속 공부하지 않으면 안되겠다!

게다가 나는 자바로 개발을 하고 있는데도 요즘 자바에 너무 관심을 끈게 아닌가 싶다.
자바에도 따로 관심이 있는 분야가 있는데(JAVA - ASM 라이브러리 이다. 정말 멋진 기술이라고 생각한다.)
언젠가 이것도 좀 더 공부해서 토이프로젝트로 하나 뭔가 만들어봤으면 좋겠다. (ASM하나만을 이용해서!)
너무 주저리 주저리 쓴건가.
아래에 현재 하고 있는 프로젝트의 링크를 담아놓아야겠다.

2017년 8월 17일 목요일

[서평] Node를 사용한다면 어디로 가야 하는지 가르쳐주는 [Node.js 6.x 블루프린트]


나는 Node.js에 대해 잘 알지 못한다. Node.js 자바스크립트만 알면 된다는 장점을 내새워 치고 올라오고 있는 기술 중 하나이다.
Node.js는 커지는 신생 기술인만큼 변화의 물결이 크다.(지금도 초기 만큼 변화가 큰지는 모르겠지만) 그만큼 개발자체와 새로운 변화를 사랑하는 사람들에게는 행복할 것이다.

해도해도 너무하다는 말도 많을 것이다.

내가 Node.js에 대해 잘 알지도 못하면서 이런 말을 하는 이유는 Node관련 세미나를 한 번 견학한 적이 있기 때문인데 그때도 1년에 다르게 새로운 기술이 나오고, 이전 기술이 옛것이 되면서 크게 발전하고 있다는 것이다.

그러므로 기존에 사용하던 모듈이 금방금방 deprecated 되는 현상을 맞볼 것이라고 한다.

예를 들자면,
이 책에서 promise라는 기술을 콜백 지옥에서 벗어나기 위한 기술로 소개한다. 하지만 내가 견학했던 세미나에선 이렇게 말했다.

"Promise도 이젠 옛말이죠. 이런 다른 걸 씁니다."

이 격한 파도의 물결을 온몸으로 받아치고 싶다면, Node.js를 그래도 알아야만 한다면

당신은 이 책을 읽어야 한다.

이 책은 말그대로 청사진이다. Node.js는 너무 많은 변화가 자칫 어디로 가야할지 헷갈리게 할 수 있다. 여기저기서 소위 약파는(?) 기술들이 많기 때문이다.

이 책을 한 번 읽으면 Node.js라는 기술이 어디로 가고 있는지 알 수 있을 것이다.

2017년 8월 8일 화요일

Udacity Robotics Nanodegree Program 수강시작!

인강 하나 듣는데 전공, 경력, 게다가 자소서까지 썼다. 이렇게까지 해서 들을 가치가 있을까. 했지만 쓰는게 어려운 것은 아니므로 보냈다. 

Robotics Nanodegree slack을 바로 열어줬는데, 다들 이미 로봇전공인 사람들이 많아보여서 나는 아무말도 하지 않고 가만히 있었다. (분명 떨어졌으리라 생각했다.)

그리고 2개월이 지나서 유다시티 Robotics Nanodegree를 수강 할 수 있게 되었다.

보기에는 엄청난(?) 경쟁률을 뚫고 내가 되었다는데 사실여부를 알 수 없다.

가격도 엄청나게 비싸다. 게다가 저게 끝이 아니다. (한 번 더 내야 하는...)

Cousera, Udemy, Udacity를 전부 사용해보았지만 항상 느낀 것이 Udacity에는 활기가 넘치는 것이 느껴진다. 가르치는 것을 즐기는 듯한 느낌이 들어서 제대로 돈을 주고 배워보고 싶은 마음이 있었다.

하지만 내 일과가 Udacity가 전부는 아니기 때문에
과연 잘 할 수 있을지 의문이지만, 
나는 열심히 해왔고, 또 더 열심히 할 것이니까
해낼 것이다.

2017년 7월 17일 월요일

[python][django] RuntimeWarning: DateTimeField received a naive datetime 에러

DateTimeField에 날짜를 테스트하려 할 때 문제가 발생했다.
from datetime import datetime
AA.objects.create(my_date=datetime.now())
장고는 날짜에 Timezone을 추가해서 사용한다. timezone을 함께 넣어주던가
사용하지 않는다고 명시하던가 해야한다.
from django.utils import timezone
AA.objects.create(my_date=timezone.now())

[python][django] Model 테이블의 이름을 변경하려면 어떻게 해야 할까?

makemigrations 손보기

ORM에 대해서 많이 들어보고 그냥 쓰면 좋다는 생각에..
그리고 장고를 사용하면 자연스럽게 쓸 수밖에 없기에 그 편리함에 놀라워했다

makemigrations와 migrate만 알면 전부 다 될 줄 알았다. 하지만 이제 알겠다.
편리하기 위해선 많이 배워야 함을... 어쩌면 한 번도 사용한 적이 없어서일지도 모르겠다.
여하튼
단순히 Model명을 변경하고 makemigrations를 하면 에러가 난다.
장고는 내 맘과 같지 않아서, 이 모델이 rename된건지 확신하지 못하는 것같다.
그러면 내가 확신을 가지도록 명시해줘야 한다.
일단 원래대로 돌려놓고
python manage.py makemigrations --empty <앱이름>
이렇게 하면 makemigrations의 빈 통이 보인다. 다른건 보지말고 얘만 보자.
...
operations = [
]
이 안에다가 무슨일을 한 건지 적어준다.
operations = [
  migrations.RenameModel(
    old_name='Pattern',
    new_name='MessagePattern',
    ),
]
이후 Model명을 바꾸고 사용하고 있는 다른 파일들 모델명을 전부 바꾼다.

출처: 이것저것 바꾸다가 makemigrations 스키마가 이런걸 사용하는 것을 확인. python 도큐먼트를 뒤늦게 확인

[python] 파이썬 디렉터리 삭제하기

os.removedirs, shutil.rmtree

단순히 디렉터리를 삭제할 때는 os.removedirs를 사용하는 것으로 가능하다.
import os

os.removedirs(some_path)
하지만 디렉터리 안에 파일이 있다면 삭제되지 않는다. 그럴땐
import shutil
shutil.rmtree(some_path)
이렇게 삭제하자

2017년 7월 7일 금요일

[python] eval 악마와의 계약

eval()을 사용해보자

후위표현식 AB+를 A+B로 변환해서 산술연산하는 함수를 만들자.
def postfix_eval(expr):
    operand_stack = []
    token_list = postfix_expr.split()

    for token in token_list:
        if token in '0123456789':
            operand_stack.append(int(token))
        else:
            operand2 = operand_stack.pop()
            operand1 = operand_stack.pop()
            result = do_math(token, operand1, operand2)
            operand_stack.append(result)
    return operand_stack.pop()

def do_math(op, op1, op2):
    if op == "*":
        return op1 * op2
    elif op == "/":
        return op1 / op2
    elif op == '+':
        return op1 + op2
    else:
        return op1 - op2
실행
print(postfix_eval('7 8 + 3 2 + /'))
여기서 주목할 것은 do_math
여기 do_math의 내용을 이렇게 바꾼다면
def post_math(op, op1, op2):
    return eval(op1 + op + op2)
테스트를 해보자.
post_math('+', '1', '2')
3
문자열을 그대로 맘대로 합쳐서 그 문자열 자체를 평가
이런 것에 대한 엄청난 효과를 볼 수 있는 것은 리스프 형태일 것 같다.
다음엔 python 리스트 형태 언어인 hy로도 조금씩 적어봐야겠다.

2017년 7월 4일 화요일

Extra Long Factorials python3

사실 푼 것도 아님. 그런데 너무 빨라서... 널 쓸 수 밖에 없었단다...
#!/bin/python3
import sys
from math import factorial

n = int(input().strip())

print(factorial(n))

2017년 7월 1일 토요일

[python][트리] 백준 알고리즘 1991번

테스트를 위해 인풋을 파일로 만들었음.
할일
  1. 파일을 읽어온다.
  2. 파일을 정재하여 리스트에 넣는다.
  3. 간단한 트리구조로 변환할 함수를 만든다
  4. 트리의 루트를 글로벌로 하나 생성한다.
  5. 트리구조의 리스트로 변환한다
  6. 전위, 후위, 중위 탐색을 함수를 만든다.
  7. 출력한다.
1. 파일을 읽어온다. 2. 파일을 정재하여 리스트에 넣는다.
def readFile(filename):
  with open(filename) as file:
    return [ x.strip('\n').replace(' ','') for x in file.readlines()]
list_ = readFile('1991.txt')

3. 간단한 트리구조로 변환할 함수를 만든다. 4. 트리의 루트를 글로벌로 하나 생성한다.
def my_tree(r):
    return [r, [], []]
root = None

5. 트리구조의 리스트로 변환한다.
def add(data, left, right):
    global root
    if root is None:
        if data != '.':
            root = my_tree(data)
        if left != '.':
            root[1] = my_tree(left)
        if right != '.':
            root[2] = my_tree(right)
        return root
    else:
        return search(root, data, left, right)

def search(root, data, left, right):
    if root is None or root == []:
        return root
    elif root[0] == data:
        if left != '.':
            root[1] = my_tree(left)
        if right != '.':
            root[2] = my_tree(right)
        return root
    else:
        search(root[1], data, left, right)
        search(root[2], data, left, right)


for l_ in list_[1:]:
    add(l_[0],l_[1],l_[2])

6. 전위 후위 중위 탐색 함수를 만든다.
def preorder(root):
    if root:
        print(root[0], end='')
        if root[1]:
            preorder(root[1])
        if root[2]:
            preorder(root[2])

def inorder(root):
    if root:
        if root[1]:
            inorder(root[1])
        print(root[0], end='')
        if root[2]:
            inorder(root[2])

def postorder(root):
    if root:
        if root[1]:
            postorder(root[1])
        if root[2]:
            postorder(root[2])
        print(root[0], end='')

7. 출력한다.
preorder(root)
print()
inorder(root)
print()
postorder(root)
print()