문자열을 암호화하는 방법은 여러가지가 있습니다만,
이번에는 가장 간단한 방법 중 하나인 caesar  암호법을 이용해 보죠.
caesar 암호법은 각각의 알파벳을 나열한 후, 일정한 간격으로 옮기는 방법입니다.
예를 들어, 'GOOD'를 오른쪽으로 하나씩 옮기면 'HPPE'가 되서 알아보기 힘들게 되는 것이죠.

이 문제는 chr과 ord를 이용하면 아래 예제와 같이 간단하게 해결됩니다.

import sys
SHIFT=1

def encrypt( raw ):
    ret = ''
    for char in raw:
        ret+=chr( ord(char)+SHIFT )
    return ret

def decrypt( raw ):
    ret = ''
    for char in raw:
        ret+=chr( ord(char)-SHIFT )
    return ret
   
if __name__=="__main__":
    print( sys.version )
    raw = input("input : ")
    encrypted = encrypt( raw )
    print("encrypted : " + encrypted)
   
    decrypted = decrypt( encrypted )
    print("decrypted : " + decrypted)
    input("press any key")

이 예제에서 어느정도 간격으로 이동할지에 대한 변수는 SHIFT입니다.
즉 현재는 오른쪽으로 1칸 이동하게 짜여져 있는 것입니다.
실행시켜보면 다음과 같이 암호화/복호화가 잘 되는 것을 볼 수 있습니다.

3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)]
input : hello world
encrypted : ifmmp!xpsme
decrypted : hello world
press any key


AND

소수는 1과 자신 이외의 약수를 갖지 않는 정수를 이야기 합니다.
정수를 입력 받아 그 수가 소수인지 아닌지 검사하는 프로그램을 짜 봅시다.

다음과 같이 소수의 정의대로 2에서부터 입력받은 n-1까지 순회하며 나누어 떨어지는지 아닌지 검사하면 간단히 해결됩니다.

import sys
import math

def isPrime(n):
    bPrime = True
    for i in range(2,int(math.sqrt(n))+1):
        if n%i==0:
            bPrime = False
            break
    return bPrime

if __name__=="__main__":
    print( sys.version )
    N = input("input a number : ")
    if isPrime(int(N)):
        print("prime number")
    else:
        print("not prime number")
    input("press any key")

실행해 보면 다음과 같이 동작하는 것을 알 수 있습니다.

3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)]
input a number : 30
not prime number
press any key

3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)]
input a number : 13
prime number
press any key

그러나 이 예제에는 약간 비효율적인 면이 있는데요.
소수검사는 2에서부터 n-1까지 할 필요가 없습니다. 2에서부터 sqrt(n)까지만 하면 충분하죠.
즉 아래와 같이 isPrime 함수를 변경하면 속도가 약간 더 빠르게 됩니다.

import math

def isPrime(n):
    bPrime = True
    for i in range(2,int(math.sqrt(n))+1):
        if n%i==0:
            bPrime = False
            break
    return bPrime

AND

간단하게 2.x에서 3.0으로 변환이 잘 되는지 테스트해보기 위해 다음과 같이
test.py 파일을 작성해 보겠습니다.

def div(a):
  print u"Result :", a/2
num = raw_input("input any number :")
div(int(num))

그럼 test.py 파일을 2to3.py를 이용해서 변환을 해 보겠습니다.

C:\Python30\Tools\Scripts>2to3.py -w test.py
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
--- \Python30\test_.py (original)
+++ \Python30\test_.py (refactored)
@@ -1,4 +1,4 @@
 def div(a):
-  print u"Result :", a/2
-num = raw_input("input any number :")
+  print("Result :", a/2)
+num = input("input any number :")
 div(int(num))
RefactoringTool: Files that were modified:
RefactoringTool: \Python30\test_.py

참고사항.
2to3에 -w 옵션을 주지 않으면 어떻게 변경해야하는지만 화면에 출력하고, 파일에 직접 수정을 가하진 않습니다.

이제 아래와 같이 바뀐 것을 확인할 수 있습니다.

C:\Python30\Tools\Scripts>type test.py
def div(a):
  print("Result :", a/2)
num = input("input any number :")
div(int(num))

다음과 같이 실행도 잘 되는 것을 확인할 수 있네요.

>test.py
input any number :3
Result : 1.5


간단한 프로그램은 이렇게 쉽게 변환이 되지만,
큰 모듈의 경우에는 테스트케이스를 견고하게 짜서 오동작을 하는지 안하는지 체크하는 것이 필수적으로 필요할 것입니다.

또한 2.5 이하의 버전의 코드를 3.0으로 포팅하려면,
우선 2.6으로 코드를 포팅하고, 2.6에서 -3 옵션을 붙여서 실행 한 후, 경고를 처리합니다.
공식문서에서는 위 작업을 완료한 후에 2to3을 사용하는 것을 권장하고 있습니다.


메리 크리스마스~~~
AND

후우, 한동안 포스팅이 뜸했는데요.

오늘은 python 2.x과 3.0의 차이를 살펴보겠습니다.

이전 글에서 썼듯이, 파이썬3000(파이썬3k)이라고도 불리는 파이썬 3.0이 2008년 12월 초에 발표되었습니다.
이번 변경 사항 중에 특히 주목해야할 것은 파이썬 2.x 버전들과 하위 호환성을 전혀 유지하고 있지 않은 것입니다.
실무에 사용하던 분들은 아직 3.0을 적용할 필요성을 못 느끼시는 분들이 많을 것이나,
추후 적용하기 위해서는 차이점을 짚고 넘어가야 할 것입니다.

자료형이나 내부 구성의 변화 등도 크게 변화 했지만, 아무래도 사용자 입장에서는 다음 사항들이 가장 크게 느껴질 것입니다.


* 체감상으로 가장 큰 차이점은 print가 함수형태로 변경된 점입니다.

Old style :
>>> print "welcome to", "python3k"
welcome to python3k

New style :
>>> print( "welcome to","python3k" )
welcome to python3k

또한 입력인자로 다음과 같이 sep, end, file 를 줄 수 있습니다.

>>> print("welcome to","python", sep="~", end="!", file=sys.stderr)
welcome to~python!

이와 유사하게 입출력관련해서 변경된 점들이 많습니다.
raw_input이 input으로 변경되고,
as, with 예약어가 추가되었습니다.
또한 새로운 string formatting을 제공한답니다.

* long type이 없어졌습니다. 즉, int로 통일 되었습니다.

Old :
>>> type(2**31)
<type 'long'>

New :
>>> type(2**31)
<class 'int'>
>>> type(2**40)
<class 'int'>

2.x에서는 sys.maxint 이하의 값은 int로 처리되고 그 이상의 값은 long으로 처리되었는데요,
3.0에서부터는 모두 int로 처리됩니다.

Old :
>>> sys.maxint
2147483647
>>> type( sys.maxint )
<type 'int'>
>>> type( sys.maxint+1 )
<type 'long'>

* int / int 의 결과는 float 으로 처리됩니다.

Old :
>>> 1/2
0
>>> 3/2
1

New :
>>> 3/2
1.5
>>> type(2/2)
<class 'float'>

사실 2.x에서는 int / int의 결과가 int로만 나와서 예상 밖의 결과가 나온 적이 많은데요,
이제는 그럴 일이 적어질 것 같습니다 :)

* String, Unicode 체계가 바뀌었습니다.

2.x에서는 아래 예제와 같이 string과 unicode로 구분이 되었습니다.

>>> type( '가' )         # 일반 string의 경우.
<type 'str'>

>>> type( '가'.decode('utf8') )          # 인코딩을 가지고 있는 스트링을 디코딩한 경우.
<type 'unicode'>

>>> type( u'가' )
<type 'unicode'>        # 유니코드의 경우.


그러나 3.0에서는 아래 예제와 같이 string과 byte로 구분이 됩니다.

>>> type(u'가')
SyntaxError: invalid syntax (<pyshell#13>, line 1)

>>> type('가')
<class 'str'>

>>> type('가'.encode('cp949'))
<class 'bytes'>

즉, 2.x에서는 일반 스트링이 인코딩이 있는 문자열이었고 unicode가 따로 있었는데,
3.0에서는 일반 스트링이 unicode와 동일하며, 인코딩이 있는 문자열은 bytes로 표현됩니다.


이 이외에도 자잘한 변경사항이 많습니다만, 너무 걱정하지 마세요.
2.x에서 3.0으로의 간편한 변환을 위해 2to3 스크립트가 제공된 답니다.
물론 만능은 아니지만 왠만한 코드는 자동으로 변환할 수 있습니다.

다음에는 이 2to3 스크립트에 대해서 한번 짚고 넘어가도록 해 보겠습니다.

AND

python 3.0 릴리즈

개발/python 2008. 12. 4. 15:35
두둥...

python 3.0이 드디어 릴리즈 되었습니다.

http://python.org/download/releases/3.0/

rc3가 나온지 며칠 되지 않아서 곧바로 업뎃 되네요...

2.x와 3.0의 차이는 다음의 문서를 보면 알 수 있습니다.

http://docs.python.org/dev/3.0/whatsnew/3.0.html

휴우 2.x에 익숙해져 있었는데 3.0에 적응하려면 좀 시간이 걸리겠네요~
AND

예전에 정리한 바와 같이 python은 C와 연동하기 나름 쉽습니다.

이번에는 마치 pyGtk처럼 다른 큰 library들을 끼고도 잘 되나 실험해봤습니다.

interface와 몸통파일은 다음과 같습니다.

>> cat foo.i
 %module foo
 %{
 extern int foo(void);
 %}
 extern int foo(void);

>> cat foo.c
#include <gtk/gtk.h>
int foo(void) {
    gtk_init(0,0);   
    GtkWidget *window;   
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window), "foo" );
    gtk_widget_show (window);
    gtk_main ();

    return 0;
}


그리고 다음과 같이 연결을 해주면 됩니다.

dsp@dsplinux:~/Projects/swig$ swig -python foo.i
dsp@dsplinux:~/Projects/swig$ gcc -c foo.c foo_wrap.c -I/usr/include/python2.5 `pkg-config --cflags gtk+-2.0`
dsp@dsplinux:~/Projects/swig$ ld -shared foo.o foo_wrap.o -o _foo.so `pkg-config --libs gtk+-2.0`

dsp@dsplinux:~/Projects/swig$ ipython
Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52)
Type "copyright", "credits" or "license" for more information.

IPython 0.8.1 -- An enhanced Interactive Python.
?       -> Introduction to IPython's features.
%magic  -> Information about IPython's 'magic' % functions.
help    -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.

In [1]: import foo

In [2]: foo.foo()

위와 같이 foo.foo()를 실행하면 윈도가 잘 뜨는 것을 확인할 수 있습니다.
정말로 pyGtk처럼 하려면 c++스타일로 붙이면 되겠죠.

AND

요즘 회사용 linux PC(ubuntu 8.04 hardy)에 Screenlets(http://www.screenlets.org/index.php/Home)를 깔아 쓰고 있습니다. 그 중에 보면 Slideshow가 있는데요. Slideshow의 기능 중에 Flickr의 공개된 일부 그림들을 볼 수가 있는데요. 이게 URL이 정해져 있어서 좀 답답합니다. 그래서 이걸 좀 다른 Flickr도 쓸 수 있게 바꿔보았습니다.


[Screenlets 화면]

/usr/share/screenlets/Slideshow/SlideshowScreenlet.py를 다음과 같이 수정하면 됩니다. 혹시 python-BeautifulSoup이나 python-image-library가 안 깔려 있다면 설치해야 합니다. 아래 와 같이 수정하면 Flickr로 설정을 변경할 경우, 전지현+김태희 그림이 나오도록 세팅되어있구요. 이걸 바꾸거나 추가하고 싶으면, 파일 제일 앞부분의 FLICKR_URLS = [ ... ] 에 url string을 추가하면 됩니다.

우선 파일 앞부분에 다음을 추가합니다.

FLICKR_URLS = [
    'http://www.flickr.com/search/?s=int&q=%EC%A0%84%EC%A7%80%ED%98%84&m=text',
    'http://www.flickr.com/search/?s=int&q=%EA%B9%80%ED%83%9C%ED%9D%AC&m=text'
]
from BeautifulSoup import BeautifulSoup
import re


그리고 파일 중간 부분의 fetch_image 함수를 다음과 같이 수정합니다. 즉, fetch_image 함수에서 if self.engine1=='Flickr': 부분부터 imageget = urlopen(realimage) 앞까지 쭈욱 갖다 붙이시면 됩니다. 아, 물론 이 사이에 있던 기존 코드는 살짝 주석처리해 주셔야됩니다.

def fetch_image(self):

    ...

     if self.engine1 == 'Flickr':
        #appended by dsp.shin
        source = urlopen( random.choice( FLICKR_URLS) )
        sourcetxt = source.read()

        sources = []
        reals = []
        rPhoto = re.compile('/photos(.*?)')
        soup = BeautifulSoup( sourcetxt )
        hrefs = soup('a', {'href':rPhoto})
        for href in hrefs:
            imgs = href('img', {'class':'pc_img'})
            if len(imgs)>0:
                sources.append( href.get('href') )
                reals.append( imgs[0].get('src') )
        if len(sources)>0:
            index = random.randint(0, len(sources)-1)
            sourceimage = str(sources[index])
            realimage = str(reals[index])
            imageurl = 'http://www.flickr.com' + sourceimage
            self.url = imageurl
        else:
            #not working
            realimage = 'http://creativeclass.typepad.com/thecreativityexchange/images/2007/09/19/menatwork.png'
            self.url = realimage
        #end -- dsp.shin


        imageget = urlopen(realimage)
        ...


ps. 현재는 flickr 검색페이지 결과만 파싱 가능함.
ps2. 괜찮은 연예인 flickr url(or 검색어) 찾으면 댓글로 좀 알려주세요~

AND

주기적으로 mysql db를 백업할 일이 생기는데,
백업 후에 replication을 다시 설정하려면 이쪽저쪽 서버에 접속을 해야합니다.

그러한 이유로 python 상에서 ssh 접속을 어떻게 하나 찾아봤더니,
paramiko라는게 있더군요.

#SSH 접속하기. - by using paramiko
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect(HOST, username=USER, password=PASSWORD)
stdin, stdout, stderr = client.exec_command('ls -l')
print stdout.read()
client.close()

위의 스크립트를 이용해서 ssh에 접속하고 나머지는 다음의 순서로 해결할 수 있겠습니다.
물론 이건 incremental하게 backup & sync하는건 아니고 통짜로 무쉭하게 할 경우에 대한 이야기입니다.

1. get master-status
2. dump
3. rsync
4. ssh open
4.1 drop db
4.2 import
4.3 slave setup & start
4.4 ssh close

1번에서 master-status를 가져오는건 commands.getoutput()을 이용하면 됩니다.
즉, "Master에 기존 데이터가 있는 상태에서 replication 하기"의 내용을 스크립트로 실행시키는거죠.

AND

MetaWebLogAPI를 사용하면 블로그에 접속하지 않고서도 포스팅을 할 수 있습니다.
python에서는 다음과 같이 간단한 함수 하나만 짜면 되죠.
물론 getPost, editPost도 가능하지만 가장 사용빈도가 높은 newPost만 예로 들겠습니다.

아래의 예는 tistory의 경우입니다.
(물론 환경설정에 가서 blogapi를 활성화 시켜 놓아야 합니다)

다른 블로그 서비스들의 경우도 크게 다르지 않습니다.

def Post( title, description, tags ):
    import xmlrpclib
    tistory=xmlrpclib.Server("http://somewhere.tistory.com/api")
    post={'category': '',
        'title': title,
        'description': description,
        'mt_keywords': tags }
    no=tistory.metaWeblog.newPost("blog ID", "user ID","password", post, True)
    print "posted :",no

       
보다 자세히 xmlrpc에 대해 알고 싶으시다면,
아래 링크에 가서 mark pilgrim님의 글을 읽어보세요.
http://www.xml.com/pub/a/2003/10/15/dive.html
AND

ubuntu에서 설치는 synaptic을 이용해서 간단하게 설치가능하니 생략하고...
mod_python을 설치한 후에 enable 시키려면,
/etc/apache2/mods-enabled 폴더에 symbolic link 를 다음과 같이 건다.

mod_python.load -> ../mods-available/mod_python.load

또한 httpd.conf , 혹은 다른 conf file에 다음과 같이 python handler를 지정한다.

<Directory "/python코드의패쓰">
AddHandler python-program .py
PythonHandler test
PythonDebug on
</Directory>

다음과 같이 지정된 경로에 test.py 파일을 생성한다.

from mod_python import apache

def handler(req):
  req.content_type="Text/Plain"
  req.send_http_header()
  req.write("This is a test page...")
  return apache.OK

그리고 apache를 재시작한 후,

sudo /etc/init.d/apache2 restart

이제, 사이트에 접속해 보면 된다.

http://localhost/python/test.py


혹시 php, perl에는 익숙하고 python은 잘 모른다면,
아래 사이트가 유용할 것이다.

http://qna.nu/w/cs/?python=on&php=on&perl=on
AND