반응형

Python3 os.path 모듈

작성하게 된 계기

C/C++ 개발자 출신 중 일부는 파일관리를 할 경우 바퀴의 재발명을 하는 경우가 많다. 물론 boost나 표준에 대해서 잘 알고 있다면 문제가 전혀 없다. 특히나 OS 크로스 플랫폼이 대세인 요즘에 OS에 따라서 (사실은 윈도우 때문에) file Path 표기법을 다르게 사용하는 문제는 어렵지는 않지만, 상당히 귀찮고 은근히 실수가 많은 분야이다. 그래서 요즘 대부분의 프로그래밍 언어들은 이러한 모듈 혹은 라이브러리를 제공을 하고 있다. 다만, 종종 이를 모르는 초보 및 현업에서 잠시 쉬신 분일 경우 모르는 경우가 있어서 기록을 남긴다. 다만, 여기는 자주 사용하는 내용만 적은 것이므로 자신이 익숙하다면 가능하면 레퍼런스를 보는 것이 좋다.

1. os.path 모듈 : 문자열 기반

내장 모듈로 경로를 다룰때 사용을 한다. 항상 파일관리 모듈을 만들경우 자주 사용하게 되는 것들을 아예 모아놓았다. 어쩌면, 경험적인 모듈이라고 볼 수 있다.

os.path.dirname

입력 받은 경로명에서 폴더(원래는 디렉토리가 표준이지만, 단어가 길어서 여기서는 편의상 폴더로 지칭함)만 출력을 해준다. 보통 파일 경로를 저장하고 있는 상태에서 폴더 경로만 알고 싶을때 많이 사용한다. 프로그램에서 파일을 관리하는 모듈을 작성할 경우 사용하기에 유용한 기능이다. 동작은 문자열 기반이다.

예시)

>>>import os
>>>os.path.dirname('/hello/world/tmp.txt')
'/hello/world'

os.path.isdir, os.path.isfile

입력 받은 경로명이 isdir의 경우 폴더이면, True이고 그외는 False를 반환하고 isfile의 경우 파일이면, True 그외는 False를 반환한다. 입력받은 문자열 기반으로 검사한다.

예시)

>>>import os
>>>os.path.isdir('C:\\hello\\world\\tmp.txt')
False
>>>os.path.isdir('C:\\hello\\world')
True
>>>os.path.isfile('C:\\hello\\world\\tmp.txt')
True
>>>os.path.isfile('C:\\hello\\world')
False

os.path.join

절대 경로와 상대경로를 조합할 경우 자주 사용하게 된다. 만약 자신이 만든 프로그램이 프로젝트 단위로 파일을 관리할 경우 프로젝트의 상위 폴더명에서 하위로 폴더를 새로 만들고 관리를 해 갈 경우에 매우 유용하다. 특이한 점은 첫 입력인자 이후 절대경로가 나오게 되면, 앞의 입력 인자로 인해 형성된 경로가 나중에 입력인자로 받은 절대경로로 초기화 되어버린다.

예시)

>>>import os
>>>os.path.join('C:\\hello\\home', 'world')
'C:\\hello\\home\\world'
>>>os.path.join('C:\\hello\\home', 'world', 'tmp.txt')
'C:\\hello\\home\\world\\tmp.txt'
>>>os.path.join('C:\\hello\\home', 'world', 'D:\\hello, 'tmp.txt')
'D:\\hello\\tmp.txt'

os.path.normcase

현재 운영체제에 맞게 경로 문자열을 정규화(Normalize)를 한다. 파이썬으로 다른 외부 모듈을 사용하다 보면 폴더의 구분자를 '/'로만 사용하는 경우가 있기 때문이다. 필자가 겪은 바로는 GUI 모듈에서 종종 그런 경우가 있다. 이 경우 해당 메서드를 사용하면 간단히 해결 된다. 대부분 윈도우 운영체제에서 사용하게 된다.

예시)

# 윈도우일 경우
>>>import os
>>>os.path.normcase('C:/hello/world')
'C:\\hello\\world'

os.path.split

내장 자료형인 str.split과 비슷하게 보이지만, 다르다. 입력받은 경로의 가장 뒷 부분에서 하나를 분리하여 2개의 string을 반환 한다. 작업중인 폴더에서 한 단계 상위 폴더 경로를 얻고 싶거나 파일경로에서 폴더 경로를 분리할 때 사용하면 유용하다.문자열 기반으로 동작을 한다.

예시)

>>>import os
# 유닉스 계열 운영체제의 경우(경로 표기가 간단해서 필자는 예시로 자주 들음)
>>>os.path.split('/hello/world/myhome')
('/hello/world', 'myhome')
>>>os.path.split('/hello/world/myhome.txt')
('/hello/world', 'myhome.txt')

# 폴더 표기를 잘못한 경우
>>>os.path.split('/hello/world/myhome/')
('/hello/world/myhome', '')

os.path.splitext

이름 그대로 확장자 부분을 분리하여 반환을 한다. 두번째 반환하는 인자가 확장자이다. 문자열 기반으로 작동을 한다. 때문에 확장자를 구분하는 .이 없을 경우에는 ''(빈)문자열를 반환한다.

예시)

>>>import os
>>>os.path.splitext('/hello/world/myhome.txt')
('/hello/world/myhome', '.txt')

# 확장자가 없는 경우
>>>os.path.splitext('/hello/world/myhome')
('/hello/world/myhome', '')

2. os.path 모듈 : 기능 기반

앞의 기능들은 대부분 문자열 기반이고 그외에 해당 경로의 파일 존재 여부나 파일 크기와 같은 것은

os.path.getctime, os.path.getmtime, os.path.getatime

윈도우에서 파일의 속성창을 열면 보이는 생성된 시각, 마지막 수정된 시각, 마지막 실행한 시각 순으로 값이 반환이 된다. 다만, os.path.getctime 의 경우 유닉스 계열 운영체제 중에서는 수정된 시각을 반환하는 경우가 있다. 반환된 시각의 단위는 초(sec) 이지만, 정수형이 아닌 실수로 표기한다.

파일 기본 속성은 파일을 열어야 알 수 있기 때문에 유닉스 계열의 경우 읽기 권한이 없는 경우 os.error를 발생 시킨다. 예외 처리를 잘 해주자.

os.path.getsize

입력인자로 받은 경로의 파일의 크기를 바이트로 반환을 해준다. 운영체제단에서 파일 크기를 알기위해서는 파일시스템에서 파일을 열어봐야 하므로 읽기 권한이 없으면, 파일을 열지 못하므로 os.error를 발생한다. 예외 처리를 잘 해주자.

참고자료

python3 공식 문서(영문)
국내 블로그 글

반응형
반응형

Python3 not의 코드 스타일

작성 계기

필자는 C/C++/C#을 주로 접한다음에 Python 을 접했기 때문에 해당 언어들은 관례상 not 연산자 !을 주로 앞에 쓰는 경우가 있다. 이유는 !는 눈에 비교적 잘 보이기 때문에 가독성을 위해서 그렇게 쓰는 버릇이 있기 때문이다. 하자만, 파이썬에서의 경우는 not 이라는 키워드를 직접 입력하기 때문에 C/C++/C#의 스타일과 다소 차이가 있다. 다만, 워낙 친인간적인 언어다 보니까 영문법과 같이 사용하는 것을 권장한다.

not의 코딩 스타일

다음은 코딩 스타일 비교이다. 결과적으로는 둘다 같은 결과를 얻을 수 있다.

전통적인 스타일

예시)

>>>tmpNum = 1
>>>not type(tmpNum) is str
True
>>>not type(tmpNum) is int
False

구글 코딩 스타일

예시)

>>>tmpNum = 1
>>>type(tmpNum) is not str
True
>>>type(tmpNum) is not int
False

어떤 방식이 좋은가?

두 예시에서 보듯이 결과적으로는 같기 때문에 사실은 상관이 없다. 하지만, 구글 코딩 스타일을 더 권장을 하는데, 이유는 앞에 괄호 없이 not이 있다보면, 가독상 사람입장에서는 (not type(tmpNum)) is str 으로 읽은 가능성이 있고, 경우에 따라서 잘못 의미를 해석할 수 있기 때문이다. 그밖에 성능상에서도 큰 차이는 없다.

반응형
반응형

Python3 : 삼항연산자(Ternary Operators)

작성한 계기

C를 먼저 익힌 개발자라면 3상연산자는 라인수는 적으면서 간단하게 조건문을 사용할 경우에 많이 사용한다. 다만, 파이썬에서는 전통적인 삼항연사자와 다르게 표현이 되어서 당황했었다. 그래서 기록으로 남긴다.

전통적인 삼항연산자

전통적으로 C/C++/C#과 같은 언어에서는 ? 기호를 삼항식으로 사용해왔다.

예시)

#include <stdio.h>

void TwoMultiple(const int num)
{
    printf("%d is %s\n", num, (num % 2 ? "even" : "odd"));
}

int main(const int argc, const char* argv[])
{
    TwoMultiple(1);
    // 1 is odd
    TwoMultiple(2);
    // 2 is even
    return 0;
}

화면 출력 코드가 길어서 코드가 길어지지만, 삼항식자체는 짧다.

파이썬의 삼항연산자

파이썬에서 삼항연산자는 처음부터 있던 것은 아니고 요구에 의해서 생기게 되었는데, 기존의 전통적인 방식과 많이 다르기에 많은 고심이 있던 것으로 생각된다. 간결한 기호를 사용하지 않고 기존의 if/else문을 한줄로 표현하는 방식을 사용하고 있다. if키워드 앞에 오는 값은 참(True)일때, else 다음에 오는 것은 거짓(False)일때 수행을 하게 된다. 그리고 if와 else 사이에는 조건문이 삽입되어 있는 구조이다.
예시)

def twoMultiple(num):
    resultStr = str(num) + ' is ' + ('odd' if num % 2 else 'even')
    print(resultStr)

twoMultiple(1)
# 1 is odd
twoMultiple(2)
# 2 is even

이전의 전통적인 삼항연산자보다는 좀 더 친 인간적인(?) 문법이 되었다. 그러나 대신 전통적인 삼항연산자 보다는 길어진 느낌이 있다. 또, 파이썬의 들여쓰기를 통한 scope를 구분한다는 효과와 함께 삼항연산자는 C/C++ 만큼 자주 사용하지 않을 것으로 보인다. 그리고 이 삼항연산자 패턴은 for문을 이용한 자료형 변경하는 패턴에서도 볼 수 있다.

삼항연산자를 보면서 느낀점

대부분의 프로그래밍 언어도 그렇지만, 활발하게 필요한 기능이 있다면 추가가 되고 있다. 다만 파이썬에서 전통적인 문법과 다른 것을 볼 때 마다 느끼는 것이 기능을 바로 추가 하지 않고 좀 더 나은 방법이 있는지 고민하면서 추가를 한다는 느낌을 받았다.

참조 자료

python 계단 밟기

반응형
반응형

Python3 타입검사(Type Check)

타입에 필자 생각

C/C++ 에서 주로 개발을 한 사람(필자의 경우) 입장에서는 자바스크립트나 파이썬처럼 변수(라고 쓰고 객체라고 읽고 쓰더라)의 형이 자유로운 경우 형이 바뀐 경우 문법상 문제가 없기 때문에 잘못된 변수 사용하는 것에 걱정을 한다. 그리고 결국 컴퓨터에서 동작하기 때문에 변수는 자유롭게 받는 것에 비해 타입 에러도 있다. 때문에 몇몇 유명한 개발자는 파이썬을 안좋게 본다. 그러나 이런 관점과 요구사항은 항상 개선책이 나오는 원동력이 되는 것 같다. 파이썬도 타입검사 메서드가 제공되면서 C++ 스타일의 코딩이 가능하기 때문이다.

type() vs isInstance()

입문자를 위한 서적에서는 대부분 type() 메서드를 잠시 소개했던 것으로 기억한다. 아마 isInstance()도 소개를 한다면, 시대가 많이 바뀌었거나 해당 입문서가 수준이 높다고 생각해야 한다.

type()

type() 메서드의 경우 입문서에서 소개한 것과 같이 파이썬에서 기본적으로 제공하는 자료형에 대해서 구분이 가능하다.

예시)

type(1) is int
# True
type([]) is list
# True
a = 1
b = 3
type(a) is type(b)
# True

그러나 이 type()의 한계는 class의 인스턴스의 경우 해당되는 클래스의 인스턴스인지만 확인을 한다. C++ 처럼 상속의 경우는 고려가 되지 않아서 상속받은 클래스의 인스턴스를 알아 볼 수 없다.

예시)

class Test1:
    pass
class Test2(Test1):
    pass

a = Test1()
b = Test2()
type(a) is Test1
# True
type(b) is Test2
# True
type(b) is Test1
# False

isInstance()

type()의 한계점을 해결해주는 것이 isInstance() 메서드이다. 개발자가 임으로 만든 class의 인스턴스의 특정 클래스인지 검사할 경우 자식 클래스의 인스턴스도 True로 리턴을 해준다. 때문에 개발자는 구현을 하면서 타입에 느슨한 연결을 구현을 좀 더 안전하게 할 수 있다.

예시)

class Test1:
    pass
class Test2(Test1):
    pass

a = Test1()
b = Test2()
isInstance(a, Test1)
# True
isInstance(b, Test2)
# True
isInstance(b, Test1)
# True

추가로 isInstance()는 튜플을 허용된다.

예시) unicode str 검사 방법 둘다 basestring 의 subclass임을 이용하는 방법

tmpStr = 'hello'
isInstance(tmpStr, (str, unicode))

무엇을 사용해야 하는가?

type()과 isInstance() 각각 특징이 있는 것이지 장단점이 있는 것이 아니기 때문에 적절히 활용하는 것이 좋다. 두 메서드를 적절히 사용하여 subclass를 확인 하는 방법도 있기 때문이다.

참조 자료

스택오브플러워

해시코드

반응형
반응형

PyQt5 Desiginer 활용

계기

프로젝트에서 PyQt를 사용하게 되면서 알게 된 것들을 정리하게 된 것이다. 문제는 한꺼번에 정리하느라 부담이 되고 있다. 필자에게는 익숙한 Tkinter를 사용 안하고 PyQt를 사용하게 된 결정적인 이유는 이러한 툴을 사용하여 생산성을 높일 수 있기 때문이다. PyQt Desiginer 역시 기존 QMaker를 Python에서 사용할 수 있도록 만든 도구이다.

ui 디자이너 툴

활용 방법

기본적으로 desiginer는 xml 포멧으로 *.ui 형태의 파일로 저장이 된다. 이 파일을 python에서 실행하기 위해서는 2가지 방법이 있다.

  1. *.py 파일로 변환하는 방법.
  2. 둘째는 ui를 python에서 클래스로 읽어서 인스턴스를 만들는 방법

필자 경험으로는 생산성 측면으로 보면은 사실 두번째 방법이 가장 좋다. 그러나 아직 컴포넌트에 대해서 잘 모르거나 입문 단계에 있을 경우에는 첫번째 방법을 사용하는 것이 학습에는 더 좋은 것으로 생각된다.

디자이너에서 예시 만들기

위지윅스(WYSIWYG)는 마우스로 컴포넌트를 드래그 드랍으로 디자인해서 보이는대로 실행되는 것을 의미한다. 필자 기억으로는 과거 MFC전성기 시절과 비주얼 베이직이 위지윅스로 인기와 욕을 같이 먹었었다는 것으로 알고 있다. 프로젝트로 나가보면 핵심로직은 대부분 코드라서 고객이 별로 딴지는 안걸지만(알면 클라이언트가 직접 코딩?), GUI 같은 눈에 보이는 것은 심할 경우 색상까지 잦은 수정을 요청 하는 경우가 있기 때문에 이런 기능은 빠른 대응이 가능해서 생상성 측면에서 좋은 기능이다.

pyqt desiginer 첫 화면

우선 시작화면서에서 Dialog without buttons 로 생성을 한다음에 새로 생성된 창이 이제 디자인할 창이다. 기본적인 화면 배치는 좌측에 컴포넌트들이 있고, 우측 상단의 Object Inspector는 해당 창의 객들간의 관계를 트리(Tree)구조로 보여준다. 그리고 우측 중단에는 상단 혹은 화면에서 선택된 디자인중인(혹은 선택된) 창의 속성편집창(Property Editor)이 있다.

dialog 편집장

위젯박스에서 라벨(Label)을 드래그해서 다이얼로그 창에 올린다음에 그리고 객체 트리창에서 다이얼로그를 선택한다음에 상단의 도구메뉴 중에 9개의 작은 박스가 그려진 버튼을 클릭을 한다. 그러면 라벨이 창의 크기에 맞게 늘어나는 것을 확인 할 수 있는데, 이것이 레이아웃 정렬로 수직, 수평, 행렬 이 3가지 방식이 자주 사용된다. GUI 프로그램에서 컴포넌트들을 정렬을 할 수 있는 것은 상당한 이점이다. 만약 이 기능이 없다면, 원래 개발자가 직접 좌표를 동적으로 변동되도록 구현을 해야 한다.

Label 수정

늘어난 TextlLabel을 더블클릭 혹은 선택한 상태에서 속성창의 text 항목을 'Hello World'라고 입력을 한다. 속성창을 본김에 font size도 변경을 해보자. 그리고 잠시 Ctrl + R 키를 눌러서 미리 보기를 한다. 창크기를 변경해보자 창크기에 따라 클자크기도 변경되는 것을 볼 수 있다. 저장을 하면 ui 파일로 저장할 수 있는 것을 확인할 수 있다.

미리보기

이제 저장을 한다. 저장된 ui 파일이 xml 형식으로 저장된것을 편지기로 열어보면 확인 할 수 있다.

xml형식의 ui 파일

py 파일로 변환하여 실행

윈도우의 경우 cmd 나 powershell 을 열고, 그외는 터미널에서 ui 파일을 저장한 경로로 이동해서 다음과 같은 명령어를 입력한다.

python -m PyQt5.uic.pyuic -x hello.ui -o hello.py

명령어의 의미는 대략 python에서 PyQt5.uic.pyuic 라는 모듈을 hello.ui를 실행해서 hello.py라는 파일로 출력하라는 의미이다. 여기서 출력된 파일은 각각 독자적으로 바로 실행이 가능하다. 출력된 소스 코드를 수정하여 원하는 GUI로 만들어도 된다. 디자이너에서 사용하는 컴포넌트가 어떻게 코드로 작성하는지 궁금하면 이런 방식으로 확인을 해도 괜찮다. 다만, 인스턴스의 속성은 디자이너에서의 속성창과 이름이 대부분 같다.

ui 파일을 py로 변환

ui 파일을 클래스로 읽어서 실행

ui 파일을 클래스로 읽는 방법은 PyQt5의 uic 모듈을 사용해서 클래스로 읽는 방식이다.

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic

ui_helloclass = uic.loadUiType('hello.ui')[0]
class DlgHello(QDialog, ui_helloclass):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    dlgHello = DlgHello()
    dlgHello.show()
    app.exec_()

위의 코드에서 다중상속을 받는데, 그 이유는 py로 컨버팅한 것에서 확인하면 ui로 생성되는 클래스의 자신은 object 인스턴스인데, setupUi() 메서드를 실행하기 위해서는 QtCore나 QtWidgets 혹은 이것이 부모인 인스턴스만 setupUi()메서드에 인자로 넘겨줄 수 있기 때문에 다중으로 한 것이다. 개발자 성향에 따라 이와 조금 다른 스타일로 코딩하는 것이 어느정도 가능하다.

이 방식의 경우 기존의 ui 파일을 수정하지 않고 바로 클래스로 읽어서 상속뒤에 기능을 붙이는 방식이기 때문에 후에 디자이너에서 컴포넌트 객체 명을 바꾸지 않는다면 GUI를 거의 따로 관리할 수 있게 된다. 물론 앞에서 생성된 py 파일도 따로 관리하면 동일한 효과를 볼 수 있지만, 변경될 때마다 변환시켜줘야 한다는 번거로움이 있다.

참고자료

위키독. 파이썬으로 배우는 알고리즘 트레이닝(py변환)
위키독. 파이썬으로 배우는 알고리즘 트레이닝(ui로드)

반응형

'Python > PyQt5' 카테고리의 다른 글

[Python, GUI]PyQt5 개요  (0) 2019.04.19
반응형

Python3 str(문자열)의 편리한 기능들

작성 계기

C/C++을 사용하던 시작부터 프로그래머들 사이에서 유행한 말이 있었는데, 그것은 문자열 처리를 잘하는 프로그래머는 웬만한 프로그램을 거의다 해결할 수 있다는 말이었다. (하지만 영상처리를 해보면 어떨까?) 역시 기본에서 다루는 내용보다는 필자가 실제 프로그램을 작성하면서 유용했던 기능들 중심으로 정리를 한다.

str 자료형에 대해

C++ STL에서는 string 이라는 표준 클래스가 존재한다. 마찬가지로 python에서는 str 이라는 자료구조가 있다. 문장을 구성할때 문자 여러개가 모여서 구성을 하는 것이다. C/C++ 시절에는 사실상 문자의 배열로 운영이 되었기 때문에 사실 다루기 상당히 까다롭다. 하지만 수십년간의 프로그래머들의 경험에 의해서 문자 하나보다는 문장단위로 다루는 일이 많은 것을 겪어왔다. 그래서, C#, javascript, python 도 대부분 string 혹은 str 형을 기본적으로 제공하고 있다.

기본적으로 list 자료형과 비슷하지만 다르다. 이는 문자열을 다룰 필요한 메서드와 list 같은 배열형 자료를 다룰때 필요한 메서드에서 차이가 있기 때문이다. 사실 str의 경우 대부분 언어들에서는 비슷하게 지원을 해서 꼭 Python 만의 특징이라고 보기는 어렵다.

python str 자료형의 특징

문자열 비교

C/C++을 주로 사용한 사람이라면은 == 연산을 문자열에 바로 사용을 하면 기겁을 하게 될 것이다. 하지만, Python의 str 자료형은 사용해도 큰 문제가 없다. 이 기능이 워낙 강력하다 보니 오히려 enum 이라는 자료형을 잘 사용하지 않게 된다. python3에서 enum 자료형이 등장하게 된것은 3.5 버전 부터이고, 사용방법도 enum 내장 모듈을 class로 상속해서 사용을 하여 enum을 만들어서 사용하는 것 보다 문자열을 사용하는 것이 나을 수 도 있다. 하지만 IDLE의 인텔리전트 기능을 사용하기 위해서라면 enum을 사용하는 것이 더 편리하고 안전할 것이다.

예시)

'hello' == 'hello'
# True
'hello' == 'world'
# False

split() 특정 문자로 나누기

사실 문자열에서 특정 문자나 기호를 기준으로 정보를 나누는 것은 문자열을 다룰때 많이 다루게 된다. 대부분 프로그램들이 최소한 데이터를 다룰때 DBMA를 사용하지 않는 경우 바로 직접 파일을 다루는데, 이 때에 각 운영체제에서 파일의 경로를 '' 이나 '/' 을 사용하기 때문이다. 물론 현재는 크로스 플랫폼 이슈로 인해서 대부분 언어들은 파일경로를 다루는 모듈이 있다(C++의 경우 C++17부터 있다).
특정 문자로 나누는 메서드는 split()메서드이며, 첫번째 인자로 받은 문자을 기준으로 리스트형에 나눈 문자열들을 담아서 반환을 한다. 두번째 인자로 숫자가 들어갈 경우 입력받은 숫자만큼 첫번째로 입력 받은 문자열로 리스트에 나누어서 담은뒤 반환을 한다. 이 메서드는 웬만한 문자열을 다루는 프로그래밍 언어들에서 공통적으로 거의 있다.

예시)

'c\python3\hello'.split('\\')
# ['c', 'python3', 'hello']
'c\python3\hello'.split('\\', 1)
# ['c', 'python3\hello']

strip() 문자열의 양쪽에 특정 문자 제거

약간의 규모가 있는 프로그램을 작성하다 보면 설정값을 파일에 저장을 하고 이를 읽어서 사용하는 경우가 있는데, 이 경우 이 설정값이 있는 파일을 프로그램을 통해서만 건들면 되는데, 간혹 프로젝트 사정상 사용자가 옵션 파일을 건들여야 하는 경우가 있다. 특히 공백을 기준으로 문자열을 나누다 보면은 앞쪽이나 뒷쪽에 공백문이 저장되어 있는 경우가 발생된다. 이 경우 split() 메서드를 바로 사용하게 되면, 공백수 만큼 리스트의 길이가 생성된 것을 볼 수 있다.

물론 이를 제거하는 알고리즘을 구현하면 되지만 이런 경우가 생각보다 많다 보니 Python 에서는 아예 이러한 메서드를 제공한다. 단순히 strip()를 호출하면 문자열의 양끝단의 공백문을 제거하고 인자를 넣을 경우 해당 인자가 양끝에 있는 경우를 제거한다.

예시)

' hello world   '.strip()
# 'hello world'
'c:\python\hello\\'.strip('\\')
# 'c:\\python\\hello'

join() 문자열이 모인 리스트를 한 문자열로 만들기

split()과 반대 개념의 메서드로 join()을 호출한 문자열을 인자로 받는 리스트의 문자열들의 사이 사이에 넣어서 하나의 문자열을 반환을 한다. 여기서 사용되는 리스트의 원소는 모두다 str 자료형이어야 하는 제약이 있다(만약 이를 무시하면 에러메시지를 발생하면 죽는 프로그램을 볼 수 있다).

필자의 경우 파일에서 ','로 구분하는 문자열을 만들어야 할 때 많이 사용하였었다. 프로그램에서는 리스트에 숫치값을 넣어서 사용하다가 저장할때는 숫자가 아닌 문자열로 변환해서 저장하는 경우에 유용했다.

예시)

a = ['1', '2', '3', '4', '5']
aStr = ', '.join(a)
# aStr = '1, 2, 3, 4, 5'

보너스: 숫자 있는 리스트를 문자열형 리스트로 바꾸기

어떤 수치 데이터를 문자열로 변환하는 작업은 단순 반복 작업이다. 다행히 python에서는 이러한 단순 반복 작업을 간단하게 코드로 작성할 수 있는 문법적 특성이 존재한다.

예시)

a = [1, 2, 3, 4, 5]
aStrList = [str(it) for it in a]
# aStrList = ['1', '2', '3', '4', '5']

이렇게 join 메서드를 조합하면 단 2줄로 수치가 들어 있는 리스트를 하나의 문자열로 변환하는 것이 가능해진다.

문자열의 곱연산

리스트와 같은 기능으로 문자열로 곱연산이 가능하다. 콘솔용 프로그램을 만들 경우 구분 선을 사용할때 쉽게 사용하기도 한다.

예시)

a = '-'*80
# a = '--------------------------------------------------------------------------------'

format() 문자열 포맷

C 언어를 먼저 배울경우 printf() 함수를 써본적이 있을 것이다. 여기서 f의 의미는 format 이라는 의미이다. 실제로 문자열을 다루다 보면은 포멧이 있는 문자열을 작성하는 경우가 많다. 따라서 python도 str 자료형 자체에 format() 메서드를 지원한다. 다만, 이 메서드는 생긴지 얼마 안되었기 때문에 오래전에 구매한 기본서라면 format() 대신 % 기호를 이용해서 같은 비슷한 기능 사용할 수 있다. 하지만 가독성등 여러 이유로 가능하면 format() 메서드를 사용하기를 권장한다.

필자의 경우 프로그램에서 로그를 따로 저장할 경우 저장할 문자열 생성시 사용하기에 용이 했었다.

예시)

talk1 = 'hello, {}!'.format('lemi')
# talk1 = 'hello, lemi!'

in 포함 문자열 여부

C#의 contain()과 같은 역할을 하는 메서드로 문법상 굉장히 직관적이다. 예시로 이해하는 것이 매우 직관적이다.

예시)

'h' in 'hello'
# True
' ' in 'hello'
# False

find() 문자열 찾기

다른 프로그래밍 언어들에게 공통적으로 있는 것으로 처음으로 같은 문자열이 있는 index를 number(int)형으로 반환을 한다. 만약 없을 경우 -1을 반환한다. 인자는 단일 문자 혹은 문자열 전부 사용할 수 있다. 이 메서드로 특정 문자열 포함 여부도 확인이 가능하기 때문에 in 문법을 모를 경우 사용하게 된다.

하지만, find()로 포함 여부를 할 경우 이 의도를 주석으로 기록해주어야 하지만, 앞의 in의 문법을 사용하면 굳이 주석 없이 코드만으로 의도를 파악할 수 있으므로 포함 여부만 확인 할경우 find()보다는 in을 사용하는 것이 더 좋다.

예시)

index = 'hello'.find('l')
# index = 2
index = 'hello'.find(' ')
# index = -1

upper(), lower() 대소문자 변환

호출한 문자열을 upper()의 경우 대문자로 lower()는 소문자로 전부 변환하여 반환한다. 많이 쓰이는 기능은 아니지만, 검색 기능을 구현할 경우 대소문자 구분을 안 할 경우 사용시 편리하다. 그중에서도 가능하면 lower()를 많이 사용하는 편이다.

예시)

lowStr = 'hello'
upStr = lowStr.upper()
# lowStr = 'hello'
# upStr = 'HELLO'

기타 문자열을 다루는 더 강력한 방법

문자열로 부터 특정한 패턴의 의미있는 자료를 얻기 위해서는 정규표현식을 사용하는 것이 가장 효과적이다. 다만, 정규식을 사용하기 전에 간단한 문자열을 전처리과정으로 정리할 경우에는 가능하면 문자열에서 제공하는 메서드를 활용하는 것이 좋다.

반응형

'Python > Python3' 카테고리의 다른 글

[Python3]삼항연산자(Ternary operators)  (0) 2019.04.30
[python3]타입검사(Type Check)  (0) 2019.04.23
[Python3]List의 편리한 기능들  (0) 2019.04.19
[python]CSV 데이터 포멧 입출력  (0) 2018.10.22
[python]기본 Shell 활용  (0) 2018.10.20
반응형

Python3 List의 편리한 기능들

작성 계기

잠시 Python을 사용해본적은 있지만, 최근 프로젝트를 아예 Python을 사용하기 시작하면서 기존의 C++의 STL에서의 Vector와 많은 부부니 비교가 되었다. 특히, 알았을때와 몰랐을때의 생산성의 차이를 많이 느끼게 되었기 때문에 기록겸 정리를 해 놓았다. 본 내용들은 기본서에서는 잘 다루지는 않는 내용이지만, 그렇다고 어려운 것은 아니다.

List의 구조

기본적으로 C++ STL의 Vector와 거의 비슷한다. 배열처럼 사용이 가능하며, 동적으로 길이를 늘리고 줄일 수 가 있다. 하지만, 경험에 의한 것인지 좀 더 편리한 기능들이 많이 있다. 그리고 정적 언어와 달리 List는 특정한 자료형을 구분 하지 않고 담을 수가 있다. 물론 C++에서도 포인터를 이용하면 구현을 할 수 있겠지만, 별로 추천하는 방법은 아니다.

Python의 List의 특징

여기서는 주로 다른 프로그램 언어에서 보기 힘든 Python의 List의 특징을 작성하겠다.

원소를 포함한 비교 연산이 가능함

Python의 str 구조도 마찬가지이지만 C/C++ 언어에서는 문자열 두개를 비교할때 각 문자의 길이 하나하나를 비교를 해서 같아야만 같은 문자열로 판단하는 알고리즘을 메서드로 구현해서 판단을 해야 한다. Python의 경우 이러한 비교 연산을 위한 Hash라는 값을 인스턴스 혹은 객체를 생성할때 만들어 놓는데, 이 숫자가 같은지만 비교를 하여 비교연산에 소모되는 연산량을 줄였다. 클래스의 Hash에 대해서 자료를 찾아보면 자세한 내용을 알 수 있다.

예시)

a = [1, 'hello', 2]
b = [2, 'hello', 1]
c = [1, 'hello', 2]
a == b
# False
a == c
# True

위의 예시 코드를 Python idle shell에서 실행해서 간단히 확인 할 수 있다.

곱연산으로 반복적인 원소 채우기

Python에서 특이한 기능중 하나로 원소가 있는 리스트와 숫자를 곱 연산 할경우 해당 리스트를 반복적으로 숫자만큼 채우는 것이 가능하다. 이 기능은 Python의 기본 문자열 자료형인 str에서도 나타나는 특징이다.

예시)

a = [1, 2]*3
# a = [1, 2, 1, 2, 1, 2]

예시 코드를 Python idle shell에서 확인 해보면 된다.

원소를 배분

Python에서 가장 두드러지는 문법 중 하나로 배열의 길이 만큼 객체명을 좌항에 작성을 하면 우항에 그 크기에 많은 리스트를 놓으면 각 원소를 순서대로 대입이 되는 특징이 있다. 필자의 경우 이러한 특징을 곱연산의 특징과 응용해서 여려개의 객체명을 초기화 해야 할 경우에 간단하게 사용하곤 한다.

예시)

a1, a2, a3 = [None]*3
# a1 = None
# a2 = None
# a3 = None

예시 코드를 Python idle shell에서 확인 해보면 된다.

단, List의 길이와 좌항의 변수의 길이가 안 맞을 경우 에러가 생기기 때문에 일반화 방식으로 작성할 경우 개수를 검사하는 로직을 미리 추가 해주는 것이 좋다.

간단한 index 로 나누어 대입

이 기능은 다른 언어에서도 있기는 하지만, Python에서 문법적으로 간결하게 제공을 하고 있다. ':'을 대괄호 안에서 사용하여 범위를 자를 수 있다. 필자의 경우 특정 2차원 배열을 1차원 배열에 넣고 관리할때 응용해서 사용하기도 한다.

예시)

a = [1, 2, 3, 4, 5]
b = a[2:]
# b = [3, 4, 5]
c = a[:3]
# c = [1, 2, 3]

index는 많이 헷깔리는 경우가 있는데, python은 친 인간 언어적인 편이라서 사람이 일반적으로 세는 방식으로 자른다. 그러나 전통적인 배열로 사용할 경우에는 0부터 시작한다.

리스트간 병합(Merrge)

List를 초기 정의한 이후 원소를 추가를 할 때 일반적으로 append와 같은 C++의 STL 경우 push 메서드를 호출해서 한쪽으로 하나씩 넣는게 일반적이다. 그러나 List의 연산자 + 혹은 +=을 사용하면 리스트를 동등하게 머지하는 결과를 나타낸다. append와 비슷해 보이나 다른 방식이기 때문에 주의해야 한다.

예시)

a = [1, 2]
b = [3, 4]
c = a + b
# c = [1, 2, 3, 4]

리스트 컴프리헨션(Comprehensions)

공식 문서에서는 간단하게 리스트를 만드는 방법이라고 소개를 하고 있다. 이터러블의 멤버들에게 특정 연산을 사용하는 경우에 응용이 가능하다. 가장 쉽게 응용이 가능한 것은 기존에 어떤 수치 리스트를 파일에 저장하기 위해서 문자형으로 바꾸거나 혹은 반대로 어떤 파일을 읽어서 숫자로 된 리스트를 수치형 자료로 변경할 경우에 응용하면 편한 기능이다. 이 방법을 몰라도 형 변환은 못 하는 것은 아니다. 다만, 간결하고 편할 뿐이다.
예시)

squaresSrc = [1, 4, 8, 16]
squaresDst = [str(it) for it in squaresSrc]
# squaresDst = ['1', '4', '8', '16']

그리고 여기서 더 나아가 컴프리헨션을 통해 중첩과 if문을 응용이 가능하다. 여기서 중첩을 할 경우에는 실제 코드에서 2중 for 문을 사용한 것과 같다. 컴프리헨션에서는 실행되는 순서는 첫 for문 부터 읽어서 가장 마지막에 앞에 있는 연산을 수행한다.

예시)공식 문서 예제

>>>[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

이러한 기능은 편리하지만, 자신이 협업 혹은 유지보수하는 인력 수준에 따라서 중첩 혹은 if문이 추가된 방식에 대해서 가독성이 떨어진다면, 가능하면 사용을 자제하는 것이 좋을 것 같다.

기타 기본적인 재배열(sort) 관련 메서드

List가 선언된 객체에 자체적으로 오름차순과 내림차순으로 재배열할 경우 sort(), 그리고 현재 배열된 원소를 역으로 배열할 경우 reverse()를 기본적으로 지원을 한다. 또한 sort()의 경우 입력인자로는 정해진 flag를 넣어서 방식의 조절이 가능하다. 다만, 이 메서들을 사용시 주의해야 할 점은 List 객체 자체를 바꿔버리기 때문에 재배열을 하기 전의 데이터를 보존을 해야한다면, 깊은 복사를 하고 나서 해야한다는 단점이 있다.

이후 추가로 편의성 기준으로 정리가 필요하면 후에라도 추가를 하도록 하겠다.

참조자료

스택오브 플로워: list str to int

반응형
반응형

PyQt5 개요

사용 계기

급하게 프로토타입을 만들어야 하는 프로젝트를 하게 되어서 Python으로 개발하기로 하고 GUI를 고민하던 중에 PyQt를 선택하게 되었다. 간단한 기능을 테스트를 한다면 자체 내장 모듈인 Tkinter를 사용해도 크게 무리는 없지만, 컴퍼넌트가 30~50여개가 넘어가게 되면, PyQt를 사용하는 것이 적절하다고 생각이 든 것이다. 이러한 이유는 Qt Desinger 라는 툴로 위지윅스(마우스로 디자인 한대로 프로그램이 보이는 기능) 기능을 지원하기 때문이다. 즉, 디자인 화면에서 GUI를 편집을 하고 그대로 코드로 내리는 것이 가능하기 때문에 이는 개발 초기 UI 디자인이 자주 변경할때 대응하기에 좋았다.

PyQt5 개요

Qt는 본래 C++ GUI 라이브러리로 크로스 플랫폼으로 알려지기 시작을 했다. Qt가 나오기 시작할때에는 운영체제에 따른 크로스플랫폼이 상당한 이슈였다. 읽는 방법은 Qt의 뒤가 소문자라서 큐트 라고 읽는 것이 맞으나 요즘 국내 유튜브등에서 큐티 라고 읽는 사람이 많은 것으로 보인다. 근데 가능하면 큐트 라고 읽기를 권장한다. 큐티 는 개신교에서 사용되는 의미가 있기 때문에 오해를 받을 수 있기 때문이다.

PyQt는 기본적으로 Qt를 Python에서 사용할 수 있도록 랩퍼(Warper) 라이브러리이다. 때문에 대부분의 클래스와 메서드의 명칭이 거의 비슷하다. 다만, PyQt5에 들어서면서 일부분 Qt5와 달라지게 된 부분이 있는데, C++ 스러운 문법의 흔적이 있었는데, 이제는 보다 Python 스러워졌다는 것에서 약간은 차이가 있다. 대부분은 PyQt4의 레퍼런스를 참고해도 제대로 사용이 가능하다.

PyQt5에서는 Python3만 지원을 한다. 따라서 아직 Python2를 사용한다면, PyQt4를 사용해야 한다. 하지만, 글을 쓰는 이 시점에는 Python2에서만 사용 가능하던 모듈 대부분이 이제는 Python3에서 지원이 되기 때문에 새 프로젝트라면 Python3를 사용하는 것이 더 좋다(요즘 누가 Python2를 쓰냐고 할지 몰라도 VS 2017에서는 Python2를 주로 지원했다).

라이선스 정책은 GPL v3를 기본으로 따르고 상업용으로 사용할 경우에는 이용료를 지불을 해야 한다.[PyQt 구매참조][1] 만약 회사 내부에서만 사용하는 툴이나 프로젝트를 진행중이라면 라이선스를 크게 걱정을 안해도 된다.

간단한 설치방법

온라인의 경우 콘솔창에 pip로 설치 명령만 내려주면 된다. 의존성도 알아서 검사를 해서 설치를 알아해서 해준다.(참 쉽죠?) 윈도우즈의 경우 콘솔 자체가 대소문자를 구분하지 않기 때문에 대소문자 신경을 안써도 된다. 그외 운영체제는 대소문자 구분을 한다.

pip install PyQt5
pip install PyQt5-tools

오프라인에서 설치할 경우에는 공식 홈페이지에서 wheel 파일을 직접 다운로드를 받아서 설치해야 한다. 설치 명령어는 위의 콘솔 명령어의 모듈명 위치에 경로가 붙는다는 것 외에는 같다. 다만 의존성 자동 설치가 안 되니 순서대로 해야 한다(SIP 모듈을 먼저 설치를 해야 한다).

PyQt5의 디자인 툴의 실행 위치는 일반적으로 모듈 폴더의 designer.exe 파일을 실행하면 된다. 윈도우 기준으로 만약

C:\Python36\

에 설치를 했다면

C:\Python36\Lib\site-packages\pyqt5_tools\designer.exe

경로에서 찾을 수 있다.

기타 사항

  • 윈도우 7 SP2 환경에서 확인한 결과 Qt5를 별도로 설치하지 않아도 사용이 가능하다.
  • 오프라인으로 모듈을 설치할 경우 반드시 SIP 모듈을 설치해야 사용이 가능하다.
  • PyQt Desinger 툴을 사용할 경우 PyQt5 Tools모듈을 별도로 설치를 하고 나서 모듈이 설치된 위치에 설치파일이 생성된다.

참조자료

[1]:https://www.riverbankcomputing.com/commercial/buy
[2]:https://riverbankcomputing.com/software/pyqt/intro

반응형

'Python > PyQt5' 카테고리의 다른 글

[Python, PyQt5]Desiginer 활용  (0) 2019.04.23
반응형

[python]CSV 데이터 포멧 입출력

CSV데이터

CSV(Comma Separated Values)데이터를 처음 접할때 엑셀에서 지원되는 포멧이기 때문에 처음에는 엑셀파일로 아는 경우가 많다. 그러나 실제로는 콤마를 기준으로 데이터를 구분하는 형식이라 볼 수 있다. 이는 CSV의 원 뜻만 확인해도 알 수 있다.

기본적으로 문자열 형태로 저장되기 때문에 문자열 처리에 자신이 있다면 쉽게 csv데이터를 만드는 것과 읽는 것을 하기에는 간단한 편이지만, 간단한 만큼 ','(콤마)가 들어있는 데이터에 대해서는 구분이 잘 안된다. 그리고 이러한 문제가 데이터 오염이라고 말을 한다.

물론 콤마를 데이터안에 반드시 입력을 해야 할 경우에는 "따옴표로 감싸주는 방법이 있다. 그러나 데이터에 다시 따옴표가 들어가야 할 경우 상황이 복잡해지게 된다. 가능하면 간단한 데이터 그중에서도 수치 데이터에 사용하기를 권장한다. 그외에 복잡한 데이터의 경우 다른 형태의 포멧을 사용하길 권장한다.


파이썬에서 CSV

본 예시는 '파이썬 프로그래밍으로 지루한 작업 자동화하기'서적의 예시를 참조하였다.

csv파일 읽기

수학자들의 사랑을 받는 파이썬은 최근에는 CSV 모듈이 자체적으로 내장이 되어 있다. (물론 문자열처리에 자신이 있다면 직접 구현해도 상관없지만, 굳이 바퀴를 재 발명할 필요는 없다.) 따라서 추가로 모듈을 다운로드 설치 과정 없이 import해서 사용할 수 있다. 사용방법은 csv파일을 open한뒤에 csv모듈의 reader 객체를 생성하여서 읽을 수 있다. 이때 읽어진 데이터는 리스트 형식으로 읽어진다.

 여기서 주목해야 할 점은 읽어진 모든 데이터는 문자열로 읽어진다는 점이다. 만약 수치를 처리하고 싶다면 수치형으로 형전환을 해야 한다.


예시1)

>>>import csv
>>>exampleFile = open('example.csv')
>>>exampleReader = csv.reader(exampleFile)
>>>exampleData = list(exampleReader)




csv파일 쓰기

반대로 csv 파일로 쓸경우에는 csv모듈의 writer객체를 생성하고 파일open객체를 연결시켜줘야 쓸 수 있다. 단, open시 줄바꿈 옵션을 제거(newline='')해야 한다. 이는 csv모듈에서 한줄씩 작성될때 마지막에 줄바꿈으로 구분하기 때문이다.


예시2)

import csv
>>>outputFile = open('output.csv', 'w', newline='')
>>>outputWrite = csv.writer(outputFile)
>>>outputWrite.writerow(['spam', 'eggs', 'bacon', 'ham'])
>>>outputWrite.writerow(['hello, world!', 'eggs', 'bacon', 'ham'])
>>>outputWrite.writerow([1, 2, 3.141592, 4])
>>>outputFile.close()


예시에서 hello, world 부분을 csv파일을 다른 편집기로 열어보면 ""으로 감싸진 것을 확인할 수 있다.



생각해 볼 점

만약 데이터가 안들어 있는 빈경우에는 csv를 편집기로 열어서 확인할 경우 콤마(,)만 있는 것을 확인할 수 있다. 이 경우 읽게되면 문자열 형식으로 읽기 때문에 ''(빈문자) 형태로 읽어진다.

 또한 csv의 파일의 에러를 확인하는 방법으로 콤마의 개수를 확인하는 방식이기 때문에 파일이 깨진경우(혹은 데이터 오염) 대부분 콤마의 개수가 안맞는 경우이다.


참고자료

서적, 파이썬 프로그래밍으로 지루한 작업 자동화하기



반응형
반응형

[python]기본 Shell 활용

파이썬의 IDE와 Shell

 파이썬으로 본격적으로 개발을 한다면은 사실 파이참(PyCharm) 같은 IDE(통합개발환경) 툴을 사용 하는 것이 좋다. 다른 IDE처럼 문법 검사 등 개발 시간을 단축시켜주는 많은 보조 기능들이 제공이 되기 때문이다. 과거에는 명필은 붓을 탓하지 않는 다는 말이 있다.


 그러나 오늘날은 도구의 성능의 영향이 확실히 크다. 그러나 초보자 혹은 상황이 여의치 않을 경우에는 파이썬을 설치할때 기본적으로 제공되는 IDE도 상당한 도움이 된다. 특히, Shell은 간단하게 테스트 할때 많은 도움이 된다.


Python Shell의 활용

 기본적으로 Windows PowerShell 이나 CMD 그리고 유닉스 계열의 bash shell 에서 파이썬을 설치한 다음에 python(혹은 python3)만 입력할 경우 보이는 >>>이 보이는 화면이 파이썬 Shell이다. 여기에서는 한 줄씩 JS(자바스크립트)처럼 코드 입력후 실행을 해볼 수 있다. 반면 GUI에 제공되는 Shell의 경우 같이 설치된 IDLE를 실행하면 파이썬에서 제공하는 Shell을 확인할 수 있다.


 이러한 기능은 모듈을 테스트하거나 간단한 코드의 결과를 확인할 때 유용하다. 이러한 기능은 개발을 단축시키는데에 도움이 된다. 특히 GUI에 제공되는 Shell의 경우 전용 단축키와 기능들이 제공이 되기 때문에 운영체제에서 제공되는 Shell에서 실행하는 것보다 더 편리한 편이다.


주요 단축키

 주요 단축키의 경우 Options -> Configure IDLE 를 선택하여 나온 화면의 Key 탭에서 변경이 가능하다. 많은 단축키들이 있고 이를 자신의 입맛대로 수정을 할 수 있다. (그러나 정해진 표준이 없다면, 가능하면 수정을 하지 않는 것을 권장한다) 그리고 기본적으로 자주 사용하는 단축키를 적어 놓는다.


윈도우 기준

Shell 재시작 : Ctrl + F6

이전 줄 코드 읽어 오기(이전으로) : Alt + p

이전 줄 코드 읽어 오기(최근으로) : Alt + n

되돌리기 : Ctrl + Shift + z

자동완성 : tab


 그 외 기본적으로 동일하게 사용되는 기능은 오려두기, 복사, 붙여넣기, 문장 맨앞으로, 문장 맨뒤로는 굳이 외우지 않아도 잘 알기 때문에 생략을 한다.

반응형

+ Recent posts