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문제는 없습니다.