2022년 12월 11일 일요일

파이썬 math (nextafter, ulp, gcd, lcm) (3.9이상)

 

math update

파이썬 3.9 math함수들이 업데이트 되었습니다 이번에는 이 변경점들에 대해서 알아보도록 하겠습니다.

nextafter, ulp

파이썬 3.9에 추가된 이 함수는 부동소수점에서 나타낼 수 있는 가장 작은 다음 값을 찾아줍니다. (Java에도 동일한 이름의 함수가 존재합니다.)

진정한 실수(floating point)에서는 두 수사이에 무한대 개수의 값이 있지만, 실제 컴퓨터는 이것은 floating point를 표현하는 방법이 IEEE-754 기반으로 표현하기때문에, 유한개의 숫자가 존재하고, 이중 가장 근접한 값을 찾아주는 함수입니다. 파이썬 뿐 아니라 대부분의 언어들이 IEEE-754로 floating point를 처리하기 때문에 비슷한 부분이 있습니다.

마찬가지로 ulp함수도, 유효숫자기반의 가장 작은 숫자, 즉 오차범위을 알려줍니다. y를 향한 x 다음의 부동 소수점 값을 반환합니다. x가 y와 같으면, y를 반환합니다.

다음 예제를 참고 바랍니다 아래와 같이 특정 숫자의 가장 작게 차이는

from math import nextafter, ulp

print (nextafter(2,3)) # 2와 3사이의 next floating point value
# 2.0000000000000004

print (nextafter(6,10))
# 6.000000000000001

print (nextafter(0,9))
#5e-324
print (nextafter(9,0))
#8.999999999999998

ulp함수를 찍어보면,

print (ulp(3))
print (ulp(3.14159265))
# 4.440892098500626e-16
# 4.440892098500626e-16
print (ulp(100_000_000_000_000_000))
print (ulp(10_000_000_000_000_000))
print (ulp(10_000_000_000_000))
print (ulp(10_000_000_000))

# 16.0
# 2.0
# 0.001953125
# 1.9073486328125e-06

ulp함수를 찍어보면, 큰 수일 수록 한틱이 움직일때 같이 움직이는 ulp숫자가 커지는 것을 확인할 수가 있습니다. 반대로 수가 작으면 작을 수록 유효한 한틱이 작아지기때문에 그 range만큼 같이 움직이는 것을 볼 수가 있습니다.

이 함수는 정밀도가 높은 연산을 할 때, 이때의 오차 범위를 계산할 수 있습니다

gcd(최대공약수), lcm(최소공배수)

기존 파이썬 버전의 최대공약수, 최소공배수를 구하는 gcd, lcm 함수는 인자를 2개밖에 받지 못하였는데, 3.9버전 부터는 인자가 여러개 되어도 문제 없이 동작합니다.

from math import lcm, gcd

print (gcd(12,60,84)) # 12
print (gcd(24,18,12)) # 6
print (lcm(3,4,5)) # 60 

위와 같이 math함수 변경점에 대해서 알아 보았습니다.

2022년 12월 4일 일요일

Numpy Array Join (hstack , vstack)

이번에는 Array Join은 Array를 붙이는 방법을 설명합니다. NumPy에서는 스택 개념을 사용하여 이와 관련하여 여러 기능을 제공합니다. vstack과 hstack이 사용됩니다 아럐 예제를 보면 간단합니다. vstack은 위아래로 쌓습니다. hstack의 경우는 좌우로 확장을 해갑니다.

import numpy as np

A = np.ones((3, 3))
B = np.zeros((3, 3))
print (np.vstack((A,B)))
print (np.hstack((A,B)))
'''
# vstack
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

# hstack
[[1. 1. 1. 0. 0. 0.]
 [1. 1. 1. 0. 0. 0.]
 [1. 1. 1. 0. 0. 0.]]
'''

여러 배열 사이에서 쌓기를 수행하는 두 가지 다른 함수는 column_stack() 및 row_stack()입니다. 이러한 기능은 이전의 두 기능과 다르게 작동합니다. 1차원 배열을 column으로 쌓을지 row방향으로 쌓을지를 정합니다.

import numpy as np

a = np.array([0, 1, 2])
b = np.array([3, 4, 5])
c = np.array([6, 7, 8])
print( np.column_stack((a, b, c)) )
print( np.row_stack((a, b, c)) )
'''
# column_stack
[[0 3 6]
 [1 4 7]
 [2 5 8]]

#row_stack
[[0 1 2]
 [3 4 5]
 [6 7 8]]
'''

이상으로 Numpy array join에 대해서 알아보았습니다. 


2022년 11월 28일 월요일

파이썬 딕셔너리 merge (|) 연산자 추가 (3.9이상)

유니온 연산자(|) 


딕셔너리에 | (유니온 연산자)를 사용할 수 있습니다. 값을 병합합니다. 기존의 값이 있으면 새 값으로 업데이트 합니다 x.update(y) 의 간단한 버전입니다.
x = {"k1": "v1x", "k2": "v2x"}
y = {"k2": "v2y", "k3": "v3y"}
print (x | y)
# {'k1': 'v1x', 'k2': 'v2y', 'k3': 'v3y'}
print (y | x)
# {'k1': 'v1x', 'k2': 'v2x', 'k3': 'v3y'}
여기서 주의 깊게 볼 건 k2값이 순서에 따라 다른 부분 입니다. 뒤에 있는 값이 Update되는 값이라 최신이 됩니다.

이 기능은 파이썬 3.9에서부터 지원합니다. 

2022년 11월 23일 수요일

Python venv(virtual Environment) 오프라인 설치


Venv

virtual 환경은 보통 파이썬 패키지등을 설치하다 보면, 가끔가다가 환경이 꼬이는 경우들이 가끔가다 발생합니다.

특히 pip같은 걸로 관리하는 경우는 그래도 좀 수월하지만, 이것 저것 패키지 dependency가 꼬이는 경우들이 종종 있습니다. 이런 것들을 방지 하기 위해서, venv를 사용합니다,

이전 python2에는 virtualenv라든지 third-party 지원을 사용했다면, 현재는 python 3.3 부터 venv가 기본 패키지 안으로 들어옴에 따라 그냥 venv를 사용하면 됩니다.

venv 실행

실행법은 아래와 같이 실행하면 됩니다.

>> python -m venv [virtualenv_name]

으로 실행하면 됩니다.

여기서는 env1 로 만들어 보겠습니다. 리눅스 기준으로는 아래와 같이 실행합니다.

>> python -m venv env1
>> cd env 
>> source ./bin/activate
(env1) >> 

위와 같이 가상환경이 준비된 것을 확인할 수 있습니다. 빠져나올때는 deactive 를 실행시키면 빠져나올 수 있습니다.

패키지 확인

다음과 같이 pip list 또는 pip freeze 를 치면 현재 깔린 패키지들을 확인할 수 있습니다 pip list의 경우는 pip나 setuptools같은 기본적으로 깔려 있는 패키지까지 출력을 해주고,

>> pip list  
Package    Version
---------- -------
pip        22.0.2
setuptools 59.6.0

패키지 설치

다음 명령어로는 깔려있는 패키지들을 requirement.txt 파일에 저장을 합니다.

(env1)>> pip freeze > requirement.txt

-r 또는 --requirement 옵션을 사용하면, requirement.txt 파일에 있는 패키지들을 설치할 수 있습니다.

(env1)>> pip install -r requirement.txt 

또 예제로, 아래와 같이 django 패키지를 설치할 수 있습니다.

(env1)>> pip install django 
(env1)>> pip freeze
asgiref==3.5.2
Django==4.1.3
sqlparse==0.4.3

패키지 삭제

pip uninstall 명령어를 이용하면 관련 패키지를 삭제할 수 있습니다. 즉, 다음과 같이 하면 관련 패키지들을 삭제할 수 있습니다.

(env1)>> pip freeze > requirement.txt
(env1)>> pip uninstall -r requirement.txt

offline 설치

그리고 사내망 같은 부분은 분리되어 있는 경우들이 있기때문에 offline 설치 방법이 필요합니다.

패키지 다운로드

먼저 외부망에서 pip download 명령어를 이용하면 패키지를 다운로드 받을 수 있습니다. 아래와 같이 django 패키지를 다운로드 받아 봅니다 whl 파일들이 다운된 것을 확인할 수 있습니다.

(env1)>> pip download django 
(env1)>> ls
Django-4.1.3-py3-none-any.whl
asgiref-3.5.2-py3-none-any.whl
sqlparse-0.4.3-py3-none-any.whl

패키지 로컬 설치

이 whl 파일들을 이용해서 다음 명령어를 사용하면 패키지들이 설치가 됩니다 -f 옵션은 whl 파일이 있는 위치를 나타냅니다.

(env1)>> pip install --no-index -f . django

마무리하며

이글을 처음 작성할 때는 python2 시절이었습니다. 그 당시에는 virtualenv, venv 와 같이 비슷한 이름의 패키지가 있어서, 헷갈리는 부분도 많았는데, 현재는 대부분 python3으로 대세가 넘어왔기 때문에 venv기준으로 내용을 정리 해 보았습니다.

2022년 11월 14일 월요일

파이썬 removeprefix, removesuffix 와 lstrip, rstrip (3.9이상)

removeprefix, removefix

파이썬 3.9에서 removeprefix와 removeprefix 함수가 추가 되었습니다. 얼핏보면 이 함수들은 기존의 lstrip과 rstrip함수와 달라보이지는 않습니다.

그런데 이 strip함수는 하나만 잘라내는게 아니라 전부 잘라냅니다. 아래의 예제를 보시면 이해가 쉽습니다.

s = 'xyzxyzxyzxyz123123'
print (s.lstrip('xyz'))
print (s.removeprefix('xyz'))

print (s.rstrip('123'))
print (s.removesuffix('123'))

# 123123123
# xyzxyzxyz123123123

# xyzxyzxyzxyz
# xyzxyzxyzxyz123123

strip함수는 1번만 잘라내는게 아니라 전부 잘라내기 때문에 의도와는 다르게 쓰일 수 있습니다. 그렇다면 파이썬 3.9이하에서는 어떻게 할까요? 

startswith와 endswith함수로 확인하고, [:] 함수를 이용해서 해당 부분만 잘라냅니다. 조금 번거롭지만 위 함수들을 이용하면, 동일한 효과를 얻을 수가 있습니다.

def removeprefix_alt(text,prefix):
    if text.startswith(prefix):
        text_new = text[len(prefix):]
    else:
        text_new = text
    return text_new

def removesuffix_alt(text,suffix):
    if text.startswith(suffix):
        text_new = text[:-len(suffix)]
    else:
        text_new = text
    return text_new    

s = 'xyzxyzxyzxyz123123123'
print (s.lstrip('xyz'))
print (removeprefix_alt(s,'xyz'))
print (s.rstrip('123'))
print (removesuffix_alt(s,'xyz'))

# prefix
# 123123123
# xyzxyzxyz123123123

# suffix
# xyzxyzxyzxyz
# xyzxyzxyzxyz123123

이상으로 파이썬 3.9에 추가된 removeprefix, removesuffix함수들을 정리 해 보았습니다

2022년 11월 2일 수요일

파이썬 2차원 배열 생성 및 초기화

파이썬에서 2차원 배열이 필요할 때가 있습니다. 그런데 2차원 배열은 리스트 컴프리헨션등으로 쉽게 만들어 낼 수가 있습니다. 다만, 여기서 하나 주의할 점이 있어서 그 부분만 집고 넘어가려고 합니다.

먼저, 2차원 배열은 화면에 그냥 뿌리면 보기 불편하니, 아래와 같이 2차원 배열을 뿌리는 함수를 먼저 만듭니다.

def print_2d(a):
    for row in a:
        for c in row:
            print (c,end= ' ')
        print ('')

2중 for문으로 2중 리스트 선언

ROW, COL = 4, 5
arr = [[0 for c in range(COL)] for row in range(ROW)]
# 5x4 리스트를 생성합니다.  = (4열 5행) 
arr[2][3] = 9 # (3, 2)에 값을 변경합니다. 
print_2d(arr)
'''
0 0 0 0 0 
0 0 0 0 0 
0 0 0 9 0 
0 0 0 0 0 
'''

2차원 배열 access

# arr[row][col]
arr[2][3] = 9 

위와 같이 row가 앞쪽에 위치합니다. 이 부분도 은근히 헷갈릴 수 있으니 주의합시다.

*연산자와 for문으로 리스트 선언

arr = [[0]*5 for i in range(4)]
arr[2][3] = 9
print_2d(arr)
'''
0 0 0 0 0 
0 0 0 0 0 
0 0 0 9 0 
0 0 0 0 0 
'''

연산자 *로 2중 리스트 선언

arr = [[0]*5 ]*4
arr[2][3] = 9
print_2d(arr)
'''
0 0 0 9 0 
0 0 0 9 0 
0 0 0 9 0 
0 0 0 9 0 
'''

이 방법은 주의해야합니다. 위의 두 방법 말고 이 방법으로 배열을 선언하게 되면, row를 새로 생성하는것이 아니라. 단순히 요소를 복사하게 되는 얕은복사 (shallow copy)가 발생합니다. 즉, row의 첫번째 값의 링크로 만들어진 것이라 저런식으로 만들게 되면 어떤 값이든 바꿀때 마다 값이 같이 변경됩니다. 위 예제에서도 (3,2)를 변경했는데 모든 row가 같이 바뀐것을 확인할 수 가 있습니다.

이러한 방식으로 선언 뒤에, 값을 변경하게되면 다른 원소들도 값이 변경되는 현상이 발생하게 되므로 이를 인지하고, 후에 대입연산자를 통해 값을 변경하지 않는 경우에만 사용하는것이 유리합니다. 그런데 위 방법은 그냥 쓰지 않는것을 추천합니다

a = [0]*10
a[3] = 8
print(a)
# [0, 0, 0, 8, 0, 0, 0, 0, 0, 0]

물론 1차원 배열을 생성할 때는 이런 shallow copy문제는 없습니다.

2022년 10월 26일 수요일

파이썬 textwrap (indent, 정렬, 줄바꿈)

 이 textwrap 모듈은 텍스트를 핸들링할때 indentation을 넣거나 빼거나, 글자수를 터미널 너비에 맞춘다거나 할때 유용합니다. 즉, pretty-print가 필요한 경우, 텍스트를 핸들링할때 유용합니다. 많은 텍스트 편집기 및 워드 프로세서에서 볼 수 있는 단락 줄 바꿈 또는 채우기 기능과 유사한 프로그래밍 기능을 제공합니다.

Filling Paragraphs

fill 함수에 대해 알아봅니다 fill() 함수는 텍스트를 width에 맞게 잘라주는 역할을 합니다.

# 실제 함수원형은 좀더 길지만, 아래 형태로 확인합니다
textwrap.fill(text: str, width: int) -> str 
import textwrap

text = '''
    I have two sisters who have made their careers in engineering. My first sister has
    a doctorate in civil engineering. She works in Australia designing mine tunnels for
    a raw materials company. My second sister earned a master's degree in electrical
    engineering. She works in the United States designing communication equipment.
    In summary, my two sisters both have graduate degrees in engineering and have
    careers in engineering.
'''

print (textwrap.fill(text,width=50))
'''
 I have two sisters who have made their careers in
engineering. My first sister has a doctorate in
civil engineering. She works in Australia
designing mine tunnels for a raw materials
company. My second sister earned a master's degree
in electrical engineering. She works in the United
States designing communication equipment. In
summary, my two sisters both have graduate degrees
in engineering and have careers in engineering.
'''

이제 텍스트가 왼쪽 정렬되지만 첫 번째 줄은 들여쓰기를 유지하고 각 후속 줄의 앞부터 공백이 단락에 포함됩니다.

textwrap 모듈은 예쁜 인쇄가 필요한 상황에서 출력할 텍스트의 형식을 지정하는 데 사용할 수 있습니다. 프로그래밍 방식을 제공합니다. 많은 텍스트 편집기에서 볼 수 있는 단락 줄 바꿈 또는 채우기 기능과 유사한 기능입니다.

Indentation 제거

이전 예제에는 출력에 포함된 탭과 추가 공백이 포함되어 있으므로 형식이 매우 명확하지 않습니다. 샘플 텍스트의 모든 줄에서 공통 공백 접두사를 제거하면 더 나은 결과를 얻을 수 있으며 코드 서식 자체를 제거하면서 Python 코드에서 직접 독스트링 또는 포함된 여러 줄 문자열을 사용할 수 있습니다. 샘플 문자열에는 이 기능을 설명하기 위해 도입된 인위적인 들여쓰기 수준이 있습니다. dedent를 사용하면 공백을 제거해 줍니다.

'''
I have two sisters who have made their careers in engineering. My first sister has
a doctorate in civil engineering. She works in Australia designing mine tunnels for
a raw materials company. My second sister earned a master's degree in electrical
engineering. She works in the United States designing communication equipment.
In summary, my two sisters both have graduate degrees in engineering and have
careers in engineering.
'''

아래 예제도 참고 합니다. indent가 들쭉날쭉 한 경우에도 이 공백을 댕겨줍니다. 다만, 실제 paragraph상의 indent를 제거하지 않습니다.

text2= '''
        I have two sisters who have made their careers in engineering. My first sister has
    a doctorate in civil engineering. She works in Australia designing mine tunnels for
    a raw materials company. My second sister earned a master's degree in electrical
    engineering. She works in the United States designing communication equipment.
        In summary, my two sisters both have graduate degrees in engineering and have
    careers in engineering.
'''

print (textwrap.dedent(text2))

'''
    I have two sisters who have made their careers in engineering. My first sister has
a doctorate in civil engineering. She works in Australia designing mine tunnels for
a raw materials company. My second sister earned a master's degree in electrical
engineering. She works in the United States designing communication equipment.
    In summary, my two sisters both have graduate degrees in engineering and have
careers in engineering.
'''

Dedent 와 Fill 함수 조합

다음은 dedent된 텍스트를 fill로 맞추어 봅니다. 위의 Text2 예제를 그대로 씁니다. dedent로 공백을 걷어내고, strip() 으로 좌우 여백을 완전히 잘라줍니다. 그리고 fill을 사용하면 width에 맞게 다시 text가 정렬이 됩니다.

text3= textwrap.dedent(text2).strip()
text4= textwrap.fill(text3,width=60)
print (text4)
'''
I have two sisters who have made their careers in
engineering. My first sister has a doctorate in civil
engineering. She works in Australia designing mine tunnels
for a raw materials company. My second sister earned a
master's degree in electrical engineering. She works in the
United States designing communication equipment.     In
summary, my two sisters both have graduate degrees in
engineering and have careers in engineering.
'''

Indents

때로는 문장 전체에 앞에 공백등을 넣어야 할때가 있습니다. 원래 문장에 4칸의 공백을 넣어봅니다.

text5='''
I have two sisters who have made their careers in
engineering. My first sister has a doctorate in civil
engineering. She works in Australia designing mine tunnels
for a raw materials company. My second sister earned a
master's degree in electrical engineering. She works in the
United States designing communication equipment.     In
summary, my two sisters both have graduate degrees in
engineering and have careers in engineering.
'''
print (textwrap.indent(text5,' '*4))

'''
    I have two sisters who have made their careers in
    engineering. My first sister has a doctorate in civil
    engineering. She works in Australia designing mine tunnels
    for a raw materials company. My second sister earned a
    master's degree in electrical engineering. She works in the
    United States designing communication equipment.     In
    summary, my two sisters both have graduate degrees in
    engineering and have careers in engineering.
'''

위와 같이 indent가 잘 삽입되었습니다.

이상으로 textwrap이 잘 동작 하는것을 확인해보았습니다. 이 textwrap은 종종 텍스트를 화면에 안잘리고 pretty-print하는 용도로 사용합니다.

2022년 10월 24일 월요일

파이썬 정수 나눗셈 (/, // 차이)

 이건 버젼별로 살짝 다른 부분이 있습니다. 파이썬 2.7에서 다음과 같이 나누기를 하면 나눗셈 연산이 버림을 기본으로 하는 정수 연산으로 수행이 됩니다. 정수끼리 나눗셈을 하면 정수를 리턴하고 , 실수가 중간에 끼어있으면 실수값이 리턴됩니다.

이게 C와 비슷한데 정수끼리 나눗셈을 할 경우 기본적으로 정수로 가정해서 연산을 하고는 합니다. 실수형을 리턴받기 위해서는 아래와 같이 하나를 실수로 변경(2 -> 2.0)하면 결과값이 실수가 리턴이 됩니다.

# python 2.7 
4 / 2 
>> 2 # int
4 / 2.0
>> 2.0 # float

파이썬 3에서는 / 연산은 float 을 리턴합니다. 즉, 나눗셈연산이 기본적으로 실수연산으로 전환이 됩니다. 정수연산을 하기위해서는 // 을 사용해서 정수연산을 수행합니다.

# python 3
4 / 2 
>> 2.0 # float
4 // 2
>> 2 # int

/ 연산자를 floating으로 전환 한다해도 정수연산이 필요한 경우가 여전히 존재하므로, 이때는 //로 정수 나눗셈연산으로 처리를 할 수가 있습니다.

이걸 왜 구분해야하는냐 이 float 연산과 int 연산은 속도 차이가 좀 있습니다. 보통은 나눗셈연산이 오래 걸리기때문에, 정수로 처리할 수 있는 것들은 정수로 처리하는게 수행시간 측면에서 유리합니다 그리고 이런 나눗셈연산자는 % 와 같은 나머지 연산자와 보통 정수와 같이 핸들링하는 경우가 많습니다.

그래서 이 차이를 알고 사용하는 것이 좀더 최적화된 구조를 만드는데 도움이 되리라 생각합니다.

이번에는 정수 나눗셈연산에 정리해보았습니다. 이부분이 실제로 작성하다보면 종종 놓치는 부분이기도 하니, 이 정수 나눗셈이 버젼별로 다름을 살짝 인지하고 정수 나눗셈이랑 실수 나눗셈을 구분해서 사용하면 좋을듯합니다.

2022년 10월 21일 금요일

파이썬 zfill 문자열 앞에 0 채우기 (이진수 만들기)

이 파이썬의 zfill함수는 이진수를 만들때 유용합니다. 뿐만 아니라, 전화번호나 날짜등을 표기할때도 유용합니다. 이번에는 주로 바이너리를 표현하는 방법에 관련해서적어 보려고 합니다.

먼저 8을 이진수로 변경해봅니다.

print (bin(8))
# 0b1000

앞의 0b가 거슬립니다. 문자열이니 2번째 다음부터 가져오면 이진수만 떼어내 봅시다.

print (bin(8)[2:])
# 1000

이번엔 8이외에 여러 숫자들을 이진수로 바꾸어 봅니다.


print (bin(0)[2:])
print (bin(1)[2:])
print (bin(2)[2:])
print (bin(3)[2:])
print (bin(6)[2:])
print (bin(7)[2:])
print (bin(8)[2:])

# 0
# 1
# 10
# 11
# 110
# 111
# 1000

이진수가 만들어지지만, 뭔가 좀 비뚤빼뚤합니다. 이때 자리를 맞추기 위해서 zfill함수를 사용합니다.

print (bin(0)[2:].zfill(4))
print (bin(1)[2:].zfill(4))
print (bin(2)[2:].zfill(4))
print (bin(3)[2:].zfill(4))
print (bin(6)[2:].zfill(4))
print (bin(7)[2:].zfill(4))
print (bin(8)[2:].zfill(4))

# 0000
# 0001
# 0010
# 0011
# 0110
# 0111
# 1000

인제 뭔가 자리수가 맞는것 같습니다. 이렇게 표현하는 것이 뭔가 줄이 맞으니, 가독성면에서도 좋습니다 이 zfill 함수는 위와 같이 N자리 보다 작은 스트링을 앞쪽에 0을 붙여서 채웁니다.

이 방법은 위와 같이 파이썬으로 이진수 표현할 때 유용합니다.