'Language'에 해당하는 글 98건

<private 멤버는 언제 왜 써야 하는가?>

괜히 private 키워드를 남발하다가 개발을 딜레이시키는 경우가 있었다.

private는 어떤 변수/메서드에 사용해야 하는걸까?

우선 나쁜 예로서, 변수를 private로 선언하고 get/set 메서드로 public 변수처럼 사용하는 경우는 불필요하게 private 키워드를 사용한 경우이다

private 키워드의 필요성을 알아보자. 데이터에 access하는 코드가 프로그램 여기저기에 분산되어 있을경우 유지보수가 어려워지게 된다

그러므로 변수를 private로 선언하고 data에 access하는 코드를 class 내의 method에서만 관리함으로써 유지보수를 편리하게 만드는 것이다

unittest, design pattern과 마찬가지로 private 키워드의 필요성 또한 프로젝트 규모와 비례하게 된다


<프로젝트 규모의 기준은?>

프로젝트 규모를 따질필요 없이, 우선 변수를 public으로 선언하여 사용하면 된다.

이때 변수에 access하는 코드가, 특히 중복코드가 많아진다면 해당 변수는 private 키워드로 바꿔주면 되는 것이다. 간단.

중복코드는 유지보수를 어렵게 만드므로, 프로젝트 규모보다는 중복코드가 많아질 때 private 키워드를 사용하면 된다.


<정리>

method보다는 변수 위주로 private 키워드의 필요성에 대해 설명했다

private 키워드는 data access 중복코드를 제거하고, 유지보수를 편리하게 만들수 있다

OOP가 나온 배경이 그렇듯, private 키워드 또한 프로젝트 규모가 커져야 비로소 필요성이 생긴다

일단은 굳이 private 키워드를 사용할지 고민하지말고, public으로 선언하여 사용하다가

중복코드가 많아질 때 private 키워드로 교체하는 식으로 사용하자

한마디로 요약하면, data access 중복코드가 많아질 때가 private 키워드가 필요할 때라는 것으로 글을 마무리한다


'Language' 카테고리의 다른 글

[C/C++] gcc option (추천 옵션)  (0) 2017.12.18
[C] 2D 배열 포인터 example (Pointer to 2D array)  (0) 2017.12.18
[OOP] [Design Pattern] State Pattern  (0) 2017.12.11
cmake 변수 설정방법  (0) 2017.12.07
cmake clean command  (0) 2017.12.06

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

1
2
3
4
5
6
7
8
import unittest
 
class MyTest(unittest.TestCase):
    def test_func(self):
        self.assertEqual(4+6 // 25# fail
 
if __name__ == '__main__':
    unittest.main()
cs


<unittest의 필요성>

프로그램 규모가 커질수록, 전체 프로그램 단위로 테스트하면 테스트 시간도 오래 걸리고

에러가 발생했을 때 디버깅도 점점더 어려워진다

이 때, unittest는 unit 단위로 테스트함으로써 테스트 시간과 디버깅을 쉽게 만들어준다

그러므로 규모가 작은 프로젝트에서는 필요성을 못느끼지만, 규모가 커질수록 필요성이 느껴질 것이다

(디자인 패턴과 같은 맥락이다)


<사용법>

1. unittest.TestCase를 상속받는 클래스

2. 테스트할 메서드 이름은 'test'로 시작

3. unittest.main() 콜



'Language > python' 카테고리의 다른 글

[python] 추상클래스(abstract class) - abc module  (0) 2017.12.16
[python] logging example  (0) 2017.12.16
[python] numpy 함수들  (0) 2017.12.14
[python] skimage ndarray shape (HWC, CHW)  (0) 2017.12.14
[python] ctypes API example  (0) 2017.12.13

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

import numpy as np


# array(...)

arr = np.array([1,2,3]) # 1 dimension array

arr = np.array([[1,2,3],[4,5,6]], np.int32) # 2 dimension array as type int32


# zeros((w, h, ...)) # empty array

arr2 = np.zeros((2,3), np.float32) # == [[0,0,0],[0,0,0]] as type float32


# arange(n)

arr3 = np.arange(10) # == [0,1,2,...9]


# reshape(w, h, ...)

arr3 = arr3.reshape(2,5) # == [[0,1,2,3,4],[5,6,7,8,9]]


---


# swapaxes()

arr.shape # (2, 3)

arr = arr.swapaxes(0, 1) # axe 0와 axe 1을 swap함

arr.shape # (3, 2) # shape을 통해 바뀐 axe 쉽게 확인가능


'Language > python' 카테고리의 다른 글

[python] logging example  (0) 2017.12.16
[python] unittest library - simple example  (0) 2017.12.15
[python] skimage ndarray shape (HWC, CHW)  (0) 2017.12.14
[python] ctypes API example  (0) 2017.12.13
[python] ctypes.memmove() example  (0) 2017.12.13

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

<HWC?>

caffe2에서 image pre-processing을 하는데, HWC, CHW가 나와서 의미를 찾아보게 되었다

H=height

W=width

C=channels


<Channels?>

특히 channels의 경우, gray-image이면 1, RGB이면 3, RGBA이면 4이다

ex) (360, 480, 3)

height=360

width=480

channels=3


'Language > python' 카테고리의 다른 글

[python] unittest library - simple example  (0) 2017.12.15
[python] numpy 함수들  (0) 2017.12.14
[python] ctypes API example  (0) 2017.12.13
[python] ctypes.memmove() example  (0) 2017.12.13
[python] REST API request using python  (0) 2017.12.09

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

-- ctypes --


from ctypes import *


# pointer

pStr = c_char_p(b'hello')

pSth = POINTER(somthing_type)

# get data of pointer

pSth.contents # *p


# array

arr = (c_char * 100)()

2dArr = (c_char * 10 * 100)() # char arr[100][10], 곱 순서 반대 주의

# get data of array

python array와 사용법 동일


# get address of data

addressof(arr)


# get size of data

sizeof(arr)


# memmove()

http://ssaemo.tistory.com/94


# c function (result type, args...)

@CFUNCTYPE(c_int, c_int)

def callback(num):

    return num


--- numpy ---


numpy는 ctypes와 compatibility를 제공하고 있다 (그 외 struct)

numpy도 함께 사용하면 편리할 때가 있으니, 추가로 알아보자


# numpy empy array

numpy.zeros((row_cnt, col_cnt))


'Language > python' 카테고리의 다른 글

[python] numpy 함수들  (0) 2017.12.14
[python] skimage ndarray shape (HWC, CHW)  (0) 2017.12.14
[python] ctypes.memmove() example  (0) 2017.12.13
[python] REST API request using python  (0) 2017.12.09
[python] random list with no duplicates  (0) 2017.12.08

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# memmove(dst, src, size) == memcpy(dst, src, size)
# usage of pointer equals to array
 
src = (c_char*100)(1,2,3,4# array declare
 
# array
pStr = c_char_p(b'kkkk'# pointer to b'hello' declare
print(pStr.value) # output: b'kkkk'
memmove(pStr, src, sizeof(pStr))
print(pStr.value) # output: 1,2,3,4
 
dst = (c_char*100)(5,5# array declare
print(dst.value) # output: 5,5
memmove(dst, src, sizeof(dst))
print(dst.value) # output: 1,2,3,4
 
cs


memmove의 첫번째, 두번째 파라미터는 data의 address(int)로도 사용가능하다

memmove(ctype, ctype, int)

memmove(int, int, int)


이것은 numpy와 ctypes를 함께 사용할 때 유용하다

ndarr.ctypes.data를 통해 array의 address를 얻을 수 있고, 이것으로 memmove를 사용할수 있기 때문이다

'Language > python' 카테고리의 다른 글

[python] skimage ndarray shape (HWC, CHW)  (0) 2017.12.14
[python] ctypes API example  (0) 2017.12.13
[python] REST API request using python  (0) 2017.12.09
[python] random list with no duplicates  (0) 2017.12.08
[python] selenium install  (0) 2017.11.30

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

<Design Pattern>

디자인 패턴은 OOP에서 사용하는 개념으로, Object를 더 flexable하게 만듬으로써 "복잡한 구조"를 간단하게 만들고 / Object의 재사용성을 높이고 / 수정(유지보수)을 편리하게 해주는 효과가 있다


하지만 간단한 구조에서 남용하면 오히려 구조를 더 복잡하게 만드는 경향이 있다.

이 부분은 State Pattern을 보면서 이해해보도록 하자


<State Pattern의 필요성>

State Pattern이 언제 필요한지부터 살펴보자

"사람"이라는 Object가 있고,

이 Object는 아래와 같은 method들을 가지고 있다고 생각해보자

 - 밥 사먹기

 - 음료수 사먹기

 - PC방 가기

 - 찜질방 가기

 - 차에 기름넣기

그리고 마지막으로 "돈"이라는 멤버 데이터를 가지고 있다!

(편의상 가격은 없이, 돈이 있다(true)/없다(false)의 상태만 가진다고 가정한다)

이 모든 method들은 돈이 있거나/없는 "상태"에 따라 동작이 다르다

그리고 보통 이것은 조건문을 통해 구현된다


밥_사먹기()

{

....if no money:

........return;

....// code

}


조건문으로 구현하면 되는데, Design Pattern이 왜 필요한가?

그것은 우리의 method가 많기 때문이다

method가 많으면 무엇이 문제가 되느냐? 중복코드가 많아진다는 것이다

method 5개이므로 중복된 조건문도 5개가 들어간다

이때, "돈"이라는 상태 외에 "건강함"이라는 상태도 추가한다고 해보자

위 조건문이 아래와 같이 바뀌는 것으로.


if no money or no health:

....return;


조건문을 수정해야하는데, 5개의 중복코드가 있으므로 이 작업을 5번 해줘야 한다는 것이다

이것은 귀찮음과 실수를 유발할 수 있다

그런 이유에서, 중복코드를 제거하고자 State Pattern을 적용할 수 있다


<State pattern>

State라는 5개의 method가 선언된 interface가 있고, 그것을 구현한 EnabledState / UnabledState가 있다고 하자

State Pattern을 적용한 "사람"이라는 Object는 State라는 멤버를 추가로 가지게 된다

그리고 위 5개의 method들을 State에게 맡기는 것이다

현재 State가 EnabledState면, 밥사먹기 등이 성공적으로 동작할 것이고, 

UnabledState이면 "돈"이 없거나 "건강하지 않은" 상태인 것이므로 method들은 아무것도 하지 않을 것이다


코드를 첨부하지 않아서 설명이 추상적일 수 있다

코드 설명은 아래 글을 참조하자

http://secretroute.tistory.com/entry/Head-First-Design-Pattern-%EC%A0%9C10%EC%9E%A5-State-%ED%8C%A8%ED%84%B4


State Pattern을 사용함으로써 중복코드를 제거하고, 코드 수정을 더 편리하기 만들었다

이러한 효과는 모든 Design Pattern이 가지는 것이며, State Pattern을 설명하여 그것을 조금더 구체적으로 보였다


---


코드 추가하였음


<code example>

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from abc import *
 
#################### context ####################
 
class Context:
    def __init__(self):
        self.idle = IdleState(self)
        self.sleep = SleepState(self)
        self.state = self.idle
    
    def sum(self, a, b):
        return self.state.sum(a, b)
    
    def wake_up(self):
        self.state = self.idle
        
#################### state ####################
 
class State:
    def __init__(self, context):
        self.context = context
    
    @abstractmethod
    def sum(self, a, b):
        pass
    
class IdleState(State):
    def sum(self, a, b):
        # set now_state <- sleep_state
        self.context.state = self.context.sleep
        return a+b
    
class SleepState(State):
    def sum(self, a, b):
        return None
 
#################### main ####################
    
if __name__ == '__main__':
    context = Context()
    print(context.sum(12)) # return 3 and set now_state <- sleep_state
    print(context.sum(34)) # None (sleep state)
    context.wake_up() # set now_state <- idle_state
    print(context.sum(56)) # return 11 and set now_state <- sleep_state
cs


<코드 설명>

context 클래스는 sum이라는 기능을 가지고있는데, 

idle state에서만 정상값을 리턴하며

값을 리턴하고나면 sleep state로 진입하게 되어있다


첫번째 context.sum()을 호출하면 idle state이므로 정상값을 리턴하고 sleep state로 바뀌게 된다

두번째 context.sum()을 호출하면 sleep state이므로 None이 리턴된다

context.wake_up()을 호출하여 idle state로 바꾼다

마지막 context.sum()을 호출하면 idle state이므로 정상값을 리턴하고 다시 sleep state로 바뀌게 된다


같은 메서드 콜이지만 context의 state에 따라 메서드 동작이 바뀌는 것을 확인할 수 있다

int값를 통해 state를 구현한다면 메서드 갯수에 비례하여 중복코드가 생기지만, state pattern은 그런 중복코드를 제거할 수 있다

'Language' 카테고리의 다른 글

[C] 2D 배열 포인터 example (Pointer to 2D array)  (0) 2017.12.18
[OOP] private 키워드의 필요성  (0) 2017.12.15
cmake 변수 설정방법  (0) 2017.12.07
cmake clean command  (0) 2017.12.06
[gcc option] linker option -Wl, -rpath, -L, -l  (0) 2017.12.06

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

https://stackoverflow.com/questions/17301938/making-a-request-to-a-restful-api-using-python


import requests
url = 'http://ES_search_demo.com/document/record/_search?pretty=true'
data = '''{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'''
response = requests.post(url, data=data)



'Language > python' 카테고리의 다른 글

[python] ctypes API example  (0) 2017.12.13
[python] ctypes.memmove() example  (0) 2017.12.13
[python] random list with no duplicates  (0) 2017.12.08
[python] selenium install  (0) 2017.11.30
[python] list in for-loop syntax (+tuple)  (0) 2017.11.29

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

중복없는 랜덤 리스트 생성하기 (파이썬)

1
2
3
4
5
6
7
8
9
def random_list(n):
    temp = list(range(n))
    result = []
    while len(temp) > 0:
        idx = int(random() * len(temp))
        result.append(temp[idx])
        del temp[idx]
    return result
 
cs




WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

cmake 변수 설정방법

Language 2017. 12. 7. 15:11

Caffe2를 예로 들어서, Caffe2 cmake를 할때 다음과 같은 변수들이 있다


USE_FFMPEG

USE_OPENCV

CMAKE_C_FLAGS

CMAKE_CXX_FLAGS


make의 경우 환경변수를 인식하기 때문에, 다음과 같이 실행하면 된다


export USE_FFMPEG=ON

make


또는


USE_FFMPEG=ON make


하지만 cmake는 그렇지않다

cmake는 환경변수가 세팅되어 있어도, 기대와 같이 동작하지 않는다


export USE_FFMPEG=ON

cmake # don't work expected


cmake 변수를 세팅할 때는 -D 옵션을 사용해야한다

주의할 점은 -D와 변수 사이에 공백이 있으면 안된다


cmake -DUSE_FFMPEG=ON -DUSE_OPENCV=ON -DCMAKE_C_FLAGS='-Wl,-pthread' -DCMAKE_CXX_FLAGS='-Wl,-rpath,/root/ffmpeg/lib'


cmake와 make의 변수 세팅방법이 서로 다르다는 걸 알아두고 헷갈리지 말자


'Language' 카테고리의 다른 글

[OOP] private 키워드의 필요성  (0) 2017.12.15
[OOP] [Design Pattern] State Pattern  (0) 2017.12.11
cmake clean command  (0) 2017.12.06
[gcc option] linker option -Wl, -rpath, -L, -l  (0) 2017.12.06
[git] merge, git pull, branch 팁/노하우  (0) 2017.12.05

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

cmake clean command

Language 2017. 12. 6. 16:46

https://m.blog.naver.com/PostView.nhn?blogId=abc2185&logNo=220554215720&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F


rm -rf CMakeCache.txt

rm -rf CMakeFiles



WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

-Wl부터 소개한다


https://stackoverflow.com/questions/6562403/i-dont-understand-wl-rpath-wl


1. c source code -> gcc -> obj

2. obj -> ld -> elf

위와 같이 링킹과정을 분리하는 것이 아니라


src -> gcc -> elf

위와 같이 한번에 컴파일할 경우, linking 옵션을 주기 위해서는 -Wl 옵션이 필요하다

아래는 모두 동일한 커맨드이다 (직접 실행해보진 않았으므로 차이가 있을수도 있다)

여담으로, gcc 옵션 중 W로 시작하는 옵션들이 많이 있는데 서로 관련이 있지는 않은듯 하다

예를 들면 -Wall은 warning 옵션 -Wl은 linking option임을 gcc manpage에서 확인할수 있다


gcc -Wl,-rpath,.

gcc -Wl,-rpath -Wl,.

ld -rpath .


---


다음은 -rpath다

https://stackoverflow.com/questions/8482152/whats-the-difference-between-rpath-and-l


runtime library path의 줄임말로, shared object(.so)파일의 path를 입력한다

그러면 프로그램 실행 시 입력한 path를 search한다는듯 하다


---


<-rpath vs -L>

우선 -L은 그 디렉토리 안에 모든 라이브러리들에 대해 -l을 부여하는 옵션이다

이 둘의 차이는 -rpath는 so 파일만, -L은 .a or .so 파일을 모두 linking 하는 것 같다

(이 또한 manpage와 서치를 통한 내용일 뿐 직접 실행해보진 않았으므로 다소 차이가 있을 수 있다)



WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

<git merge와 git pull>

git 커맨드 종류가 다양해서 외우고 이해하기 힘들수도 있는데

그 중 git merge와 git pull는 비슷한 커맨드이다

git merge : local branch와 local branch를 merge(병합)한 commit을 생성한다

git pull : local branch와 remote branch를 merge한 commit을 생성한다

정말 그럴까?


master와 my_branch라는 두 개의 브랜치를 사용한다고 할때

git pull은 보통 local/master 브랜치로 remote/master 브랜치를 가져올 때 사용한다

또는 local/my_branch로 remote/my_branch를 가져오는 것도 마찬가지이다

(좀더 자세하게 설명하면, 위와 같이 사용할 경우 merge라기보다는 forward된다)

그런데 이걸 cross하여 사용하면, 즉 local/master 브랜치로 remote/my_branch 브랜치를 가져오면

이 둘이 merge된 commit이 생성된다

결론적으로 merge와 pull 커맨드의 차이점은 local이냐 remote냐의 차이점 뿐이다


---


<git merge와 branch>

merge에 대해 또한가지 설명하자면

merge는 branch 2개가 branch 1개로 되어 하나의 브랜치가 사라지는 작업이 아니다

merge 후에도 여전히 branch들은 각각 유효하다

이와 관계된 이야기로, 필자는 최근 프로젝트를 할때 branch를 아래와 같이 네이밍하여 생성하는 실수를 했었다


branch: master / map_api / db_connect / data_structure_update / ...


작업단위마다 branch를 생성/작업/merge 했고, 사용하지 않는 branch들이 계속 생겨났다

branch는 merge 후에도 계속 사용할 수 있으므로, 작업단위로 네이밍하는 것은 불필요하다

그래서 아래와 같이 네이밍했다


branch: master / hojong / kmk(팀원의 브랜치)


hojong 브랜치만 생성하고, 그 브랜치에서 작업/merge/작업/merge를 반복하여 사용했다

merge 후에도 각 branch들은 vaild하므로 브랜치를 생성 및 사용할 때 위와 같은 내용을 참고하면 좋을 것이라고 생각하여 작성하게 되었다




WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

<전제>

github.com에 회원가입을 먼저 해야한다

git이 설치되어 있어야한다 (source tree를 사용해도 된다)


1. github에 remote repository를 생성한다

 

 

 

.gitignore에서 Unity를 꼭 선택해주자

그렇지 않으면 불필요한 Library, Temp 파일들이 모두 커밋되어 용량이 심각하게 커진다


 

github url은 위와 같이 카피해올 수 있다

 

2. Unity 프로젝트 디렉토리에서 cmd를 실행하고 아래 커맨드를 실행한다

git init

git remote add origin https://github.com/ssaemo/Unity-2D-Side-Scroll.git

git pull origin master

git add .

git commit -m "first commit"

git push origin master # origin으로 local master commit을 push

git init : 

 - local repository 생성

git remote add <name> <remote-url> : 

 - local repository에, remote repository를 등록한다.

 - origin은 default name이고, remote-url은 github repo 페이지에서 카피해올 수 있다

git pull origin master

 - origin(remote repo)을 local repo의 master branch로 가져온다(pull)

 - master는 default branch이다

git add .

 - 모든 파일들을 index에 올린다 -> 모든 파일들을 commit하겠다는 의미

 - pull을 통해 .gitignore 파일이 생성되었으므로 불필요한 파일들은 무시된다

git commit -m "커밋내용(message)"

 - 메세지와 함께 local repo에 commit한다

 - 커밋메세지는 필수이며, 변경사항을 특정 commit으로 되돌릴 때 확인하기 위해 메인 변경사항을 메모한다

git push origin master

 - origin에 local repo master branch의 새로운 commit들을 올린다(push)

 

 


WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

github에 repository를 먼저 생성

(remote repo에는 .gitignore와 LICENSE가 commit되어있는 상태)


git init

git remote add origin https://github.com/ssaemo/asyncio-irc-client.git

git pull origin master # origin으로부터 local master로 가져옴

git add .

git commit -m "first commit"

git push origin master # origin으로 local master commit을 push


이 글을 포스팅하다가 git pull에 대해 설명을 적으면 좋겠다 싶어, 아래와 같은 글을 작성하였다

참고하면 좋을 것같다


<git merge, git pull, branch 팁/노하우 공유>



WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/

아래 페이지에 대한 번역이다

https://www.quora.com/What-are-the-advantages-of-non-blocking-IO

오역이 많을 것으로 예상되오니 태클 및 지적은 환영합니다


non block IO를 사용하면 IO request와 실제 IO작업(actual delivery)를 분리할 수 있다. 결과적으로 우리는 request task를 계속 진행할 수 있다



  • request file
  • do
  • something else
  • until file is there

  • file을 읽어오는 방법은 2가지가 있다.

    하나는 blocking IO를 사용하여 file을 다 읽어올 때까지 기다리는 것,

    다른 하나는 file을 다 읽어올 때까지 loop를 도는 것인데, 이 loop는 busy loop가 되거나 event driven으로 처리할 수 있다

    이것은 데이터가 읽어졌을 때, request file 커맨드가 event를 발생시키고 프로그램이나 함수를 실행하는 것을 의미한다


    대부분의 GUI에서 non block IO를 볼수 있는데, menu에서 오는 모든 것들이 event driven인 부분에서 볼수 있다

    Java에는 event driven으로 동작하지 않는 나쁜 예시들이 있으며, 잘못 작성된 GUI event 응답 코드 ㅡ 몇몇 Java 관련 서적에서 논의되고 있는 ㅡ 로부터 "Java는 느리다"라는 불만이 있다


    But that’s not just true for Java, but there it’s very obvious when it happens


    대부분의 전통적인 프로그래밍 훈련들은 bad blocking IO로 접근하기 때문에,

    당신이 프로그래머로서 시작하고 학교에서 나왔다면,

    실용적이고 modern한 S/W를 작성할 때 기초부터 다시 배워야 합니다

    특히 GUI같은 느린 IO (사람에 의한 입력)이나 네트워크 IO를 이용하는 어떤 프로그램을 작성할 때는 특히 더 그렇다

    하지만 대부분의 IO와 flow hog라고 볼수있는 (느린) 연산에도 해당하는 이야기이다

    Always try to spawn number crunching off your main process like everything that takes time and create an event for the moment when it’s ready.


    이것은 애플리케이션의 반응성에 의한 트러블로부터 안전해질 뿐만 아니라 이것은 "연산을 병렬처리하는 멀티프로세싱"을 구현하기 위한 좋은 단계(step)이다

    이 다음에 논리적인 단계가 있습니다


    Event-driven program structures are more or less what you need on modern systems,

    하나 예외는 리눅스에서 shell 기반의 입력-연산-출력 구조의 프로그램이다

    이것은 왜 리눅스에서 프로그래밍하는 것이 아주 쉬운 이유이고 적은 코드로 문제를 해결할수있는 이유이다 : 쉬운 흐름 구조 덕분이다


    하지만 OS는 여전히, 어쨌든 kernel level에서는 non blocking IO를 할것이고, 단지 프로그램은 blocking IO call에서 block될 것이다

    이것은 이전에 논의된 방식이다

    특정한 모던 언어들은 non blocking IO를 더 쉽게 만들려고 노력하고 있다 (애플리케이션 레벨에서), Javascript처럼

    하지만 필자는 그것이 일반적으로 가능하다고 생각하지 않는다

    이것은 그저 JS에서만 잘 작동하는 것이다, 왜냐하면 JS는 주로 event-driven 방식으로 동작하는 GUI 기반 언어이기 때문이다

    이것을 native로 하는 또다른 유일한 언어는 AWK이다. 이것은 당장 만나볼 수 있다 (come up)


    AWK는 프로그램이 복잡해지고 사이즈가 증가할 때마다 messy해진다는 점에서 비판받는다

    그리고 모든 event-driven GUI 기반 프로그램들도 마찬가지이다

    GUI driven 프로그램은 데이터 흐름을 이전 또는 이후로 엉망으로 만들고(mess up) AWK에서 이미 발견된 동일한 문제들과 fight하기(싸우기) 시작한다


    그러므로 event-driven 프로그래밍 구조를 train하길 원한다면 there is hardly a way around something like AWK

    event driven 방식이 메인인 다른 언어들(특히 JS같은)을 찾을지도 모른다, 하지만 많지는 않다.

    실제로 (in effect) AWK로 구현한 것같은 상태머신(state-machine)이 얻어지는데, 그것이 바로 event-driven non-blocking IO 프로그램을 구현하기 위한 것이다


    무슨 일이 일어나고있는지 추적(track)은 가능하지만, 조심해야하고 스스로 train해야한다. 그렇지않으면 프로그램이 복잡해질수록 심각한 트러블을 겪을 것이다

    이것과 느슨하게 연관된 각 문제들이(메모리 누수, 가끔씩 발생하는 NULL 포인터 예외같은) 시작하면 빈번한 가비지 컬렉팅 등등 수많은 very ugly bugs의 원인을 찾는것이 드럽게 힘들다(ugly hard)


    진짜로 힘들다. 왜냐하면 디버거를 통해 그 원인들을 찾는것에 문제가 있기 때문이다.

    디버거는 전통적인 제어-흐름 구조에서 최고로 잘 동작하지만 event-driven 구조에서는 딱히 그렇지 않다

    My tip: AWK를 배워라 그리고 잠깐 AWK를 가지고 놀아봐라(play). 이것은 프로그램 플로우를 생각하는 방식을 바꿀 것이다. 그리고 그 후에는 그 지식을 어떤 GUI-driven 애플리케이션에든지 쉽게 이식(port)할 수 있을것이다


    ----


    대략적인 내용흐름은 non-blocking IO -> GUI event-driven -> program complexity -> AWK인듯하다

    결론적으로 non-blocking IO는 GUI event-driven이나 Network같은 IO를 처리할 때 반응성 또는 병렬처리 면에서 효과적(advantage)이다

    대신 프로그램이 복잡해지는 것은 어쩔수 없으므로 AWK를 먼저 접해보는 것을 tip으로 조언하고 있다

    (필자는 AWK는 사용한 적이 없어서 event-driven과 어떤 연관인지 잘 모르겠으나)



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    TDD: Test-Driven Development

    test를 기반으로 한 개발방법론을 말한다


    아래 블로그에 쉽게 설명되어있다

    https://academy.realm.io/kr/posts/ios-tdd-test-driven-development/


    기존에는 구현 후 프로그램을 여러 번 실행하여 test case를 돌렸는데

    TDD는 테스트 과정을 기반으로 구현함으로써 개발기간을 단축할 수 있을 것으로 기대된다

    그래서 앞으로 개발할 때 TDD를 사용해 보려한다


    아래는 TDD에 대한 위키 글이다

    https://en.wikipedia.org/wiki/Test-driven_development


    ---


    python unittest 사용이유


    python unittest는 JUnit을 기반으로 한 unit test 자동화 라이브러리이다

    유닛 테스트란, 프로그램 전체 테스트를 유닛별로 쪼개서 테스트하는 것을 의미한다

    테스트의 목적은 컴파일 에러가 아닌, 런티암 에러(access violation, logic error)를 테스트하는 것이다


    unittest나 junit이나 그러한 원념에 기반하고있으므로, junit에 대한 글을 한번 살펴보자


    아래는 junit에 대한 stackoverflow 유저의 재밌는 답변이다

    https://stackoverflow.com/questions/10858990/why-use-junit-for-testing


    이 글에서는 다음과 같이 이야기하고있다

    만약 unit test를 하지않는다면, 코드를 조금이라도 수정할 때마다 프로그램 전체를 테스트 해야할 것이다

    이것은 문제가 많고 에러가 발생하기쉽다 (problematic and error-prone)

    이것은 프로그램 규모가 커질수록 이것은 힘들 뿐만 아니라(unpleasant) 불가능해지기까지 한다


    unit test는 프로그램 전체 test의 반대 개념이고

    코드를 수정할 때마다 테스트 할때 편리함을 제공해준다

    이것은 프로젝트 규모가 커질수록 unit이 많아질수록 필요성이 커진다


    개인프로젝트로 접하기 가장 쉬운 프로젝트는 안드로이드 프로젝트일 것이다

    안드로이드 스튜디오에서는 기본적으로 JUnit 사용이 내장되어있다

    안드로이드는 웬만한 프로젝트들에 비해 빌드시간이 굉장히 오래걸린다

    즉 기능을 하나 추가할 때마다 앱을 빌드하고 실행해서 테스트해보는 것은 굉장히 시간 비효율적이다


    안드로이드 프로젝트에 있는 JUnit을 잘 활용한다면 unit test가 왜 개발기간 단축에 효과적인지 비교적 쉽게 이해할 수 있을것이다


    Caffe2 python binding에서도 operator_test를 할때 unittest 라이브러리를 사용하고 있다

    결론적으로 unittest 라이브러리를 사용하는 이유는 위에서 언급한 내용과 동일하다

    unit test를 사용하는 이유 관점에서 원론적인 이야기를 했다


    caffe2 사용 중에 python unittest를 보고 이걸 사용하면 뭐가 좋은지 궁금하여 찾아보았고

    필자는 파이썬으로 규모가 큰 프로젝트를 진행할 때 unittest 라이브러리를 활용해볼 계획이다



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    selenium은 automated browser(자동화 브라우저) 라이브러리로서, 웹 애플리케이션 테스팅이나 기타 등등의 용도로 사용할 수 있다

    selenium의 python binding을 설치해보자


    아래 명령어로 selenium을 설치한다

    pip install selenium

    아래 사이트에서 자신의 OS에 맞춰 chromedriver를 다운받는다

    https://sites.google.com/a/chromium.org/chromedriver/getting-started

    그리고 아래 샘플 코드를 실행해보자

    import time
    from selenium import webdriver

    driver = webdriver.Chrome('/path/to/chromedriver')  # Optional argument, if not specified will search path.
    driver.get('http://www.google.com/xhtml');
    time.sleep(5) # Let the user actually see something!
    search_box = driver.find_element_by_name('q')
    search_box.send_keys('ChromeDriver')
    search_box.submit()
    time.sleep(5) # Let the user actually see something!
    driver.quit()

    webdriver.Chrome()의 파라미터만 수정 해주면 된다

    코드를 실행하면 크롬 브라우저가 실행되는 것을 확인할 수 있다


    참고:

    http://selenium-python.readthedocs.io/installation.html

    https://sites.google.com/a/chromium.org/chromedriver/getting-started




    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    리스트 내포(List comprehension)

    # '1 2 3 4'를 입력받아 [1,2,3,4] 리스트 생성

    [int(i) for i in input().split()] # == list(int(i) for i in input().split())

    # tuple version

    tuple(int(i) for i in input().split())


    참고: 

    https://wikidocs.net/22

    https://stackoverflow.com/questions/16940293/why-is-there-no-tuple-comprehension-in-python



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    pip install ipython 시 겪은 에러로, 원인은 pip version이었다


    ipython github README 인용

    You will need to update pip to the version 9.0.1 or greater


    아래 명령어로 pip를 upgrade하고 version을 확인해보자

    pip install -U pip

    pip --version



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    ctypes에서 python 함수를 callback 함수로 사용하기 위해서는 CFUNCTYPE을 사용해야한다

    ctypes documentation에 나온 사용방법은 아래와 같다


    1
    2
    3
    4
    5
    6
    from ctypes import *
     
    def py_callback(mystr):
        pass
     
    callback = CFUNCTYPE(c_int, POINTER(c_char))(py_callback)
    cs


    C 함수에 function pointer를 전달할 때 py_callback을 전달할 수는 없으므로

    CFUNCTYPE을 이용해서 callback을 만들어 전달하면 된다

    이때 CFUNCTYPE을 python decorator로 사용하여 더 간단하게 만들 수 있다


    1
    2
    3
    4
    5
    from ctypes import *
     
    @CFUNCTYPE(c_int, POINTER(c_char))
    def callback(mystr):
        pass
    cs


    ---


    cfunc는 arg, restype를 아래와 같이 설정할 수 있다

    이 작업은 optional하지만, 디버깅을 쉽게만들어주는 효과를 줄것이다


    callback.argtypes = [ ... ] # default: None

    callback.restype = ... # default: c_long




    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    C언어 Calling Convention

    Language 2017. 11. 26. 20:37

    대표적으로 __cdecl과 __stdcall이 있는데, 이 둘의 차이점은

    memory에서 argument stack을 생성/정리하는 것이 caller냐 callee냐이다


    __cdecl -> caller가 parameter stack 정리 -> default calling convention

    __stdcall -> callee가 parameter stack 정리 -> WINAPI calling convention

    __stdcall 호출 규칙은 Win32 API 함수를 호출하는 데 사용됩니다. 호출 수신자가 스택을 정리하므로 컴파일러는 vararg 함수를 __cdecl로 만듭니다. 이 호출 규칙을 사용하는 함수에는 함수 프로토타입이 필요합니다.
    참조: https://msdn.microsoft.com/ko-kr/library/zxk0tw93.aspx

    덧붙이자면

    variable argument function(가변인자 함수)의 경우 caller가 직접 stack을 정리하는 __cdecl을 사용하는 것이 적절하다

    argument의 갯수를 caller만이 알고있기 때문이다

    프로그래머가 __stdcall로 선언해도 __cdecl로 컴파일한다


    함수에 호출 규약을 별도로 명시하지않으면 암묵적으로 cdecl을 사용한다 (기본 호출 규악인 것처럼)

    그런데 WINAPI는 왜 굳이 stdcall을 사용할까?


    stdcall을 직역하면 "표준 호출"로, 다른 언어에서 WINAPI를 호출할 경우 호환성(compatibility)을 위한 것이다

    참조: cfile30.uf.tistory.com/attach/27486F4B5674253F22A740


    python ctypes 라이브러리을 사용하려고 documentation을 살펴보다가, cdll과 windll의 calling convention이 언급되어있어서 찾아보게 되었다



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    필자는 처리방법을 기준으로 데이터를 스트링 데이터와 바이너리 데이터로 나눈다

    스트링 데이터도 인코딩 이슈가 있지만

    바이너리 데이터는 그보다 더 많은 이슈가 발생한다


    특히 \x00이나 \x27 등을 특수문자로 인식해서 발생하는 이슈가 많다

    1. 데이터 중간에 \x00이 있을경우, NULL로 인식하여 데이터의 끝으로 인식한다. 또는 \x00이 생략되는 경우도 있다

    2. linux shell에서 바이너리 데이터를 파라미터로 사용할 때 \x27을 quote( ' )로 인식하여 syntax error가 발생한다

    3. JSON, XML은 binary data를 지원하지 않는다

    4. 데이터 타입과 byte order 이슈가 있다


    그러므로 바이너리 데이터를 처리할 때는 위와 같은 이슈를 고려하고 디버깅을 잘 해야한다

    이 외에 스트링 데이터와 바이너리 데이터의 차이점으로, 

    C언어에서 문자열은 \0을 통해 길이를 체크하므로 별도로 길이 데이터를 줄 필요 없지만

    바이너리 데이터는 그럴 수 없으므로 길이 데이터를 별도로 전달해야 한다는 차이점이 잇다


    결론적으로, 바이너리 데이터를 처리할 때 일반적인 스트링 데이터처럼 생각하면 생각치못한 이슈들이 발생하므로

    구분해서 생각하도록 하자



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    <converting bytes to ctypes.c_short array가 필요한 경우>

    NAVER CAMPUS HACK DAY에서 진행한 프로젝트 중에

    pcm 파일을 read하여 c 함수에 short array 파라미터로 전달해야했다

    그 때 이 converting 과정이 필요했다


    <example>

    struct 라이브러리에 있는 struct.unpack(fmt, buf)를 사용하면 된다


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import struct
     
    # CONSTANT
    FILE_PATH = 'sample.pcm'
    BUF_SIZE = 3200
    SHORT_PER_BYTE = 16/8 # 2
     
    def callback(buf): # buf is POINTER(c_short)
        # read to bin_data
        f.open(FILE_PATH, 'rb')
        bin_data = f.read(BUF_SIZE)
     
        # unpack to short_arr
        count = len(bin_data)/SHORT_PER_BYTE
        short_arr = struct.unpack('<'+('h'*count), bin_data)
     
        #copy to buf
        for i in range(count):
            buf[i] = short_arr[i]
     
    cs


    struct.unpack('<hh', bin_data)

    length=4의 bin_data 변수를 unpack하여 length=2의 tuple을 return한다

    unpack format에 대해서 설명하자면,

    '<'는 byte order 중 little-endian을 의미 (반대는 '>')

    'h'는 short 1개를 의미, 즉 'hh'는 short 2개를 의미

    즉 h 갯수를 len(bin_data)에 맞춰주면 된다


    필자가 사용한 pcm 파일이 pcm_s16le 타입이었기 때문에 (ffmpeg audio Types 참고)

    위와 같은 format을 사용했다


    ---


    여담으로, 'h'와 'H'의 차이는 signed/unsigned인데

    memory-level에서 보면 동일하지만 그것을 어떻게 decode하느냐가 다르다.

    예를들어 'h' 또는 'H'에 따라 b'\xff\xff'는 -1 또는 65535로 decode된다



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    import requests

    from bs4 import BeautifulSoup


    html = requests.get(url).content

    soup = BeautifulSoup(html, 'html.parser')

    soup.find_all('mytag') # output: list

    soup.find_all(id='myid')

    soup.find_all('mytag', { 'class' : 'myclass' })


    soup.find('mytag') # output: only one

    soup.mytag

    'Language > python' 카테고리의 다른 글

    [python] ctypes.CFUNCTYPE 사용법  (0) 2017.11.27
    [python] converting bytes to ctypes.c_short array  (0) 2017.11.26
    [python] get html (urlopen) best way  (0) 2017.11.26
    [python] str to bytes  (0) 2017.11.25
    [python] json example  (0) 2017.11.25

    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    url로부터 html을 가져오기 위한 라이브러리로 urllib, 2, 3 등이 있지만

    필자는 requests를 이용할 것이다

    request는 urllib3를 기반으로 한 라이브러리로, 가장 짧고쉽게 html을 얻을 수 있다

    pip install requests

    설치 후, 아래와 같이 사용할 수 있다

    import requests


    url = 'https://www.naver.com/'

    html = requests.get(url).content

    얻은 html은 BeautifulSoup 등에서 이용할 수 있다

    from bs4 import BeautifulSoup


    soup = BeautifulSoup(html, 'html.parser')


    'Language > python' 카테고리의 다른 글

    [python] converting bytes to ctypes.c_short array  (0) 2017.11.26
    [python] beautifulsoup4 example  (0) 2017.11.26
    [python] str to bytes  (0) 2017.11.25
    [python] json example  (0) 2017.11.25
    [python] Windows python3, jupyter 설치하기  (0) 2017.11.25

    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    # str vs bytes

    'string' # type: str

    b'string' # type: 


    string = 'string'

    string # output: 'string'

    type(string) # output: str


    # str to bytes (encode str obj to utf-8 bytes)

    bstr = string.encode()

    type(bstr) # output: bytes


    # bytes to str (decode utf-8 bytes to str obj)

    bstr.decode() # output: utf-8

    bstr.decode('utf-16') # output: utf-16



    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    참조: http://docs.python-guide.org/en/latest/scenarios/json/


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import json
     
    # json string to dict obj
    json_string = '{"first_name": "Guido", "last_name":"Rossum"}'
    parsed_json = json.loads(json_string)
    print(parsed_json['first_name'])
     
    # dict obj to json string
    = {
        'first_name''Guido',
        'second_name''Rossum',
        'titles': ['BDFL''Developer'],
    }
    print(json.dumps(d))
    cs




    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    Windows 10 64bit 기준


    python3.6에서 jupyter를 설치하다가 에러가 나서 쓰는글


    -> python3를 설치할거면 3.6 말고 3.5로 설치하라


    1. python3.5 설치

    2. cmd 관리자 모드로 실행

    3. pip install jupyter

    4. jupyter notebook # run webserver


    python interpreter를 쓰고싶으면 built-in 대신 ipython 또는 jupyter를 사용하자


    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    필자는 python이 dynamic typing language라는 특징이 좋아보였으나

    직접 사용해보니 함수의 파라미터 타입 때문에 자꾸 에러가 나고 고치기는 힘들어서

    C, C++, Java를 사용해왔다


    그런데 이번에 NAVER CAMPUS HACK DAY를 다녀온다음에 생각이 바뀌었다

    프로젝트 내용은 python ctypes library를 사용하여 C library module을 call하는 client를 개발하는 것이었는데, 이 때 느낀 것이 python ctypes의 강력한 C Portability였기 때문이다


    자세히 말해, python은 다른 언어들에 비해 C 라이브러리 함수 call이 쉽다

    python은 C언어로 구현된 라이브러리를, 그대로, 간단하게 사용할 수 있다는 의미이다 (Java보다 훨씬)

    그 예로 Caffe, Caffe2, Tensorflow 등 매우 많은 프레임워크/라이브러리에서 python binding을 제공해준다

    정리하여 python의 C Library의 함수 call이 굉장히 쉽다는 점은 가장 큰 장점이자 python을 써야하는 이유라고까지 할수있다

    이제 python의 특징을 다른 언어들과 비교해보자

    필자가 자주 사용하는 언어들과 주관적으로 비교해보았다


    C언어
    pro: high performance
    con: low productivity

    Raspberry Pi나 아두이노같은 Embedded programming이 아니면 C언어는 낮은 생산성 때문에 쓰기 힘들다


    C++

    멀티-패러다임 언어

    중간 성능, 중간 생산성(난이도)

    멀티-패러다임 언어라서 가장 자유로운 언어라고 할수있다.

    하지만 애매하다. 성능을 원한다면 C언어 / 생산성을 원한다면 Java가 낫다
    그리고 자유로운만큼 에러 디버깅이 힘드므로 (예를들면 segmentation fault) 생산성은 중간
    성능이 부족할 일은 웬만하면 없으므로 필자는 편리함을 보고 Java로 넘어갔다


    Java
    pro: high productivity, platform-independent
    con: low performance, JNI
    OOP 패러다임 언어

    생산성이 높고, OS 플랫폼에 독립적이며, 비교적 성능은 낮지만 웬만하면 문제가 되지 않으며, 
    성능이 필요하면 JNI를 통해 C언어와 연동하면 된다.

    JNI를 사용하는 또다른 이유, C로 이미 구현한 함수를 Java에서 사용할수 있다는 것이지만 JNI 사용법이 까다롭기 때문에 그냥 Java로 porting해서 사용했다


    결론적으로 python은 Java의 특징들을 모두 가지면서 C로 구현된 라이브러리를 훨씬 쉽게 호출할 수 있다!

    이외에도 python은 여러가지 장점들이 있다
    * 가장 큰 장점인 C portability (ctypes)
    * 코드가 짧다는 점
    * 가독성 좋은 문법
    * 방대한 라이브러리 (beautifulsoup4, numpy 등)


    python도 dynamic typing 등 불편한 점이 없진 않지만, 적응하면 오히려 편리할 것 같고
    Caffe2를 공부해보니, 앞으로 python은 계속 쓰게될것 같아서 평소에 미리 익숙해져 있어야겠다




    WRITTEN BY
    hojongs
    블로그 옮겼습니다 https://hojongs.github.io/

    사용중인 블로그 스킨이 방명록을 지원하지 않습니다.

    초대장을 받고싶으신 분들은 댓글 또는 블로그 설명의 메일로.