태그 보관물: python

[Python 2.x] print without newline

파이썬 2.X 에서 줄바꿈 없이 출력하기

파이썬 2.x를 사용하다 보니 출력 결과가 줄바꿈이 되서 표시되는 현상이 발생하였습니다.
그래서 그걸 해결하기위해 검색하다보니 역시나…

from __future__ import print_function

위와 같이 선언하고 python3 에 있는 print 함수를 동일하게 사용하면 되는 편리함이…

data = ['hello', 'world']
for d in data:
    print(d, end=' ')

# 출력결과
# hello world

다른 방법은 sys 모듈을 사용하는 방법입니다.

sys.stdout.write('a')

위와 같이 사용하면 되는데 sys 모듈을 사용하는 것 보다는 __future__print_function 을 사용하는게 보다 유용하게 사용할 수 있을 것 같습니다.

이상입니다.

[Shell Script] 인라인 파이썬코드로 ini 파일 파싱

Shell Script에서 python 을 이용하여 ini 파일 파싱


의도

쉘 스크립트를 이용해 /etc/systemd/system/서비스명 파일을 분석하려고 하니 스크립트에서 ini 형태의 파일을 분석하는게 조금 노가다성이라 pythonConfigParser 를 이용하면 좋겠다라는 생각이 들어 사용하였습니다.

[/etc/systemd/system/web-monitor.service] 샘플

[Unit]
Description=CHIeru Webmonitoring system.

[Service]
ExecStart=/usr/bin/node $INSTALL_PATH/server/server.js
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=web-monitor
User=root
Environment=\"NODE_CONFIG_DIR=$INSTALL_PATH/config\"

[Install]
WantedBy=multi-user.target

위의 부분에서 제가 필요한 부분은 Service 섹션의 ExecStart 값중 INSTALL_PATH 경로를 가져오는 것입니다.

[Shell Script code]

pathFromService=$(python - <<EOF
import ConfigParser
import os
Config = ConfigParser.ConfigParser()
Config.read('/etc/systemd/system/web-monitor.service')
executeCommand = Config.get('Service', 'ExecStart')
executeFilePath = executeCommand.split(' ')[1]

installationPath = os.path.abspath(os.path.dirname(executeFilePath) +'/../')

print installationPath
EOF
)
    LEN=$(echo ${#pathFromService})
    echo $pathFromService

[Python] 크리스마스트리

제작 의도

어제 다음 카페 게시글을 보다 보니 각 학과별 크리스마스트리를 그리는 방법이라는 글이 올라와 있어 Python을 이용하여 크리스마스 트리를 제작해봤습니다.

모두 즐거운 성탄절 되세요..!!

소스 코드

ROW = 9


def printTree(maxCountOfSpaceNStart):
    for i in range(1, maxCountOfSpaceNStart):
        print '%*s%*s' % (ROW-i, ' ', 0, '*' * (i * 2 -1))

if __name__ == '__main__':
    print '=' * 20
    print '%2s%s' % (' ', 'Merry Christmas!!!')
    print '=' * 20
    trees = [5, 7, 9]
    for i in trees:
       printTree(i)

실행 결과

====================
  Merry Christmas!!!
====================
        *
       ***
      *****
     *******
        *
       ***
      *****
     *******
    *********
   ***********
        *
       ***
      *****
     *******
    *********
   ***********
  *************
 ***************

[Python] netstat

개발 내용

네트워크 프로그래밍을 하다 보면 서버에서 어떤 클라이언트가 접속했는지 확인을 해야 하는데 Windows 환경에서 제공하는 netstat 으로 목록을 출력하고 findstr command를 이용하여 필터링하는 과정을 주기적으로 하는 프로그램을 Python 으로 구현

개발 및 동작 환경

  • OS: Windows 7 64Bit
  • Python: 2.7.10

소스 코드

# -*- coding: utf-8 -*-
# ===================================================================
# Author: coozplz@gmail.com
# File: netstat.py
# Date: 2015. 10. 16
# Desc: Windows command "netstat -anp tcp | findstr [PORT]" 를 주기적으로 하는 프로그램
# ===================================================================

import subprocess
import time
from time import localtime, strftime
import datetime

PORT = '12084'
SLEEP_SEC = 5


class NetstatInfo:
    def __init__(self, protocol, local_addr, remote_addr, status):
        self.protocal = protocol
        self.local_addr = local_addr
        self.remote_addr = remote_addr
        self.status = status

    def __str__(self):
        return '%s %s %s %s' % (self.protocal, self.local_addr, self.remote_addr, self.status)


if __name__ == '__main__':
    while True:
        print '-' * 70
        print '%40s' % strftime('%Y-%m-%d, %H:%M:%S', localtime())
        print '-' * 70
        out, err = subprocess.Popen("netstat -anp tcp", stdout=subprocess.PIPE).communicate()
        result = out.splitlines()
        filtered_line = []
        for line in result:
            if PORT in line:
               splitted_value = filter(lambda x: len(x) > 0, line.split(' '))
               n = NetstatInfo(splitted_value[0], splitted_value[1], splitted_value[2], splitted_value[3])
               print n
        time.sleep(SLEEP_SEC) 

오픈소스 파일별 라인수

집에서 동영상으로 코딩 가이드에 대한 강좌를 보는 과정중에 재미난 내용이 있어 python을 사용해서 분석해 보았습니다.

해당 동영상에 나온 내용은 빠른 시일내에 블로그에 정리해서 올릴려고 합니다. 좋은 내용들이 많아서…

프로그래밍 가이드에는 왜 한 라인에 80자만 사용하라고 하는 것인가?

동영상 강좌에 나온 내용으로는 예전 환경은 콘솔 + 작은 모니터 + IDE없는 이어서 한 줄에 80라인을 넘기면 보기가 어려워서 그렇다고 설명을 하였습니다.

그러면서 나온게 최근에 사용되는 오픈소스 프로젝트인 JUnit, Ant와 몇몇가지를 예를 들어 최근에는 80자가 넘는 소스들도 많이 있다고 하였습니다.

그렇지만 한 줄에 너무 많은 글자를 쓰면 가독성이 떨어진다고 단지 좌우스크롤이 안될 정도로만 하라고 설명하셨습니다.

분석

그렇다면 제가 자주 사용하는 라이브러리들은 한 줄에 어느정도의 평균 글자수 와 한 파일에 몇라인이 포함되어 있는지 확인을 해보았습니다.

분석은 소스 폴더에 포함된 java로 확장자를 가지는 파일을 대상으로 하였습니다.

[분석도구]

  1. python 2.7
  2. matplotlib
  3. OSX(Yosemite)

[분석대상]

  1. commons-lang
  2. commons-net
  3. Ant
  4. Open JDK7

결과

결과는 어느정도 예상한대로 commons-lang 과 commons-net의 경우는 평균 100자를 넘지 않는 수치가 나왔습니다. 그렇지만 의외로 open-jdk7에서 평균 400자를 넘는 파일이 있어 확인을 해보니 그럴만한 이유가 있었습니다. 기타 참조

commons-lang

commons-lang_result

commons-net

commons-net_result

open-jdk7

jdk_result

분석 소스

import os
import fnmatch
import matplotlib.pyplot as plt

class FileVO:
def __init__(self, filename, file_size, line_of_file, avg_char):
self.file_size = file_size
self.line_of_file = line_of_file
self.avg_char = avg_char
self.filename = filename

def __str__(self):
return '%-20s / size=%5d, line=%5d, chars(AVG)=%5d' % (self.filename, self.file_size, self.line_of_file, self.avg_char)

if __name__=='__main__':
matches = []
source_path = '/Users/coozplz/Downloads/sources/src-jdk'
for root, dirnames, filenames in os.walk(source_path):
for filename in fnmatch.filter(filenames, '*.java'):
found_file = os.path.join(root, filename)
file_size = os.path.getsize(found_file)
js_file = open(found_file)
lines = js_file.readlines()
sum_of_chars = 0
for line in lines:
sum_of_chars += len(line)
vo = FileVO(filename, file_size, len(lines), sum_of_chars / len(lines))
# print vo
matches.append(vo)
js_file.close()

plt.title("%s(%d files)" % (source_path, len(matches)))
for match_file in matches:
plt.scatter(match_file.line_of_file, match_file.avg_char)
plt.ylabel("Average chars of line")
plt.xlabel("Lines per file")
plt.grid()
plt.show()

기타

평균글자수가 가장 많은 파일 : launcher.java
아래와 같은 코딩이 되어 있어 평균 글자수 길이가 비약적으로 많이 나오는거 같습니다. 나머지 파일들도 마찬가지라고 생각합니다.

소스코드

package sun.launcher.resources;

import java.util.ListResourceBundle;

public final class launcher extends ListResourceBundle {
protected final Object[][] getContents() {
return new Object[][] {
{ "java.launcher.X.macosx.usage", "nThe following options are Mac OS X specific:n -XstartOnFirstThreadn run the main() method on the first (AppKit) threadn -Xdock:name="n override default application name displayed in dockn -Xdock:icon=n override default icon displayed in docknn" },
{ "java.launcher.X.usage", " -Xmixed mixed mode execution (default)n -Xint interpreted mode execution onlyn -Xbootclasspath:n set search path for bootstrap classes and resourcesn -Xbootclasspath/a:n append to end of bootstrap class pathn -Xbootclasspath/p:n prepend in front of bootstrap class pathn -Xdiag show additional diagnostic messagesn -Xnoclassgc disable class garbage collectionn -Xincgc enable incremental garbage collectionn -Xloggc: log GC status to a file with time stampsn -Xbatch disable background compilationn -Xms set initial Java heap sizen -Xmx set maximum Java heap sizen -Xss set java thread stack sizen -Xprof output cpu profiling datan -Xfuture enable strictest checks, anticipating future defaultn -Xrs reduce use of OS signals by Java/VM (see documentation)n -Xcheck:jni perform additional checks for JNI functionsn -Xshare:off do not attempt to use shared class datan -Xshare:auto use shared class data if possible (default)n -Xshare:on require using shared class data, otherwise fail.n -XshowSettings show all settings and continuen -XshowSettings:alln show all settings and continuen -XshowSettings:vm show all vm related settings and continuen -XshowSettings:propertiesn show all property settings and continuen -XshowSettings:localen show all locale related settings and continuennThe -X options are non-standard and subject to change without notice.n" },
{ "java.launcher.cls.error1", "Error: Could not find or load main class {0}" },
{ "java.launcher.cls.error2", "Error: Main method is not {0} in class {1}, please define the main method as:n public static void main(String[] args)" },
{ "java.launcher.cls.error3", "Error: Main method must return a value of type void in class {0}, please ndefine the main method as:n public static void main(String[] args)" },
{ "java.launcher.cls.error4", "Error: Main method not found in class {0}, please define the main method as:n public static void main(String[] args)" },
{ "java.launcher.ergo.message1", " The default VM is {0}" },
{ "java.launcher.ergo.message2", " because you are running on a server-class machine.n" },
{ "java.launcher.init.error", "initialization error" },
{ "java.launcher.jar.error1", "Error: An unexpected error occurred while trying to open file {0}" },
{ "java.launcher.jar.error2", "manifest not found in {0}" },
{ "java.launcher.jar.error3", "no main manifest attribute, in {0}" },
{ "java.launcher.opt.datamodel", " -d{0}t use a {0}-bit data model if availablen" },
{ "java.launcher.opt.footer", " -cp n -classpath n A {0} separated list of directories, JAR archives,n and ZIP archives to search for class files.n -D=n set a system propertyn -verbose:[class|gc|jni]n enable verbose outputn -version print product version and exitn -version:n require the specified version to runn -showversion print product version and continuen -jre-restrict-search | -no-jre-restrict-searchn include/exclude user private JREs in the version searchn -? -help print this help messagen -X print help on non-standard optionsn -ea[:...|:]n -enableassertions[:...|:]n enable assertions with specified granularityn -da[:...|:]n -disableassertions[:...|:]n disable assertions with specified granularityn -esa | -enablesystemassertionsn enable system assertionsn -dsa | -disablesystemassertionsn disable system assertionsn -agentlib:[=]n load native agent library , e.g. -agentlib:hprofn see also, -agentlib:jdwp=help and -agentlib:hprof=helpn -agentpath:[=]n load native agent library by full pathnamen -javaagent:[=]n load Java programming language agent, see java.lang.instrumentn -splash:n show splash screen with specified imagenSee http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details." },
{ "java.launcher.opt.header", "Usage: {0} [-options] class [args...]n (to execute a class)n or {0} [-options] -jar jarfile [args...]n (to execute a jar file)nwhere options include:n" },
{ "java.launcher.opt.hotspot", " {0}t is a synonym for the "{1}" VM [deprecated]n" },
{ "java.launcher.opt.vmselect", " {0}t to select the "{1}" VMn" },
};
}
}

[Python] 018/067 Maximum Path Sum

밤에 잠이 안와서 시작한 문제 풀이가 어느덧 3시간이 지났다.
그래서 풀어서 기분은 좋다..^^

문제를 보고 잘못 생각해서 위에서 아래로 큰 수를 찾아가는 거로 계산을 하고 제출을 했는데 오답 표시.

문제를 다시 읽어보니 어떻게 풀어야 할지 조금 막막하다.. 구글신의 도움을 받아 다른 사람이 어떻게 풀었는지를 찾아보았다.

http://www.mathblog.dk/project-euler-18/

위의 링크에 보면 Dynamic Programming 이라는 섹션에 어떤식으로 풀어야 되는지 표시가 되어 있다.

풀이과정

[초기값]

8 5 9 3
2 4 6
7 4
3

[가공값]

  1. 8+2 와 5+2 를 비교하여 큰값을 2행 1열(2)위치에 입력
  2. 5+4 와 9+4 를 비교하여 큰값을 2행 2열(4)위치에 입력
  3. 9+6 과 3+6 을 비교하여 큰값을 2행 3열(6)위치에 입력
  4. 1~3의 스텝을 반복한다.

[소스코드]

import unittest


class TestMaximumPathSumClass(unittest.TestCase):

    def testExample(self):
        input_str = '''
                    3
                    7 4
                    2 4 6
                    8 5 9 3'''
        value = self.maximum_path_sum(input_str)
        self.assertEqual(value, 23)

    def testPE67(self):
        f = open("/Users/p/Downloads/p067_triangle.txt")
        lines = f.readlines()
        value = self.maximum_path_sum(''.join(lines))
        print(value)
        f.close()

    def testPE18(self):
        input_str = '''
                    75
                    95 64
                    17 47 82
                    18 35 87 10
                    20 04 82 47 65
                    19 01 23 75 03 34
                    88 02 77 73 07 63 67
                    99 65 04 28 06 16 70 92
                    41 41 26 56 83 40 80 70 33
                    41 48 72 33 47 32 37 16 94 29
                    53 71 44 65 25 43 91 52 97 51 14
                    70 11 33 28 77 73 17 78 39 68 17 57
                    91 71 52 38 17 14 91 43 58 50 27 29 48
                    63 66 04 68 89 53 67 30 73 16 69 87 40 31
                    04 62 98 27 23 09 70 98 73 93 38 53 60 04 23'''
        value = self.maximum_path_sum(input_str)
        print("Maximum path sum = ", value)

    def maximum_path_sum(self, input_str):
        input_str = input_str.strip()
        lines = input_str.split('n')
        array = []
        for line in lines:
            if len(line) == 0:
                continue
            nums_array = line.strip().split(" ")
            array.insert(0, nums_array)

        for i in range(0, len(array) - 1):
            nums_array = array[i]
            changed_array = []
            for j in range(0, len(nums_array)-1):
                v1 = int(array[i][j]) + int(array[i+1][j])
                v2 = int(array[i][j+1]) + int(array[i+1][j])
                changed_array.append(max(v1, v2))
            array[i+1] = changed_array
            print(changed_array)

        return array[len(array)-1][0]

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestMaximumPathSumClass)
    unittest.TextTestRunner(verbosity=2).run(suite)

[Python] 53_combinatoric_selections

문제링크

문제풀이

  1. 조합을 구하는 함수를 정의한다
  2. 팩토리얼을 구하는 함수를 정의한다. (팩토리얼을 lambda를 이용한다)
  3. 조합의 공식에 따라 구해진 값이 1,000,000이 넘는 값을 카운팅 한다.
import unittest
import functools


class TestCombination(unittest.TestCase):

    def testCombination(self):
        value = self.combination(5, 3)
        self.assertEqual(value, 10)

        value = self.combination(23, 10)
        self.assertEqual(value, 1144066)

    def combination(self, a, b):
        v1 = self.fact(a)
        v2 = (a == b and 1 or (self.fact(b) * (self.fact(a - b))))
        return v1 / v2

    def fact(self, a):
        if a == 0:
            return 0
        fact_value = functools.reduce(lambda x, y: x * y, range(1, a + 1))
        return fact_value

    def testOverMillionCount(self):
        count = 0
        for i in range(1, 101):
            for j in range(1, i):
                combi_value = self.combination(i, j)
                if combi_value > 1000000:
                    # print("%d, %d, combi_value=%d" % (i, j, combi_value))
                    count += 1
        print("Over 1million counts = ", count)

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestCombination)
    unittest.TextTestRunner(verbosity=2).run(suite)

[Python] 56-Powerful digit sum

A googol (10100) is a massive number: one followed by one-hundred zeros; 100100 is almost unimaginably large: one followed by two-hundred zeros. Despite their size, the sum of the digits in each number is only 1.

Considering natural numbers of the form, ab, where a, b < 100, what is the maximum digital sum?


문제 해결 전략

  1. 제곱을 문자열로 변환하여 문자열을 한자씩 더해 간다.
  2. 문자열을 더하기 위해서 reduce 와 lambda를 활용한다.
def sumOfDigit(i, j):
  powValue = str(i**j)
  result = reduce(lambda x, y: int(x)+int(y), powValue)
  return int(result)


if __name__ == '__main__':
  maxValue = iVal = jVal = 0    
  for i in range(1, 101):      
    for j in range(1, 101):        
      result = sumOfDigit(i, j)
      if (result > maxValue):          
        maxValue, iVal, jVal = result, i, j          
  print "i=%d, j=%d, maximum=%d" % (iVal, jVal, maxValue)

PythonMagick과 PIL을 이용한 PDF에서 이미지 추출

테스트 환경

  • 운영체제: Windows 7 64Bit
  • PythonVersion: 2.7

ImageMagick 설치

  1. ImageMagick 다운로드 [링크]
  2. ImageMagick 설치
  3. 중요 환경 변수 등록 (IMAGEMAGICK_HOME)

PythonMagick 설치

PIP 또는 easy_install 을 이용하여 설치 할 수 없기 때문에 수동으로 설치를 해야 하는 부분이 있습니다.

  1. PythonMagick‑0.9.10‑cp27‑none‑win32.whl 파일 다운로드 [링크] (운영체제가 64Bit여도 32Bit 파일을 다운로드)
  2. pip 를 이용하여 설치
C:UserscoozplzDownloads>pip install PythonMagick-0.9.10-cp27-none-win32.whl

테스트
파이썬 명령 프롬프트에서 import를 했을때 Module Not Found 가 표시되지 않으면 정상적으로 설치된 것입니다.

>>> import PythonMagick

GhostScript 설치

GhostScript가 없는 경우 Windows에서 실행하면 파일의 저장경로를 찾을 수 없다는 오류가 발생됩니다.

  1. GhostScript 32Bit 다운로드 [링크] (운영체제가 64Bit여도 32Bit 파일을 다운로드)
  2. GhostScript 설치
  3. 환경변수 등록 (GHOSTSCRIPT_HOME)

PIL 설치

> easy_install PIL

테스트
파이썬 명령 프롬프트에서 import를 했을때 Module Not Found 가 표시되지 않으면 정상적으로 설치된 것입니다.

>>> import Image

소스

import PythonMagick
import Image
import time

def loadPDFImage(pdfPath, outputFile):
    """
    PDF 파일을 로딩하여 이미지 파일로 저장한다.
    :param pdfPath  PDF 파일 경로
    :param outputFile   추출한 이미지 저장 경로
    """
    pdfImage = PythonMagick.Image()
    pdfImage.density("300")
    pdfImage.read(pdfPath)
    pdfImage.write(outputFile)


def splitImage(imageFileName, splittedImageSavingDir):
    """
    이미지 파일을 원하는 크기로 Split한 후 저장한다.
    :param imageFileName    원본 이미지의 경로
    :param splittedImageSavingDir   잘린 이미지를 저장할 상위 디렉토리
    """
    loadedImage = Image.open(imageFileName)
    for i in range(3):
        left = 256 + (952 * i) + (15 * i)
        right = 1212 + (952 * i) + (15 * i)
        cropImage = loadedImage.crop((left, 278, right, 1800))
        savingFileName = "%s_%d.jpg" % (time.strftime('%Y%m%d%H%M'), i)
        cropImage.save("%s/%s" % (splittedImageSavingDir, savingFileName))
        print "Successfully saved, %s" % savingFileName


if __name__ == '__main__':
    pdfPath = "D:/test.pdf"
    outputPath = "D:/test.jpg"
    splittedImageSavingDir = "D:/"
    loadPDFImage(pdfPath, outputPath)
    splitImage(outputPath, splittedImageSavingDir)

결과

원본 PDF
ORIGIN_IMAGE

잘린 이미지
SPLIT_IMAGE{max-width:320px}

Python 스크립트파일을 Exe로 변경

Install py2exe

> pip install py2exe

실행 스크립트

#execute_test.py
print 'HelloWorld'

Setup.py 스크립트

#setup.py
from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

options = {
    "bundle_files": 1,                    # create singlefile exe
    "compressed"  : 1,                    # compress the library archive
    "excludes"    : ["w9xpopen.exe"]    # we don't need this
}

setup(
    options = {'py2exe' : options},
    windows = [{'script': "merge_swf_helper.py"}],
    zipfile = None,
)

Cmd 창에서 빌드 명령 실행

> python setup.py install

결과 확인

명령을 실행한 폴더의 dist 디렉토리에 들어가면 생성된 exe 파일을 볼 수 있다.