반응형

list boolean 판별 all, any

배경

Python의 가장 큰 매력은 있으면 편할 것 같은 내장함수가 많다는 것이다. 종종 여러요소들을 검사할 경우 검사 결과에 대해서 list에 담아서 확인을 하고 싶은 경우가 있다. 경우에 따라 모두 True이어야 하거나 하나라도 True 인 경우가 필요하다면, all()과 any() 내장 함수를 사용하면 된다.

사용 조건은 iterable (반복자 사용가능)으로 즉, 좀 더 쉽게 접근하자면 for in 문 사용이 가능한 list 같은 자료구조에 사용할 수 있다.

 

all()

입력받은 list 인스턴스중 모두다 True 이여야 True 값을 반환한다. 즉, 각 list내의 boolean 값이 각각 and 논리연산을 한 것과 같다.

a = [True, True, True]
b = [True, False, True]
all(a)
# True
all(b)
# False

 

any()

입력받은 list 인스턴스중 하나라도 True이면 True를 반환한다. 각 list내에 boolean 값이 각각 or 논리연산을 한 것과 같다.

a = [False, False, False]
b = [True, False, False]
any(a)
# False
any(b)
# True

 

 

반응형
반응형

datetime, timestamp, str 변환

배경

 어쩌다보니 플라스크를 이용해서 서버관련된 개발을 하게 되었다. 원래 도쿠 위키에 정리를 해놓은 문서이지만, 다시 블로그에 올리는게 나을 것 같아 정리를 한다.

 서버쪽에서 데이터를 수집 및 표시를 할 때 시간에 대해서 자주 다룬다. 특히 실시간으로 뭔가를 처리해야 할 경우나 데이터를 처리하는 경우 더 더욱 자주 사용한다. 참고로 하드웨어 쪽 펌웨어의 timestamp와 서버에서 말하는 timestamp 간 차이가 있으니 주의해서 이해를 해야 오해가 없다.

 

datetime 관리 팁

 서버에서 timestamp의 의미는 unix timestamp로 1초는 1의 값이 된다.

 

 파이썬에서는 내장모듈인 datetime을 중심으로 코드를 작성하는 것이 좀 더 단순한 구조가 된다. 이는 내장 모듈이기 때문에 어지간하면 ORM 모듈에서 지원을 하기 때문이다.

1. datetime now

from datetime import datetime

datetime.now()
# datetime instance now

 

2. datetime to timestamp

from datetime import datetime

timestamp = datetime.now().timestamp()

 

3. datetime to str

from datetime import datetime

datetimeStr = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%L")
# ex) 2021-06-07 14:57:01.113000

 

4. timestamp to datetime

from datetime import datetime

timestamp = datetime.now().timestamp()
dt = datetime.fromtimestamp(timestamp)

 

5. str to datetime

from datetime import datetime

datetimeStr = "2021-06-07 14:58:01.11100"
dt = datetime.strptime(datetimeStr, "%Y-%m-%d %H:%M:%S.%L")

 

참조 자료

(추후 추가)

반응형
반응형

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 계단 밟기

반응형
반응형

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

반응형

+ Recent posts