Python과 C++ 함께 디버그 (혼합 디버깅)


이전 Ctypes 예제를 바탕으로 C코드로 작성된 부분을 Python을 실행 할 때 어떻게 Breakpoint를 잡아서 Debug하는지를 설명한다.

2019.7월 기준으로 필자가 아는한 Visual Stduio만이 IDE중에선 이러한 혼합 디버깅을 지원 한다 (참조).

본 포스팅에서는 Mac이나 Ubuntu환경에서 가능한 LLDB를 활용한 방식을 소개한다.

디버깅

C++ GCC로 컴파일 할 떄 당연히 -g 옵션을 넣어서 컴파일한다. 그래야 C++코드를 디버깅시 볼 수 있다. 그렇지 않으면 Assembly로 코드가 나오고 디버깅도 어쩌면 정상 동작하지 않는다.

아래와 같이 LLDB로 옵션을 주고 실행한다음 원하는 곳에 breakpoint를 걸고 run을 실행 한다.

$ lldb python3 callclib1.py

(lldb) target create "python3"
Current executable set to 'python3' (x86_64).
(lldb) settings set -- target.run-args  "callclib1.py"

breakpoint set --name simple_function

(lldb) run

최종적으로 아래와 같이 simple_function에 breakpoint가 걸리는 것을 알 수 있다.

Process 7816 launched: '/Users/jeminlee/anaconda3/bin/python3' (x86_64)
1 location added to breakpoint 1
Calling simple C counting function four times:
Process 7816 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100550dc4 libclib1.so simple_function at clib1.c:7:12
   4
   5       int simple_function(void) {
   6           static int counter = 0;
-> 7           counter++;
   8           return counter;
   9       }
   10
Target 0: (python3) stopped.

실행 스크린샷
스크린샷 2019-07-05 오후 6.24.39

참고문헌


Ctypes를 이용한 Python과 C와의 연결


속도나 하드웨어 디바이스 드라이버 접근 등을 위해서 C와 연결해서 Python을 사용해야 할 일들은 생기기 마련이다.
두 언어를 이어 붙이기 위한 수단인 이종 언어간 인터페이스 (Foreign Function Interface, FFI)를 다룬다.

FFI를 지원하는 방법으로는 ctypes CFFI 방법이 있다.

  • ctypes방법은 파이썬 표준 라이브러리에 포함되어 있다.
    • C로 작성된 코드가 Shared object (*.so)형태로 컴파일 되어 있어야함.
    • 함수와 구초제 등을 ctypes에 맞는 방식으로 다시 정리해야된다.
    • OS에서 제공하는 symbol lookup 방식으로 찾을 수 있는 요소에 한해서만 접근이 가능함

C코드 스타일로 예제 작성

값을 카운트 하는 코드

int simple_function(void) {
    static int counter = 0;
    counter++;
    return counter;
}

문자열 하나 하나를 입력해서 string으로 변환함.

void add_one_to_string(char *input) {
    int ii = 0;
    for (; ii < strlen(input); ii++) {
        input[ii]++;
    }
}

두 개의 함수는 string을 C 컨텍스트 안에서 allocate 하고 free 하는 기능을 가진다.

char * alloc_C_string(void) {
    char* phrase = strdup("I was written in C");
    printf("C just allocated %p(%ld):  %s\n",
           phrase, (long int)phrase, phrase);
    return phrase;
}

void free_C_string(char* ptr) {
    printf("About to free %p(%ld):  %s\n",
           ptr, (long int)ptr, ptr);
    free(ptr);
}

Python에서 해당 ctypes 모듈을 loading하는 방법

기본적인 form은 아래와 같다.
그냥 같은 위치에 .so가 존재 한다면 아래와 같이 간단하게 읽어 올 수 있다.
다른 경로라면 다양한 방법으로 os package를 이용해서 path를 생성할 수 있다.

import ctypes

# Load the shared library into c types.
libc = ctypes.CDLL("./libclib1.so")

예를 들면 아래와 같이 처리 할 수 있다.

libname = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "libclib1.so"))

libc = ctypes.CDLL(libname)

호출 방법 (기본)

파라메터 없이 호출하는건 간단하게 수행 된다.

import ctypes

# Load the shared library into c types.
libc = ctypes.CDLL("./libclib1.so")

# Call the C function from the library
counter = libc.simple_function()

여기서 int를 c에서 반환하고 이것은 ctypes에서 이러한 type부분을 python에 맞게 적절하게 변환해 준다.

Makefile 및 실행 결과

Makefile

all: test

clean:
  rm -f *.o *.so

clib1.so: clib1.o
  gcc -shared -o libclib1.so clib1.o

clib1.o: clib1.c
  gcc -c -Wall -Werror -fpic clib1.c

test clib1.so
  ./callclib1.py

실행 결과

./callclib1.py
Calling simple C counting function four times:
1
2
3
4

참고문헌


PyCharm에서 PYTHONPATH 설정하기



bashrc 또는 zshrc에 설정한 환경변수 PYTHONPATH의 설정을 pycharm에서 하는 방법이다.



You need to go to the Main PyCharm Preferences, which will open up a separate window. In the left pane, choose Project:... > Project Interpreter. Now, in the main pane on the right, click the settings symbol (gear symbol) next to the field for "Project Interpreter". Choose More in the menu that pops up. Now in the final step, pick the interpreter you are using for this project and click on the tree symbol at the bottom of the window (hovering over the symbol reveals it as "Show paths for the selected interpreter"). Add your path by click in the "plus" symbol.

It took me ages to find, so I hope the detailed instructions will help. Further details are available in the PyCharm docs.

https://www.jetbrains.com/help/pycharm/2016.1/installing-uninstalling-and-reloading-interpreter-paths.html?search=add%20folder%20to%20path

It is good practice to have __init__.py in each subfolder of the module you are looking to add, as well as making your project folder a 'Source Root'. Simply right-click on the folder in the path bar and choose 'Mark Directory as ...'


https://stackoverflow.com/questions/28326362/pycharm-and-pythonpath?rq=1



Configure a Python interpreter

https://www.jetbrains.com/help/pycharm/configuring-python-interpreter.html


PYTHONPATH는 아래와 같이 커스텀 라이브러리들을 추가 할 수 있다.




Python Console에도 추가 할 수 있다.



참고 미디엄 포스팅: https://medium.com/@erikhallstrm/work-remotely-with-pycharm-tensorflow-and-ssh-c60564be862d

Jupyter 서버 설치 및 실행법


Data Science 분야와 과학분야에서 편하게 Python이 쓰이도록 개발된
Notebook에 대해서 살펴본다.

사용된 설치환경은 아래와 같다.

  • Ubuntu 18.04

실행 명령어 (개인 환경) -나의 경우 이대로 따라하면 된다-

source ~/tensorflow/bin/activate # virtualEnv 활성화를 통한 TensorFlow library 연동
#활성화 성공

#활성화 한다음 아래의 config 파일이 있는 디렉터리로 이동한다음 jupyter를 실행 해야 한다!!!
(tensorflow)root@jemin-virtual-machine:~/.jupyter# 
# jemin_config.py 환경으로 Jupyter 실행
# jemin_config.py는 SSL 설정을 Disable 한것이다.
jupyter notebook --config jemin_config.py

설치 및 실행

Ipython Notebook 보다 더 발전된 Interactive IDE이다.
Jupyter가 다중 kernel을 지원한다고 한다.
즉, python 2,3 모두를 지원 한다.

python2는 pip이고 python3은 pip3이다.

pip install jupyter

실행 방법

jupyter notebook

도움말 실행 방법

(tensorflow)root@jemin-virtual-machine:~/.jupyter# jupyter notebook --h
usage: jupyter-notebook [-h] [--certfile NOTEBOOKAPP.CERTFILE]
                        [--ip NOTEBOOKAPP.IP] [--pylab [NOTEBOOKAPP.PYLAB]]
                        [--log-level NOTEBOOKAPP.LOG_LEVEL]
                        [--port-retries NOTEBOOKAPP.PORT_RETRIES]
                        [--notebook-dir NOTEBOOKAPP.NOTEBOOK_DIR]
                        [--config NOTEBOOKAPP.CONFIG_FILE]
                        [--keyfile NOTEBOOKAPP.KEYFILE]
                        [--port NOTEBOOKAPP.PORT]
                        [--transport KERNELMANAGER.TRANSPORT]
                        [--browser NOTEBOOKAPP.BROWSER] [--script] [-y]
                        [--no-browser] [--debug] [--no-mathjax] [--no-script]
                        [--generate-config]

optional arguments:
  -h, --help            show this help message and exit
  --certfile NOTEBOOKAPP.CERTFILE
  --ip NOTEBOOKAPP.IP
  --pylab [NOTEBOOKAPP.PYLAB]
  --log-level NOTEBOOKAPP.LOG_LEVEL
  --port-retries NOTEBOOKAPP.PORT_RETRIES
  --notebook-dir NOTEBOOKAPP.NOTEBOOK_DIR
  --config NOTEBOOKAPP.CONFIG_FILE
  --keyfile NOTEBOOKAPP.KEYFILE
  --port NOTEBOOKAPP.PORT
  --transport KERNELMANAGER.TRANSPORT
  --browser NOTEBOOKAPP.BROWSER
  --script
  -y, --y
  --no-browser
  --debug
  --no-mathjax
  --no-script
  --generate-config

주피터의 다중 커널 개념 지원은 매우 간단하고, 강력하다. IPython이 실행되는 파이썬 실행기에 종속되지 않기 때문에, 다른 언어들의 커널을 지원할 뿐만 아니라, 환경만 갖춰져 있다면 같은 언어의 다양한 버전에 대해서도 별도의 커널을 만들어 사용할 수 있다. 나아가 파이썬의 virtualenv와 결합하면 환경별로도 커널을 분리해 사용할 수 있다. 이와 같이 다중 커널 개념은 Jupyter의 핵심 개념이며, 이를 통해서 좀 더 자유롭게 Notebook 생활이 가능해질 것이다.

참고사이트: http://jupyter-notebook.readthedocs.org/en/latest/public_server.html

설정 방법

실행방법

jupyter notebook

시작 디렉터리 위치 변경

  • Window
    아이콘 오른쪽버튼 -> 시작 경로 변경

  • Linux
    To launch Jupyter Notebook App:

    • Click on spotlight, type terminal to open a terminal window.
    • Enter the startup folder by typing cd /some_folder_name.
    • Type ipython notebook to launch the Jupyter Notebook App (it will appear in a new browser window or tab).

원격 서버로 설정

우분투환경

Securing a notebook server

jupyter notebook --generate-config

profile 생성없이 defalut내용을 바로 변경한다. 전체 Jupyter에 영향을 미친다.

Writing default config to: /root/.jupyter/jupyter_notebook_config.py

Preparing a hashed password

In [1]: from notebook.auth import passwd

In [2]: passwd()
Enter password: 
Verify password: 
Out[2]: 'sha1:f24baff49ac5:863dd2ae747212ede58125302d227f0ca7b12bb3'

jupyter_notebook_config.py를 열어서 아래의 내용을 입력한다.

# Password to use for web authentication
c = get_config()
c.NotebookApp.password ='sha1:f24baff49ac5:863dd2ae747212ede58125302d227f0ca7b12bb3'

패스워드를 사용할 때 SSL을 사용하는것은 좋은 생각이다.
SSL을 이용해서 브라우저에서 패스워드가 암호화되서 보내지기 때문이다.
이를 위해서 self-signed certificate를 생성 한다.

OpenSSL을 이용해서 certificate을 생성할 수 있다. 유효기간은 365일이다.

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem

jupyter_notebook_config.py를 열어서 아래의 내용을 입력한다.

c.NotebookApp.certfile ='/absolute/path/to/your/certificate/mycert.pem'

서버 설정 내용을 jupyter_notebook_config.py를 열어서 아래의 내용을 입력한다.

# The IP address the notebook server will listen on.
# c.NotebookApp.ip = 'localhost'
c.NotebookApp.ip = '192.168.174.131'
# c.NotebookApp.port_retries = 50
c.NotebookApp.port_retries = 8888

또는 아래의 명령어로 수작업으로 설정해 줄수도 있다.

jupyter notebook --ip=* --no-browser

특정 config 파일로 실행 하기

명렁어 --config jemin_config.py를 설정해 준다.

(tensorflow)root@jemin-virtual-machine:~/.jupyter# jupyter notebook --config jemin_config.py 
[I 00:46:15.432 NotebookApp] Serving notebooks from local directory: /root/DataScience/
[I 00:46:15.432 NotebookApp] 0 active kernels 
[I 00:46:15.432 NotebookApp] The IPython Notebook is running at: http://192.168.174.132:8888/
[I 00:46:15.432 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).

기타설정

#실행과 동시에 web-browser를 실행하지 않게 한다.
c.NotebookApp.open_browser = False
#시작 디렉터리를 변경한다.
c.NotebookApp.notebook_dir = u'/root/DataScience/'

c.NotebookApp.matplotlib='inline' 옵션은 사용하지 못하도록 변경되었다.
IPython shell에서 직접 magic 함수를 이용해야 한다.

%matplotlib inline

다중 Kernel 사용 하기

현재 설치된 커널 종류 확인
jupyter kernelspec list

(tensorflow_py2) jemin@jemin-desktop:~$ jupyter kernelspec list
Available kernels:
  python3    /home/jemin/.local/lib/python3.5/site-packages/ipykernel/resources

python2 커널 설치

python2 -m pip install ipykernel
python2 -m ipykernel install --user

커널 설치 확인

(tensorflow_py2) jemin@jemin-desktop:~$  jupyter kernelspec list
Available kernels:
  python3    /home/jemin/.local/lib/python3.5/site-packages/ipykernel/resources
  python2    /home/jemin/.local/share/jupyter/kernels/python2

추가 설정 자료
https://songyunseop.github.io/post/2016/09/Using-Jupyter-inside-virtualenv/

업데이트 방법

버전어 맞춰서 아래 명령어를 이용한다.
python 3.5는 pip3
python 2.7는 pip

pip install --upgrade pip # pip update

pip install jupyter

백그라운드에서 실행하기

terminal window를 유지하지 않아도 connection이 보장된다.

nohup명령어의 기능

  • 표준 출력을 nohup.out또는 다른곳으로 redirection하는 작업 수행
  • 프로세스가 백그라운드에서 지속적으로 실행하도록 함.

물론 그냥 &만 뒤에 붙여주면 shell에서 백그라운드로 동작하지만 terminal을 닫으면 프로세스가 terminate되기 때문에 보장되지 않는다.

nohup jupyter notebook &

이렇게 실행한 프로세스는 kill로 terminate해야 한다.

lsof nohup.out
kill -9 <PID>

좀 더 일반적인 확인 후 종료

1. “ps -ef | grep 쉘스크립트파일명” 명령으로 데몬형식으로 실행
2. "kill -9 PID번호“ 명령으로 해당 프로세스 종료

부팅시 자동 실행 (19.5.8 수정)

service 생성

sudo vim /etc/systemd/system/jupyter.service

아래의 내용을 입력한다.

[Unit]
Description=Jupyter Notebook Server

[Service]
Type=simple
PIDFile=/run/jupyter.pid
User=<username>
ExecStart=/home/<username>/.local/bin/jupyter-notebook
WorkingDirectory=/your/working/dir

[Install]
WantedBy=multi-user.target

ExecStart설정은 anaconda의 경우 /home/<username>/anaconda3/bin/jupyter-notebook으로 설정한다. 각자 상황에 맞춰서 설정해야 한다.

service 등록

systemctl daemon-reload
systemctl enable jupyter.service
systemctl start jupyter.service

service 상태 알애내기

sudo systemctl status jupyter.service

● jupyter.service - Jupyter Notebook
   Loaded: loaded (/etc/systemd/system/jupyter.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-05-08 15:07:55 KST; 17min ago
 Main PID: 2057 (jupyter-noteboo)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/jupyter.service
           └─2057 /home/jemin/anaconda3/bin/python /home/jemin/anaconda3/bin/jupyter-notebook

 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.357 NotebookApp] JupyterLab extension loaded from /home/jemin/anaconda3/lib/python3.7/s
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.357 NotebookApp] JupyterLab application directory is /home/jemin/anaconda3/share/jupyte
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.358 NotebookApp] Serving notebooks from local directory: /home/jemin/development
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.358 NotebookApp] The Jupyter Notebook is running at:
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.358 NotebookApp] http://192.168.0.4:8888/
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [I 15:07:56.358 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to
 5월 08 15:07:56 jemin jupyter-notebook[2057]: [W 15:07:56.360 NotebookApp] No web browser found: could not locate runnable browser.
 5월 08 15:20:16 jemin jupyter-notebook[2057]: [I 15:20:16.468 NotebookApp] 302 GET / (192.168.0.2) 1.18ms
 5월 08 15:20:16 jemin jupyter-notebook[2057]: [I 15:20:16.470 NotebookApp] 302 GET /tree? (192.168.0.2) 0.28ms
 5월 08 15:20:18 jemin jupyter-notebook[2057]: [I 15:20:18.201 NotebookApp] 302 POST /login?next=%2Ftree%3F (192.168.0.2) 2.41ms

재시작: sudo systemctl restart jupyter.service
멈춤: sudo systemctl stop jupyter.service
해제: sudo systemctl disable jupyter.service

참고문서: https://wiki.ubuntu.com/SystemdForUpstartUsers

Trouble Shooting

1. IP 변경에 따른 에러

(tensorflow)root@jemin-virtual-machine:~/.jupyter# jupyter notebook --profile=jemin_config.py 
[W 20:34:44.745 NotebookApp] Unrecognized alias: '--profile=jemin_config.py', it will probably have no effect.

Traceback (most recent call last):
  File "/usr/local/bin/jupyter-notebook", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/jupyter_core/application.py", line 267, in launch_instance
    return super(JupyterApp, cls).launch_instance(argv=argv, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/traitlets/config/application.py", line 591, in launch_instance
    app.initialize(argv)
  File "<string>", line 2, in initialize
  File "/usr/local/lib/python2.7/dist-packages/traitlets/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/notebook/notebookapp.py", line 1007, in initialize
    self.init_webapp()
  File "/usr/local/lib/python2.7/dist-packages/notebook/notebookapp.py", line 873, in init_webapp
    self.http_server.listen(port, self.ip)
  File "/usr/local/lib/python2.7/dist-packages/tornado/tcpserver.py", line 126, in listen
    sockets = bind_sockets(port, address=address)
  File "/usr/local/lib/python2.7/dist-packages/tornado/netutil.py", line 196, in bind_sockets
    sock.bind(sockaddr)
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 99] Cannot assign requested address

2. SSL 사용 오류

config file에서 아래의 SSL 설정관련 코드들이 문제가 된다.
보안상 문제가 있지만 그냥 주석처리하고 실행 한다.

파일위치: /root/.jupyter

c.notebookApp.certfile = u'/root/.jupyter/mycert.crt'
c.notebookApp.certfile = u'/root/.jupyter/mycert.key'

아래는 에러 코드이다.

(tensorflow)root@jemin-virtual-machine:~/.jupyter# jupyter notebook --profile="jemin_config.py"
[W 22:43:24.515 NotebookApp] Unrecognized alias: '--profile=jemin_config.py', it will probably have no effect.
[W 22:43:24.520 NotebookApp] Error loading config file: jupyter_notebook_config
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/dist-packages/jupyter_core/application.py", line 202, in load_config_file
        path=path
      File "<string>", line 2, in load_config_file
      File "/usr/local/lib/python2.7/dist-packages/traitlets/config/application.py", line 75, in catch_config_error
        return method(app, *args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/traitlets/config/application.py", line 564, in load_config_file
        collisions = loaded[0].collisions(loaded[1])
      File "/usr/local/lib/python2.7/dist-packages/traitlets/config/loader.py", line 212, in collisions
        for key in mine:
    TypeError: 'LazyConfigValue' object is not iterable
[I 22:43:24.545 NotebookApp] Serving notebooks from local directory: /root/DataScience/
[I 22:43:24.545 NotebookApp] 0 active kernels 
[I 22:43:24.545 NotebookApp] The IPython Notebook is running at: http://192.168.174.132:8888/
[I 22:43:24.545 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).

참고사이트

http://jdfreder-notebook.readthedocs.org/en/docs/examples/Notebook/Configuring%20the%20Notebook%20and%20Server.html

공식사이트

다중 커널 설치법 (공식)


Python 파라메터 앞에 *와 **의 의미 (*args, **kwargs)


다른사람들이 작성한 python 코드를 보다보면
*args, **kwargs 를 심심치 않게 본다.
그냥 막연하게 "어떤 파라미터를 몇개를 받을지 모르는 경우 사용한다" 라고 알고 있었지만
자세히 설명한 예 가 있어서 소개한다.

*args

  • 파라미터를 몇개를 받을지 모르는 경우 사용한다. args 는 튜플 형태로 전달된다.
def print_param(*args):
    print args
    for p in args:
        print p
 
print_param('a', 'b', 'c', 'd')
#('a', 'b', 'c', 'd')
#a
#b
#c
#d

**kwargs

  • 파라미터 명을 같이 보낼 수 있다. kwargs는 딕셔너리 형태로 전달된다.
def print_param2(**kwargs):
    print kwargs
    print kwargs.keys()
    print kwargs.values()
 
    for name, value in kwargs.items():
        print "%s : %s" % (name, value)
 
print_param2(first = 'a', second = 'b', third = 'c', fourth = 'd')
 
#{'second': 'b', 'fourth': 'd', 'third': 'c', 'first': 'a'}
#['second', 'fourth', 'third', 'first']
#['b', 'd', 'c', 'a']
#second : b
#fourth : d
#third : c
#first : a

그러면 두개를 같이 쓰는 경우는??

def print_param3(*args, **kwargs):
    print args
    print kwargs
 
print_param3('a', 'b')
#('a', 'b')
#{}
 
print_param3(third = 'c', fourth = 'd')
#()
#{'fourth': 'd', 'third': 'c'}
 
print_param3('a', 'b', third = 'c', fourth = 'd')
#('a', 'b')
#{'fourth': 'd', 'third': 'c'}

응용 해 보자

def print_param4(a, b, c):
    print a, b, c
 
p = ['a', 'b', 'c']
print_param4(*p)
#a b c
 
p2 = {'c' : '1', 'a' : '2', 'b' : '3'}
print_param4(**p2)
#2 3 1

출처

http://jhproject.tistory.com/109


Python 2 와 Python 3의 차이점


코드를 유지보수 하다보면 Python2로 작성된 것을 Python3으로 Migration 할 때가 많다.
이 때 생각보다 두 버전간의 backward compatibility를 지원하지 않는 부분이 많다는 것을 알게 된다.
이러한 부분을 다룬다.

xrange vs range

python3는 더이상 xrange를 지원하지 않는다.
무조건 range를 쓴다. 그리고 내부적으로 그형태가 약간 다르므로
xrange를 무조건 range로 대체 할 수도 없다.

python2에서 xrange는 정해진 숫자 만큼 object를 생성한다. 이는 list를 생성하는 range와는 다른 방식이고
looping을 할 때 약간 더 memory efficint 때문에 빠르다. 그래서 python2를 보면 대다수가 xrange를 사용 한다.

python 2    |  python 3
#------------------------
xrange(10)  |  range(10)
range(10)   |  list(range(10))

# example
# python2
[10] + xrange(9)

# python3
[10] + list(range(9))

만약 python3 코드를 python2에서 수행한다면 아래와 같이 입력해주면 된다.

import sys
if sys.version_info < (3,):
    range = xrange

print

python2는 print "string"
python3는 무조건 함수 호출이다. print ("string")

나눗셈

python2는 정수 / 정수 = 졍수 (5/2=2)
python2는 정수 / 정수 = 실수 (5/2=2.5)

생각보다 이런 사소한 문제 때문에 기능이 이상하게 동작 할때가 많다.
자동 타입할당이 편하지만 떄로는 디버깅할 때 상당히 난감하다.


PyCharm을 우분투 14.04설치 하는 방법


https://launchpad.net/~mystic-mirage/+archive/ubuntu/pycharm


There’s a PPA repository for Ubuntu based users that contains both professional (30-day free trial) and community version of PyCharm packages. So far, Ubuntu 15.04, Ubuntu 14.04, Ubuntu 12.04 and their derivatives are supported.


1. To add the PPA, open terminal from the Dash, Launcher, or via Ctrl+Alt+T shortcut keys. When it opens, run command:


sudo add-apt-repository ppa:mystic-mirage/pycharm


2. After adding the PPA, update system package cache and install the IDE via Synaptic Package Manager. Or just run below commands one by one in terminal:


sudo apt-get update

sudo apt-get install pycharm


You may replace last command via sudo apt-get install pycharm-community to install the community version which is free.


3. How to run


pycharm-community


4. Remove Pyharm


# for community edtion

sudo apt-get remove pycharm-community


# for professional version

sudo apt-get remove pycharm


Afterward, use the command below to remove the PPA from the source list:


sudo add-apt-repository --remove ppa:mystic-mirage/pycharm



(기록 보관용) IPython 및 Jupyter를 Window에 설치 및 설정

새로운 버전 Jupyter가 나왔으므로 이것을 사용하자.

IPython Notebook

기존 IPython Notebook 설치명령어는 아래와 같다.
debian 명령어와, pip 둘중 아무거나 하나를 쓰면 된다.

apt-get install ipython-notebook
pip install ipython[notebook]

실행 명령어

ipython notebook

참고사이트: http://opentechschool.github.io/python-data-intro/core/notebook.html

Jupyter와 IPython window에 설치

Window에서 쉽게 IPython을 설치하는 방법은 Anaconda를 이용하는 방법이다.
해당 설치파일을 받아서 install하면 Python 필수 package들과 Jupyter가 모두 설치 된다.

설치하면 자동으로 환경 변수 및 모든게 설정 된다.
아래와 같이 CMD창에 입력하면, IPython console과 Jupyter가 모두 실행되는 것을 볼 수 있다.

IPython Notebook을 Window에서 원격 서버로 설정하는 방법

C:\Users\justin>ipython profile create myipythonserver
[ProfileCreate] Generating default config file: u'C:\\Users\\justin\\.ipython\\p
rofile_myipythonserver\\ipython_config.py'
[ProfileCreate] Generating default config file: u'C:\\Users\\justin\\.ipython\\p
rofile_myipythonserver\\ipython_kernel_config.py'

윈도우에서 c:\Users\username.ipython 폴더에 profile_myipythonserver 폴더가 생성되었음을 알 수 있다. (profile을 삭제하려면 해당 폴더를 삭제하면 된다.) 이 폴더 아래의 파일 ipython_notebook_config.py를 열어 내용을 다음과 같이 수정한다. (주의 python은 대소문자 구별있음)

c=get_config()

c.NotebookApp.ip = 'localhost'                    # 외부접속을 허용하고싶다면 접속가능한 IP리스트
c.NotebookApp.pylab = 'disabled' 'inline'            # 그래프 코드를 창안에서 실행
c.NotebookApp.port = 8888                                 # 원하는 포트번호로 변경
c.NotebookApp.open_browser = True False         # 웹브라우저

웹서버를 통해 외부에서 ipython notebook을 이용할 것이라면 비밀번호 설정이 필요하다.
cmd창에서 ipython에 접속하여 비밀번호를 생성한다

c:\>ipython
... 
In [1]:from IPython.lib import passwd
In [2]:passwd()
Enter password:
Verify password:
Out [2]: 'sha1:~~~~~'
In [3]:exit

참고사이트: 
http://durst.tistory.com/242
https://ipython.org/ipython-doc/3/config/intro.html


Data Science를 위한 Python package 꾸러미들


설치방법은 크게 두가지이다.

Ubuntu packages

  • Ipython: 인터렉트 python kernel
  • numpy: 수치배열 연산
  • Scipy: 과학 공학 계산에 필요한 툴박스
  • Matplotlib: 매트랩 스타일의 plot 생성
  • pands: R과 같은 statistical package (통계)
  • sympy: 심볼릭연산. 즉 도함수를 쉽게 그릴 수 있다.
  • scikit-learn: machine learning package 이다. (deep learning은 아직없음 tensorflow 설치법 참조)
sudo apt-get install ipython 
sudo apt-get install python-numpy 
sudo apt-get install python-scipy 
sudo apt-get install python-matplotlib 
sudo apt-get install python-pandas 
sudo apt-get install python-sympy 

pip를 이용한 설치 (python 2.7)

pip의 장점은 virtualenv를 사용할 수 있다는 것이다.
apt-get의 경우 system-wide로 영향을 미치게 된다.

Prerequisite:

sudo apt-get install build-essential gfortran libatlas-base-dev python-pip python-dev
sudo pip install --upgrade pip
sudo pip install numpy
sudo pip install scipy
sudo pip install matplotlib 
sudo pip install pandas 
sudo pip install sympy 
sudo pip install -U scikit-learn


Python 설치법, 환경설정, IDE 설정


python 설치방법 -기본



Python 2.7 버전 설치

sudo apt-get install python


수동 설치 (비추천)

#download using the following command:
cd ~/Downloads/
wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz

#Extract and go to the directory:
tar -xvf Python-2.7.9.tgz
cd Python-2.7.9

#Now, install using the command you just tried:
./configure
make
sudo make install


우분투에서 python3을 default로 잡지 않은 이유는 다음과 같다.

1) 우분투는 python 2.x의 스크립트를 많이 이용하고 있다.

2) python 2와 python3은 서로를 완전히 보완하지 못한다. 버전간의 충돌이 있다.

3) python 2.7은 지속적으로 bugfix가 되며, 2020년까지는 지원을 해준다고 한다.

4) 대부분의 python script는 명시적으로 #!/usr/bin.env python 이라고만 명시하는데, 만약 /usr/bin/python을 python3으로 변경 한다면, #/usr/bin/env python2라고 명시한 스크립트를 제외하고는 python2에서만 동작하는 스크립트가 문제가 생기게 된다.




python 설치방법 - Virtualenv 




Python VirtuaEnv


Virtualenv is a tool to reate isolated Python environment
만약 서로다른 version app이 서로다른 version의 python library를 사용하다면 그것은 하나의 컴퓨터 환경에서는 지원해 주기 어렵게 된다.
``/usr/lib/python2.7/site-packages``
라이브러리만 업데이트할경우 떄떄로 응용프로그램이 망가진다.
때때로 global “site-packages”에다가 package를 설치하고 싶지 않을 수도 있다.
모든 경우에 대해서 virtualenv는 도움을 줄 수 있다. 이것은 어떠한 독립적인 하나의 installation environment를 생성 한다.

좀 더 장점에대해서 알고싶으면 blog를 참조하자.

설치방법
# On Linux:
$ sudo apt-get install python-pip python-dev python-virtualenv
#활성화 방법
source (설치경로)/bin/activate #일반적인 경우
source ./tensorflow/bin/activate #나의 경우
#비활성화 방법
deactivate


IDE 설정 - PyDev (Eclipse)


필자는 PyDev를 사용한다.

하지만 다른 IDE가 궁금하다면 10 Best Python IDE for Developers를 읽어보자.


필자가 PyDev를 선택한 이유는 간단하다. Eclipse 기반의 Plugin으로써 Eclipse의 개발 경험을 그대로 활용할 수 있기 때문이다.

그리고 commercial IDE는 사용하고 싶지 않기 때문이다.


설치방법

Help -> Install New Software -> Add

Name: Pydev and Pydev Extensions

Location: http://pydev.org/updates








문제점.


wxPython에서 'Start'버튼을 눌렀 때, 정말 긴 작업을 발생 시킬 때가 존재한다.

당연히, 이때 GUI는 락킹 되어진다. 

이때, Thread를 사용하지 않고 이 GUI 락킹 문제를 해결 할 수 있을까?



해결방법.


3가지 방법: Threading, wxYield, Chunking up your processing in a wxEVT_IDLE handler.



1) Threading을 이용하는 방법


Thread와 별 차이가 없으며, 가장 쉽고, 일반적인 방법이다.


import time
from threading import *
import wx

# Button definitions
ID_START = wx.NewId()
ID_STOP = wx.NewId()

# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data

# Thread class that executes processing
class WorkerThread(Thread):
    """Worker Thread Class."""
    def __init__(self, notify_window):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self._notify_window = notify_window
        self._want_abort = 0
        # This starts the thread running on creation, but you could
        # also make the GUI thread responsible for calling this
        self.start()

    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread. Simulation of
        # a long process (well, 10s here) as a simple loop - you will
        # need to structure your processing so that you periodically
        # peek at the abort variable
        for i in range(10):
            time.sleep(1)
            if self._want_abort:
                # Use a result of None to acknowledge the abort (of
                # course you can use whatever you'd like or even
                # a separate event type)
                wx.PostEvent(self._notify_window, ResultEvent(None))
                return
        # Here's where the result would be returned (this is an
        # example fixed result of the number 10, but it could be
        # any Python object)
        wx.PostEvent(self._notify_window, ResultEvent(10))

    def abort(self):
        """abort worker thread."""
        # Method for use by main thread to signal an abort
        self._want_abort = 1

# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
    """Class MainFrame."""
    def __init__(self, parent, id):
        """Create the MainFrame."""
        wx.Frame.__init__(self, parent, id, 'Thread Test')

        # Dumb sample frame with two buttons
        wx.Button(self, ID_START, 'Start', pos=(0,0))
        wx.Button(self, ID_STOP, 'Stop', pos=(0,50))
        self.status = wx.StaticText(self, -1, '', pos=(0,100))

        self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START)
        self.Bind(wx.EVT_BUTTON, self.OnStop, id=ID_STOP)

        # Set up event handler for any worker thread results
        EVT_RESULT(self,self.OnResult)

        # And indicate we don't have a worker thread yet
        self.worker = None

    def OnStart(self, event):
        """Start Computation."""
        # Trigger the worker thread unless it's already busy
        if not self.worker:
            self.status.SetLabel('Starting computation')
            self.worker = WorkerThread(self)

    def OnStop(self, event):
        """Stop Computation."""
        # Flag the worker thread to stop if running
        if self.worker:
            self.status.SetLabel('Trying to abort computation')
            self.worker.abort()

    def OnResult(self, event):
        """Show Result status."""
        if event.data is None:
            # Thread aborted (using our convention of None return)
            self.status.SetLabel('Computation aborted')
        else:
            # Process results here
            self.status.SetLabel('Computation Result: %s' % event.data)
        # In either event, the worker is done
        self.worker = None

class MainApp(wx.App):
    """Class Main App."""
    def OnInit(self):
        """Init Main App."""
        self.frame = MainFrame(None, -1)
        self.frame.Show(True)
        self.SetTopWindow(self.frame)
        return True

if __name__ == '__main__':
    app = MainApp(0)
    app.MainLoop()


여기서 문제는, 어떤 이유에서 Thread가 종료 되어 지지 않는다면, 그냥 "self.setDaemon(1)"을 에 추가하면 된다. 그러면, Python은 그것의 terminate을 기다리지 않게 된다.


문제점

Thread는 미세한 종료문제를 발생 시킴

Signal 처리와 같은 Process 레벨의 작업



2) wxYield를 이용하는 방법


computation code가 있는 위치에대가 wxYield()의 호출을 추가해 준다.

wxYield 가 호출 되어질 때, 어떤 pending window event들은 dispatched 되어 지게 된다. 즉, window는 refresh되고, 버튼이 눌러지게 되는 등의 작업을 할 수 있다.


그다음, 위에서 Thread로 처리 했을 때와 같게, wxYield 가 리턴된 뒤의 위치의 작업 코드들을 제어하기 위해서 flag들을 설정 해야 한다. 즉, wxYield로 인해서 pending 되어진 'STOP'에 관한 이벤트가 들어 왔다면, 작업은 종료가 되어 져야한다. 따라서 그 후의 처리를 위해서는  flag를 통해서 제어를 해줘야 한다.


Threading의 경우와 마찬가지로, 모든 이벤트들은 wxYield 가 호출되어지는 동안, 처리되어 지므로, 반드시 같은 오퍼레이션이 두번 실행되어지는것에 대해서 보호되어 져야된다.


보여지는 코드는, 위의 Threading 코드와 똑같은 기능을 하지만, Computation Code들이 main window class안으로 들어 갔다. 핵심은, Threading 코드와 다르게 응답성은 절대적으로 wxYield의 호출 빈도에 의존한다는 것이다.


import time
import wx

# Button definitions
ID_START = wx.NewId()
ID_STOP = wx.NewId()

# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
    """Class MainFrame."""
    def __init__(self, parent, id):
        """Create the MainFrame."""
        wx.Frame.__init__(self, parent, id, 'wxYield Test')

        # Dumb sample frame with two buttons
        wx.Button(self, ID_START, 'Start', pos=(0,0))
        wx.Button(self, ID_STOP, 'Stop', pos=(0,50))
        self.status = wx.StaticText(self, -1, '', pos=(0,100))

        self.Bind (wx.EVT_BUTTON, self.OnStart, id=ID_START)
        self.Bind (wx.EVT_BUTTON, self.OnStop, id=ID_STOP)

        # Indicate we aren't working on it yet
        self.working = 0

    def OnStart(self, event):
        """Start Computation."""
        # Start the processing - this simulates a loop - you need to call
        # wx.Yield at some periodic interval.
        if not self.working:
            self.status.SetLabel('Starting Computation')
            self.working = 1
            self.need_abort = 0

            for i in range(10):
                time.sleep(1)
                wx.Yield()
                if self.need_abort:
                    self.status.SetLabel('Computation aborted')
                    break
            else:
                # Here's where you would process the result
                # Note you should only do this if not aborted.
                self.status.SetLabel('Computation Completed')

            # In either event, we aren't running any more
            self.working = 0

    def OnStop(self, event):
        """Stop Computation."""
        if self.working:
            self.status.SetLabel('Trying to abort computation')
            self.need_abort = 1

class MainApp(wx.App):
    """Class Main App."""
    def OnInit(self):
        """Init Main App."""
        self.frame = MainFrame(None,-1)
        self.frame.Show(True)
        self.SetTopWindow(self.frame)
        return True

if __name__ == '__main__':
    app = MainApp(0)
    app.MainLoop()



3) Chunking up your processing in a wxEVT_IDLE handler


마지막으로, 작업을 idle handler에서 처리 할 수 있다. 이것을 사용할 때에는, wxPython이 IDLE event를 언제든지 발생 시킬 수 있도록 허용 해야 한다. 즉, 일반적인 유저 이벤트들의 처리가 완료 되어졌을 때, IDLE 핸들러가 실행 되도록 해야 한다. 단순히 그냥 Flag로 조작 된다.


구현된 알고리즘에 따라서 약간은 어려운 부분이 존재 한다. 이러한 알고리즘들은, 별게의 조각들로 나누어서 실행 할 수 있어야 한다.


IDLE handler안에서, 만약, 작업이 완료 되지 않았다면, 다시 이 핸들러가 호출 되어 질 수 있도록 해야 한다.


결국, IDLE Hander에서 얼마나 자주 return 되는지가 응답성을 보장 하게 된다. 매우 제약적인 방법이며, 복잡하기만 하다. 쓸때없음.


import time
import wx

# Button definitions
ID_START = wx.NewId()
ID_STOP = wx.NewId()

# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
    """Class MainFrame."""
    def __init__(self, parent, id):
        """Create the MainFrame."""
        wx.Frame.__init__(self, parent, id, 'Idle Test')

        # Dumb sample frame with two buttons
        wx.Button(self, ID_START, 'Start',p os=(0,0))
        wx.Button(self, ID_STOP, 'Stop', pos=(0,50))
        self.status = wx.StaticText(self, -1, '', pos=(0,100))

        self.Bind (wx.EVT_BUTTON, self.OnStart, id=ID_START)
        self.Bind (wx.EVT_BUTTON, self.OnStop, id=ID_STOP)
        self.Bind (wx.EVT_IDLE, self.OnIdle)

        # Indicate we aren't working on it yet
        self.working = 0

    def OnStart(self, event):
        """Start Computation."""
        # Set up for processing and trigger idle event
        if not self.working:
            self.status.SetLabel('Starting Computation')
            self.count = 0
            self.working = 1
            self.need_abort = 0

    def OnIdle(self, event):
        """Idle Handler."""
        if self.working:
            # This is where the processing takes place, one bit at a time
            if self.need_abort:
                self.status.SetLabel('Computation aborted')
            else:
                self.count = self.count + 1
                time.sleep(1)
                if self.count < 10:
                    # Still more work to do so request another event
                    event.RequestMore()
                    return
                else:
                    self.status.SetLabel('Computation completed')

            # Reaching here is an abort or completion - end in either case
            self.working = 0

    def OnStop(self, event):
        """Stop Computation."""
        if self.working:
            self.status.SetLabel('Trying to abort computation')
            self.need_abort = 1

class MainApp(wx.App):
    """Class Main App."""
    def OnInit(self):
        """Init Main App."""
        self.frame = MainFrame(None, -1)
        self.frame.Show(True)
        self.SetTopWindow(self.frame)
        return True

if __name__ == '__main__':
    app = MainApp(0)
    app.MainLoop()







Image.open() 이 정상적으로 작동하다가 갑자기 작동 하지 않으면서, no Attribute라는 error 메시지를 나타낼 경우 그것은, namespace 충돌 때문일 것이다.


그 경우 모듈로 다시 masking을 해주면 문제를 해결 할 수도 있다.

PIL.Image

이렇게 하는 경우 어떤 class 이름이 Image일경우 namespace 문제가 발생 하는 것을 맊을 수 있다.


from PIL import Image

위의 것 대신에,

Import PIL.Image 를 사용 한다.


When working with a lot of imports, beware of namespace confilict.

I'm generally very wary of from some_module import * statements.


'Computer Science > Python' 카테고리의 다른 글

Python 설치법, 환경설정, IDE 설정  (0) 2015.11.17
GUI Responsive ( Thread, wx.Yield  (0) 2014.04.11
subprocess  (0) 2013.07.26
mutlprocessing의 오류  (0) 2013.07.19
GUI 프로그래밍  (0) 2013.06.23

subprocess


이 모델은 2.4 버전에서 새롭게 생긴것으로 이전의 os, poepn2, commands와 같은 다양한 다른 모듈에 있는 기능을 한곳에 모은 것이다.


Popen(args, **parms)


class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)



args는 'ls -l'과 같은 문자열 또는 ['ls','-l']과 같은 문자열 리스트로 지정 한다.

parms는 하위 프로세스의 다양한 속성을 제어하기 위해 설정한 키워드 인수들을 나타낸다. 다음 키워드 인수들을 인식한다.

bufsize: 버퍼링 방식을 지정한다. 0은 버퍼링하지 않고, 1은 줄 버퍼링을 하며, 음수 값은 시스템 기본 값을 사용한다. 그 밖에 양수 값은 대략적인 버퍼 크기를 나타낸다. 기본 값은 0이다.

excutable: 사용할 실행 프로그램의 이름을 지정한다. 프로그램 이름이 이미 args에 담겨져 있기 때문에 사용할 일이 거의 없다. 다만, shell이 주어지면 이 매개변수는 셀의 이름을 지정한다. 기본 값은 None 이다. 

stdin: 자식프로세스에서 stdin에 사용할 파일을 나타내는 파일 객체. stderr에서 사용할 수 있는 값을 사용할 수 있다. 기본 값은 None 이다.

stdout: 자식프로세스에서 stdout에 사용할 파일을 나타내는 파일 객체. stderr에 사용할 수 있는 값을 사용할 수 있다. 기본 값은 None 이다.

stderr: 자식프로세스에서 stderr에 사용할 파일을 나타내는 파일 객체. open()로 생성한 파일객체, 정수 파일 기술자 또는 새로운 파이프가 생성되었음을 나타내는 특수 값 PIPE가 될 수 있다. 기본 값은 None이다.

preexec_fn: 명령을 실행하기 바로 전에 자식프로세스에서 호출할 함수를 지정한다. 이 함수는 인수를 받지 않는다.

close_fds: True이면 자식 프로세스를 실행하기 전에 0,1,2를 제외한 모든 파일 기술자를 닫는다. 기본 값은 0이다.

shell: True 이면 os.system()함수 처럼 작동하는 유닉스 쉘을 사용하여 명령을 실행 한다. 기본 쉘은 /bin/sh 이지만 executable 설정을 통해서 변경할 수 있다. shell의 기본값은 None 이다.  

cwd: 명령을 실행할 디렉터리, 실행 전에 자식 프로세스의 



'Computer Science > Python' 카테고리의 다른 글

GUI Responsive ( Thread, wx.Yield  (0) 2014.04.11
PIL 라이브러리: Image.open AttributeError  (0) 2013.11.26
mutlprocessing의 오류  (0) 2013.07.19
GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07

multiwin.py: Fatal IO error 0 (Success) on X server :0.0. python: ../../src/xcb_io.c:249: process_responses: Assertion `(((long) (dpy->last_request_read) - (long) (dpy->request)) <= 0)' failed.

Sometimes I get:

multiwin.py: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.

위 2개의 에러가 뜬다면, 그것은 multiprocessing 모듈을 썻기 때문일 것이다.


즉 동시에 X server랑 통신하려고하면 에러가 난다.


즉, UI는 무조건 main process에서 변경할 수 있다. fork 시킨 자식 프로세스가 변경하기위해서 X server와 커넥션을 하려고하면 무조건 에러가 난다.


이부분 때문에.. 고생좀 했다. 


아래 사이트 참초:

http://stackoverflow.com/questions/9989475/python-multiprocessing-with-2-gtk-windows



▣ 질문: 멀티 프로세싱을 처리할때 어떻게 해야 신뢰성 있게 자식 프로세스의 stdout 결과를 redirect 할 수 있는가?


답변

이것에 대한 해결방법중 하나는 다음과 같다.

먼저 당신의 프로세스들을 메뉴얼하게 생성 해야 된다. 이러한 것들은 명시적으로 stdout/stderr file 핸들을 접근하게 될 것이다. 그리고 나서 당신은 socket을 이용해서 sub process와 커뮤니케이트를 하게 되고 multiprocessing.connection을 socket 위에서 하게 된다. 즉, multiprocessing.Pipe와 같은 것이다.

이러한 작업은 당신에게 IPC와 같은 기능을 제공해 줄 것이다.


아래에 2개의 에제를 참고하도록 하시오.


master.py

import multiprocessing.connection
import subprocess
import socket
import sys, os

## Listen for connection from remote process (and find free port number)
port = 10000
while True:
    try:
        l = multiprocessing.connection.Listener(('localhost', int(port)), authkey="secret")
        break
    except socket.error as ex:
        if ex.errno != 98:
            raise
        port += 1  ## if errno==98, then port is not available.

proc = subprocess.Popen((sys.executable, "subproc.py", str(port)), stdout=subprocess.PIPE, stderr=subprocess.PIPE)

## open connection for remote process
conn = l.accept()
conn.send([1, "asd", None])
print(proc.stdout.readline())


subproc.py
import multiprocessing.connection
import subprocess
import sys, os, time

port = int(sys.argv[1])
conn = multiprocessing.connection.Client(('localhost', port), authkey="secret")

while True:
    try:
        obj = conn.recv()
        print("received: %s\n" % str(obj))
        sys.stdout.flush()
    except EOFError:  ## connection closed
        break


'Computer Science > Python' 카테고리의 다른 글

PIL 라이브러리: Image.open AttributeError  (0) 2013.11.26
subprocess  (0) 2013.07.26
GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03

윈도우 프로그래밍을 하기위해서는

wxPython이라는 프로그램을 이용하게 된다.


ubuntu에서 설치하기 위해서는 아래의 사이트에서 APT-get명령어를 참조 한다.

http://wiki.wxpython.org/InstallingOnUbuntuOrDebian


그 외의 플랫폼은 아래의 사이트에서 적당한것을 골라서 참조하자.

http://www.wxpython.org/download.php



wxPython을 쉽게 사용하기 위해서 wxGlade라는 편집도구를 사용하게 된다.

이것의 다운로드는 아래의 사이트를 참조한다.

http://sourceforge.net/projects/wxglade/



wxGlade 및 wxPython을 각종 튜토리얼및 소스코드들은 아래를 참고 한다.

http://wiki.wxpython.org/WxGladeTutorial


한국인 블로그 기초적인 튜토리얼이다.

http://sjs0270.tistory.com/entry/wxPython-%EC%9C%BC%EB%A1%9C-GUI-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EB%A7%8C%EB%93%A4%EA%B8%B0-wxGlade



'Computer Science > Python' 카테고리의 다른 글

subprocess  (0) 2013.07.26
mutlprocessing의 오류  (0) 2013.07.19
ImageMagick for Python  (0) 2013.05.07
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03
3장 타입과 객체  (0) 2012.07.01

참고 사이트:


python을 위한 ImageMagick: http://www.imagemagick.org/download/python/


ImageMagick Compare command-line tool: http://www.imagemagick.org/script/compare.php



그냥 commnadLine에서 사용하는 방법은 아래와 같다.


compare -verbose -metric mae rose.

'Computer Science > Python' 카테고리의 다른 글

mutlprocessing의 오류  (0) 2013.07.19
GUI 프로그래밍  (0) 2013.06.23
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03
3장 타입과 객체  (0) 2012.07.01
2장 어휘 규약과 구문  (0) 2012.07.01
7장 클래스와 객체지향 프로그래밍

 

 

self

 

클래스에서 유효 범위가 생성되지 않는 점은 파이썬이나 C++나 자바와 다른 점 중 하나이다.

C++나 자바를 써본 적이 있으면 파이썬의 self 매개변수를 this 포인터와 같다고 생각하면 된다.

파이썬에서는 변수를 명시적으로 선언할 수 있는 방법(즉, C에서 int x나 flot y 같은 선언)이 없기 때문에 self를 써주어야 한다. 그렇지 않으면 메서드에서 변수에 값을 대입할 때 이 값이 지역 변수에 대입되어야 하는 지 인스턴스 속성에 저장되어야 하는지 알 수 있는 방법이 없다. self를 직접 써줌으로써 이 문제를 해결한다. Self에 저장되는 값은 모두 인스턴스의 일부가 되고 나머지는 모두 지역 변수에 저장 된다.

 

 

'Computer Science > Python' 카테고리의 다른 글

GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07
3장 타입과 객체  (0) 2012.07.01
2장 어휘 규약과 구문  (0) 2012.07.01
1장 파이썬 맛보기  (1) 2012.06.21

3장 타입과 객체

 

 

'Computer Science > Python' 카테고리의 다른 글

GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03
2장 어휘 규약과 구문  (0) 2012.07.01
1장 파이썬 맛보기  (1) 2012.06.21

 

파이썬은 특이하게도 세미콜론(;) 따위의 것들을 사용하지 않는다.

 

따라서 줄 바꾸기를 매우 잘 해주어야 구문해석이 정확하게 진행되어 진다.

 

 

문서화 문자열

 

def fact(n):

"This function computes a factorial"

if (n <= 1): return 1

else: return n * fact(n-1)

 

fact.__doc__ 하면

This function computes a factorial"가 출력 된다.

 

 

'Computer Science > Python' 카테고리의 다른 글

GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03
3장 타입과 객체  (0) 2012.07.01
1장 파이썬 맛보기  (1) 2012.06.21

우선 파이썬에서 한글을 쓰기 위해서는

#coding: euc-kr

위 문법을 맨위에 삽입해 준다.

 

 

문자열

 

+연산은 오로지 문자열만 연결한다.

 

수리 계산은 init(), float() 함수로 반드시 변환해야 한다.

z = init(x) + init(y)

 

str()

print시 문자열 변환 함수: str()는 3.4입력시 3.4가 나온다.

 

 

repr()

print는 문자열 변환 함수: repr()는 3.4입력시 3.39999가 나온다.

 

 

format()

 

foramt은 정해진 ofrmat으로 출력을 한다.

format(x,"0.5f ")

 

리스트(List)

 

names = ["a", "b", "c", "d"]

a = names[2]

 

names.append("Paula") # 리스트 가운데의 항목을 교체 한다.

 

b = names[0:2]

 

리스트 연결시 플러스(+)연산자를 사용 한다.

 

빈 리스트 생성

names = []

names = list()

 

import sys
if len(sys.argv) != 2 :
    print "Please supply a filename"
    raise SystemExit(1)

f = open(sys.argv[1])
lines = f.readlines()
f.close()

fvalues = [float(line) for line in lines]

print "min", min(fvalues)
print "max", max(fvalues)

 

 

튜플(tuple)

 

stock = ('GOOG', 100, 490.10)

stock = 'GOOG', 100 ,490.10

 

튜플과 리스트의 가장 큰 차이점은 한번 정의되면 수정 되어질 수 없다는 것이다.

 

하지만 성능 최적화를 위해서는 튜플을 사용하는것이 더 좋다.

왜냐하면 튜플은 수정이 되지 않기 때문에 over memory alloacate를 하지 않는다.

 

List와 Tuple의 코드상에서 구분하는 방법은 대괄호와 소괄호의 차이점으로 구별 한다

 

튜플과 리스트를 함께 사용하는 예제)

#coding: euc-kr

filename = "int"
portfolio = []
for line in open(filename):
    fields = line.split(",") #줄을 분할해서 , 단위로 리스트를 만든다.
   
    #리스트를 각 타입에 맞게 변환 한다.
    name = fields[0]
    shares = int(fields[1])
    price = float(fields[2])
   
    #튜플을 만든다.
    stock = (name, shares, price)
   
    #투플을 리스트에 추가 한다.
    portfolio.append(s 

 

 

 

집합(set)

 

집합은 객체들의 순서 없는 모음을 담는데 사용된다. 집합은 다음과 같이 set()함수에 일련의 항목들을 넘겨 주어 생성 한다.

 

s = set ([3,5,9,10])

리스트나 튜플과는 달리, 집합은 순서가 없기 때문에 숫자로 색인될 수 없다. 게다가, 집합은 요소가 중복되는 일이 없다.

 

즉, t = set("Hello")

set(['H','e','l','o']) 이와 같이 l이 한번만 나타나게 되는 것이다.

 

집합 연산자를 사용 할 수 있다.

 

또한 집합에 아이템이 추가될수도 삭제될 수도 있다.

add()

update()

remove()

 

사전(dictionary)

 

사전은 키로 색인되는 객체들을 담는 연관 배열 혹은 해시 테이블이다.

다음과 같이 값들을 중괄호({})로 둘러싸서 사전을 생성 한다.

 

stock = {

"name" : "GOOG",

"shares" : 100,

"price" : 490.10

}

 

키로 접근해서 자료를 꺼내오거나 갱신 한다.

객체 추가 및 수정은

stock["shares"] = 75

stock["date"] = "June 7, 2007"

주로 문자열이 키로 사용되지만, 숫자나 튜플 같은 다른 파이썬 객체도 키로 사용될 수 있다.

 

사전은 이름 있는 필드들로 구성되는 객체를 정의하는 데 유용하게 쓰인다.

하지만, 사전은 순서 구분 없는 데이터를 빠르게 검색하기 위한 용도의 컨테이너로도 사용 된다.

 

빈사전을 만드는 방법

 

prices = {}

prices = dict()

 

사전에 어떻게 키가 들어있는지 확인 하는 방법

1) 방법 in 연산자의 활용

if "SCOX" in prices:

p = prices["SCOX"]

else:

p = 0.0

2) 방법

p = prices.get("SCOX",0.0)

 

사전의 키 목록을 얻고 싶으면 사전을 리스트로 변환하면 된다.

syms = list(prices)

# syms에는 "AAPL", 등..이 연속해서 저장되어진다.

 

del prices["MSFT"]

 

사전은 파이썬의 꽃이다. 따라서 이것을 잘 사용하는것이 좋다.

 

 

반복과 루프

 

for를 이용해서 가장 간단하게 루프를 도는 형태는 간단히 문자열, 리스트, 튜플 같은 순서열의 모든 구성요소에 대해 루프를 도는 것이다. 다음은 한 예이다.

 

#coding: euc-kr

f = open("int")
for line in f:
    print line

 

 

 

함수

 

다음 예처럼 함수는 def문을 사용해 생성한다.

 

#coding: euc-kr

def remainder(a,b):
    q = a // b
    r = a - q*b
   
    return r

result = remainder(37,15)

print result 

 

 

 

특이한점

리턴이 2개 이상일 수 있다.

 

return (a,b)

 

a,b = func()

 

인자의 초기 값이 있을 수 있다.

 

저역 변수를 수정 할 때에는 global이라는 keyword를 사용 한다.

 

생성기

 

함수는 단일 값을 변환하는 대신, yield문을 사용해 일련의 결과 값을 생성할 수도 있다.

def countdown(n):
    print "Counting down!"
    while n > 0:
        yield n # 값(n)을 생성한다.
        n -= 1

c = countdown(5);

for i in countdown(5):

 

 

yield를 사용하는 함수를 생성기(generator)라고 부른다. 생성기 함수를 호출하면, next() 메서드를 호출 하면 일련의 결과를 반환하게 된다.

 

 

생성기는 처리 파이프라인, 스트림, 데이터 흐름에 기반한 프로그램을 작성할 때 강력한 위력을 발휘 한다. 예를 들어, 다음 생성기 함수는 로그 파일을 검토하는 데 흔히 사용되는 유닉스의 tail -f 명령의 동작을 흉내낸다.

 

리눅스 명령어중 grep을 흉내낸 파이썬 코드이다.

 def grep(lines, searchtext):
    for line in lines:
        if searchtext in line: yield line

       
f = open("int")

lines = f.readlines()

c = grep(lines,"MS")

print c.next() 

 

 

리눅스 명령어 "tail -f | grep python"를 구현 하겠다.

즉 2개의 generatior를 연결 시켜서 리눅스의 파이프라인을 구현한 간단한 예이다.

 

#coding: euc-kr
import time

def tail(f):
    f.seek(0.2)
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

def grep(lines, searchtext):
    for line in lines:
        if searchtext in line: yield line
       
#f = open("int")
#lines = f.readlines()
#c = grep(lines,"MS")
#print c.next()

wwwlog = tail(open("int"))
#f = open("int")
#lines = f.readlines()
pylines = grep(wwwlog,"MS")

for line in pylines:
    print line,

 

 

 

 

 

 

코루틴

 

보통 함수는 입력으로 주어진 인수에 대해서 한 번만 실행된다. 하지만, 일련의 입력을 처리하도록 함수를 작성할 수도 있다. 이런 종류의 함수를 coroutine이라고 한다.

 

yield는 그냥 쓰면 generator이지만, ()를 양 옆에 달게 되면 coroutine이 된다.

 

 

def print_matches(matchtext):
    print "Looking for", matchtext
    while True:
        line = (yield)
        if matchtext in line:
            print line

#matchtext로 초기화 한다음

#matcher.send()를해서 해당 문자열이 있는지 검사하게 만들 수 있다.

 

 

 코루틴은 send()로 값이 도착할 때까지 멈춰 있는다.

send()가 호출되면, 코루틴 안에서 yield 표현식을 만날 때까지 계속되고, 그 순간 함수가 다시 멈춘다.

앞의 예에서 보았듯이, 이 과정은 close()가 호출될 때까지 이어진다.

 

코루틴은 프로그램의 한 곳에서 생성된 데이터를 다른 곳에서 소비하는 생성자 소비자 모델이 기반한 병행 프로그램을 작성할 때 유용하게 쓰인다. 이 모델에서 코루틴은 데이터 소비자의 역할을 수행한다. 다음은 생성기와 코루틴을 결합하는 예이다.

 

 

객체와 클래스

객체에 정의된 메서드를 살펴 보고 싶을 경우

dir(object)를 하면 알 수 있다.

 

이렇게해서 메서드를 확인할 경우 __메서드__ 와 같이 이중 언더바로 시작하고 끝나는 특수한 메서드들을 볼 수 있다.

 

 

 

 

 #coding: euc-kr

class Stack(list):
    def push(self,object):
        self.append(object)

s = Stack() # 스택을 생성한다.
s.push("Dave")
s.push(42)
s.push([3,4,5])

print s.pop()
print s.pop()

 

 

C++ / java 프로그래밍에서 쓰는 정적 메서드 또한 사용 할 수 있다.

@staticmethod

 

예외

 

try이와 except문으로 예외를 잡아서 처리 할 수 있다.

 

#coding: euc-kr

try:
    f = open("int2","r")
except IOError as e:
    print e 

 

 

IOError가 발생하면, 에러의 원인에 대한 내용이 e에 담기고 except 블록으로 제어가 넘어간다.

 

 

모듈

 

프로그램 크기가 커지면 손쉬운 관리를 위해 프로그램을 여러 파일로 나누고 싶어 질 것이다.

파이썬에서는 정의들을 파일에 넣어 다른 프로그램이나 스크립트에 Import할 수 있는 모듈의 형태로 사용할 수 있다.

 

모듈을 생성하려면 관련문장과 정의들을 모듈과 동일한 이름을 가지는 파일에 넣으면 된다.

 '''
Created on 2012. 6. 30.

@author: root
'''

def divide(a,b):
    q = a/b
    r = a -q*b
    return(q,r)

 

 

 #coding: euc-kr

import div as foo

a,b = foo.divide(2305,29)

print "%d %d" %(a,b)   

 

 

 

도움

 

dir(package name)

 

print packagename.__함수__

 

위와 같이 입력하면 해당함수의 사용법을 알 수 있다.

 

 

 

 

'Computer Science > Python' 카테고리의 다른 글

GUI 프로그래밍  (0) 2013.06.23
ImageMagick for Python  (0) 2013.05.07
7장 클래스와 객체지향 프로그래밍  (0) 2012.07.03
3장 타입과 객체  (0) 2012.07.01
2장 어휘 규약과 구문  (0) 2012.07.01

+ Recent posts