python 모듈, 시간객체!

모듈

사용자가 직접 만드는 .py (모듈) 과 파이썬 설치시 기본 내장되어있는 표준 라이브러리,
pip 를 통해 설치가능한 외부 라이브러리에 대해 알아본다.

import

import 키워드는 사실 __import__ 함수를 사용한것

import itertools
itertools = __import__("itertools")

import echo as ec
ec = __import__("ec")

sys 모듈을 사용해 import 된 전체 모듈을 확인할 수 있다.

import sys
sys.module

기존에 어떤 모듈들이 포함되어 있는지 알 수 있다.

만약 동일한 이름의 모듈을 사용할 경우 먼저 검색된 것을 우선시,
보통 사용자가 직접 만드게 가장 앞에 배치되고 그후에 기본 모듈들이 따라옴

표준 라이브러리

파이썬 설치시 기본 제공되는 표준 라이브러리들
아래 소개하는 라이브러리들은 매우 많이 사용되기에 외워두는 것을 추천

atexit
프로그램이 종료될 때 호출할 함수를 등록.

argparse
명령줄 인수를 분석하는 함수를 제공.

bisect
정렬 리스트에 대한 이중 섹션 알고리즘을 제공.

calendar
날짜에 관련된 다양한 기능을 제공.

codecs
인코딩과 디코딩 데이터를 위한 함수를 제공.

collections
다양하고 유용한 자료구조를 제공.

copy
데이터 복사 기능을 제공.

csv
CSV 파일을 읽고 쓰는 기능을 제공.

datetime
처리 날짜, 시간에 대한 클래스를 제공.

fnmatch
유닉스 스타일의 파일 이름 패턴을 일치하는 함수를 제공.

concurrent
비동기 계산을 제공.

glob
유닉스 스타일의 경로 패턴을 일치하는 함수를 제공.

io
I / O 스트림을 처리하는 기능을 제공. 파이썬 3 에선 StringIO 가 포함되어 있어 문자열을 파일로 처리.

json
JSON 형식으로 데이터를 읽고 쓰는 기능을 제공.

logging
파이썬 자체에 기본으로 제공되는 로깅 기능에 대한 액세스를 제공.

multiprocessing
응용프로그램에서 여러 하위 프로세스를 실행하는 동시에 스레드처럼 보이게 하는 API 를 제공.

operator
자신의 람다 표현식을 작성하지 않고, 기본 파이썬 연산자를 구현하는 함수를 제공

os 기본 OS 기능에 대한 액세스를 제공.

random
의사난수 생성 함수를 제공.

re 정규표현식 기능을 제공.

sched 멀티스레딩을 사용하지 않고 이벤트 스케줄러를 제공.

select 이벤트 루프를 만들기 위한 select()poll() 함수에 대한 액세스를 제공.

shutil 높은 수준의 파일 함수에 대한 액세스를 제공.

signal POSIX 신호를 처리하는 기능을 제공.

tempfile 임시 파일과 디렉터리를 만드는 기능을 제공.

threading 고급 스레딩 기능에 대한 액세스를 제공.

urllib URL 을 처리하고, 분석하는 기능을 제공.

uuid 범용 고유 식별자를 생성.

외부 라이브러리

파이썬 사용자 커뮤니티에서 배포되는 외부 라이브러리들

외부 라이브러리 사용시 고려할 사항은 아래와 같다.

  • 파이썬 버전별 호환성
  • 라이브러리 업데이트 대응
  • OS 별 차이
  • API 호환성
  • 라이선스

보통 외부 라이브러리를 사용할 경우 API 래퍼 를 통해
래퍼 외부의 시스템에는 라이브러리가 변경되더라도 영향이 없도록 설계하는 것이 정석

프레임워크

웹 프레임워크에는 장고, 플라스크, 파이런스 등이 있고
이벤트기반 프레임워크는 Twisted, Circuits 가 있다.

프레임워크 역시 파이썬 라이브러리의 묶음으로 배포되기 때문에 라이브러리 사용시 고려할사항이 그대로 적용된다.

배포

파이썬 애플리케이션과 라이브러리를 설치할 때 setup.py 를 사용하는 방법과 동작구조를 알아본다.

현재 배포시 사용하는 라이브러리는 setuptools 이지만 아래와 같은 역사를 가지고 있으며
향후 distlib 로 표준이 변경될지 모른다.

distutils 과저 파이썬 표준 라이브러리.

distribute 0.7 버전부터 setuptools 에 통합, 이후 개발 X

setuptools 표준 고급 패키지 설치 방법, 가장 활발하게 개발되고있는 표준 설치 패키지.

distlib 나중에 distutils 를 대신할 수도 있습니다.

setuptools

setup.py 파일을 사용하는 파이썬 설치/배포 표준패키지.

# setup.py
import setuptools

setuptools.setup(
    name="game",
    version="0.2",
    author="Julien Danjou",
    author_email="acid@debian.org",
    description="Debian packages game tool",
    license="GPL",
    url="http://julien.danjou.info/software/game/",
    packages=['game', 'game/sound', 'game/graphic'],
    classifiers=[
        "Development Status :: 2 - Pre-Alpha",
        "Intended Audience :: Developers",
        "Intended Audience :: Information Technology",
        "License :: OSI Approved :: GNU General Public License (GPL)",
        "Operating System :: OS Independent",
        "Programming Language :: Python"
   ],
)

위와같이 setup 객체안에 dict 형식의 데이터를 전달, 설치시 매개변수로 사용 가능하다.

setup.cfg 를 통해 설치시 사용하는 메타데이터를 별도의 파일로 관리 가능하다.

# setup.cfg
[metadata]
name = foobar
author = Dave Null
author-email = foobar@example.org
summary = Package doing nifty stuff
license = MIT
description-file =
    README.rst
home-page = http://pypi.python.org/pypi/foobar
requires-python = >=2.6
classifier = 
    Development Status :: 4 - Beta
    Environment :: Console
    Intended Audience :: Developers
    Intended Audience :: Information Technology
    License :: OSI Approved :: Apache Software License
    Operating System :: OS Independent
    Programming Language :: Python

# setup.py
import setuptools

# setup.cfg 파일이 있다면 setup 함수안에 매개변수를 안넣어도 된다.  
setuptools.setup()
$ tree
.
├── game
│   ├── __init__.py
│   ├── graphic
│   │   ├── __init__.py
│   │   └── render.py
│   └── sound
│       ├── __init__.py
│       ├── echo.py
│       └── greeting.py
├── main.py
└── setup.py

$ python setup.py build
running build
running build_py
creating build
creating build/lib
creating build/lib/game
copying game/__init__.py -> build/lib/game

압축 - bdist_wheel, sdist

배포 패키지 표준(PEP427) 를 지원하는 툴로
아래 명령어로 사용한다.

pip 1.4 버전부터 지원

$ python setup.py bdist_wheel
running bdist_wheel
running build
running build_py
...
creating 'dist/game-0.2-py3-none-any.whl' and adding 'build/bdist.macosx-10.9-universal2/wheel' to it
....
adding 'game-0.2.dist-info/top_level.txt'
adding 'game-0.2.dist-info/RECORD'
removing build/bdist.macosx-10.9-universal2/wheel

bdist_wheel 를 사용해 .whl 형식으로 압축, dist 디렉터리에 .whl 파일이 생성된다(사실 그냥 zip 형식의 압축파일)

sdist 를 사용해 tar.gz(tarball) 형태로 압축 가능하다.

$ python setup.py sdist

bdist_wheel 이 표준임으로 pypi 업로드시에 bdist_wheel 만 사용 가능함

PyPI 업로드

예전에는 setup.py 를 직접호출해서 압축된 파일을 PyPI 서버에 올렸지만
최근 변경되었다.

태스트용 파이썬 온라인 패키지 관리페이지는 testpypi 를 사용

홈 디렉토리에 .pypirc 파일 생성

[distutils]
index-servers =
  testpypi
  pypi

[testpypi]
username = <username>
password = <password>
repository = https://test.pypi.org/legacy/

[pypi]
username = <username>
password = <password>
repository = https://pypi.python.org/legacy/
$ python setup.py bdist_wheel upload -r testpypi

만약 server response (500): <urlopen error [ssl: certificate_verify_failed] ... 에러가 뜬다면 아래 커맨드 실행 open /Applications/Python\ 3.10/Install\ Certificates.command

pbr (Python Build Reasonableness)

setuptools 과 같이 사용되며 git, spinks 와 연동되어 부가설정이 더해진다.

import setuptools

setuptools.setup(setup_requires=['pbr'], pbr=True)

pip

파이썬 3.4 부터 같이 배포되는 pip 를 사용해 파이썬 패키지를 PyPI, tarball, wheel 저장소에서 가져올 수 있다.

일반적으로 Python Package Index(PyPI) 를 사용함

# 이미 설치된 패키지 목록 확인
$ pip3 freeze
absl-py==1.3.0
boto3==1.24.95
...

# 설치된 패키지 삭제
$ pip3 uninstall boto3

**pip install -e ** `editable` 옵션으로 `egg-info` 파일이 `path` 위치에 생김 개발중인 패키지를 테스트하고 싶을 때 실시간으로 변경된 내용이 적용됨, 아래와 같이 git 에서 패키지를 설치받아 사용하는 경우가 대부분, URL 끝에 `$egg` 와 디렉토리 위치 표기 필수

pip install -e git+https://github.com/jd/daiquiri.git/#egg=daiquiri

시간정보

파이썬에는 여러가지 시간정보 패키지가 존재한다.

timestamp 를 관리하는 datetime 패키지와 timezone 을 관리하는 dateutil 패키지 를 알아본다.

import datetime
# datetime.datetime(2022, 10, 24, 10, 21, 5, 504442)
d1 = datetime.datetime.utcnow()

# datetime.datetime(2022, 10, 24, 19, 21, 42, 736294)
d2 = datetime.datetime.now()

print(d1.tzinfo) # None
print(d2.tzinfo) # None

utcnow() 함수와 now() 함수를 비교하면 9시간 차이(유럽과 한국 시간차)가 난다.
datetime 패키지의 함수는 항상 timezone 이 없는 timestamp 를 반환한다.

timezone 관련해선 dateutil 패키지의 tz 클래스를 사용해야 한다.

import datetime
import dateutil.tz

now = datetime.datetime.now()
tz1 = dateutil.tz.gettz("Asia/Seoul")  # tzfile('/usr/share/zoneinfo/Asia/Seoul')
tz2 = dateutil.tz.gettz("GMT+8")  # tzstr('GMT+8')
tz3 = dateutil.tz.gettz()  # tzfile('/etc/localtime')

now1 = now.replace(tzinfo=tz1)
now2 = now.replace(tzinfo=tz2)
now3 = now.replace(tzinfo=tz3)

print(now1)  # 2022-10-24 19:43:53.064341+09:00
print(now2)  # 2022-10-24 19:43:53.064341+08:00
print(now3)  # 2022-10-24 19:43:53.064341+09:00

print(now1.tzinfo)  # tzfile('/usr/share/zoneinfo/Asia/Seoul') 
print(now2.tzinfo)  # tzstr('GMT+8') 
print(now3.tzinfo)  # tzfile('/etc/localtime') 

print(type(tz1)) # <class 'dateutil.tz.tz.tzfile'>
print(type(now1)) # <class 'datetime.datetime'>

zoneId 혹은 GMT 시간대 정보를 기반으로 tz 클래스 객체생성이 가능
아무것도 사용하지 않을경우 localtime 의 timezone 을 사용한다.

위와같이 datetime 패키지의 datetime 클래스로 부터 반환되는 timestamptzinfo 를 지정하여 사용한다.

timestamp 직렬화

ISO 8601 형식으로 timestamp 직렬화

print(now.isoformat())   # 2022-10-24T20:00:59.956548
print(now1.isoformat())  # 2022-10-24T20:00:59.956548+09:00
print(now2.isoformat())  # 2022-10-24T20:00:59.956548+08:00
print(now3.isoformat())  # 2022-10-24T20:00:59.956548+09:00

now 는 단순 datetime 객체로 생성한 timestamp now1~now3tz 클래스로 timezone 까지 넣은 객체