Programming-[Backend]/Python 38

파이썬 itertools.groupby 주의사항. 키가 연속으로 붙어있어야함

조회해온 객체를 같은 키값을 가진 것끼리 묶어서 그루핑하고 로직을 처리할려고 파이썬의 itertools.groupby를 사용 grouped_students = groupby(students, key=lambda x: (x.school, x.grade)) 학생들을 학교, 학년별로 묶음 그런데 잘 작동하지 않아 확인해보니, itertools의 groupby는 순회하면서 하나씩 비교하기 때문에 key값이 같은 요소들끼리 연속적으로 붙어있어야 정상 동작함 sorted(students, key=lambda x: (x.school, x.grade)) 로 먼저 정렬 후 groupby를 적용해야함

Decorator 개념과 적용, @wraps

Decorator decorator는 함수를 파라미터로 받아서 그 함수를 실행하면서 다른 기능들을 실행할 수 있도록 해주는 패턴이다. 여기서 다른 기능들이란 인자로 받는 함수의 실행 전, 후로 로그인, try-catch문 등 반복적으로 수행되는 작업을 의미한다. 참조1의 예시가 가장 이해하기 좋고 일반적인 예제인것 같다. decorator_exam 메서드에서 인자로 받아오는 함수 func를 내부 함수 decorator_func에서 다른 기능들과 함께 실행한 후 리턴하도록 만들어준다. 그러면 @decorator_exam을 위에 써준 함수들을 실행했을 때, 해당 기능이 작동한다. def decorator_exam(func): def decorator_func(): print('함수 시작') func() pr..

[TIL] Python O(n)은 몇 초 정도일까 (Casting, converting)

100만개 원소를 가진 list를 set으로 변환하면 실제 시간은 얼마나 걸릴까? set 변환은 O(n)의 시간복잡도를 갖는다.import time l = [] for i in range(1000000): l.append(i) start_time = time.time() s = set(l) end_time = time.time() print(f"execution time = {end_time - start_time:.4f} seconds")상황에 따라 다르겠지만, 평균적으로 0.03초 정도 걸렸다. 로컬, macOS m1, python 3.10 기준이다.

[탐험] 테스트하기 좋은 코드, private과 given이 너무 많을 때

대략적으로 공부하고 깨달은 부분이라 정확하지 않을 수 있다. 개발 업무를 해나가면서 계속해서 개선할 내용이니, 일단 참고만 하자 문제상황 테스트 코드를 작성하는데 public 메서드 1개에 여러 개의 private 메서드가 포함되었다. 많은 참조 자료에서 private 메서드를 테스트하는 것은 바람직한 방향이 아니라고 한다. ( 참조 3. 자바에서 private 메서드를 import할 때 Reflection을 사용하게 되는데, Reflection은 컴파일 에러를 유발하지 못하므로 메서드 이름 변경 등에 취약하다. 그리고 애초에 private은 외부 참조가 안되도록 만들어놓고 결합도를 낮추어 놓은 측면이 있는데, 이를 무시하게 되는 것이 된다.) 그러나 각 메서드를 private으로 처리한 것은 정말 해당..

[TIL] 파이썬 단일 메서드 실행 디버깅 - shell_plus

앱의 환경 설정 조건에 구애받지 않고 단일 메서드를 테스트하고 싶다면 아래 명령어로 파이썬 인터프리터를 실행하면 된다. python manage.py shell_plus mac의 경우 python 대신 python3 입력 이후 콘솔창에서 변수를 생성하고, 함수를 import 후 해당 위치의 함수에 break point를 잡고 실행하면 디버깅이 가능하다. 예를 들어서, projects/utils.py 위치에 아래와 같은 메서드가 있다면 def test(name: str) -> str: ... 해당 메서드에 break point를 설정한 뒤 콘솔에서 아래 명령어들을 실행하면 된다. name = "테스트 이름" # 인자값을 변수로 생성 from projects.utils import test # py 파일 i..

[TIL] PyPy, CPython과 session close(), reference counting

CPython 상용 Python은 CPython이다. CPython은 Garbage Collector(GC)를 통해 Reference Counting 방식으로 참조되지 않는 객체는 메모리에서 제거한다. 따라서 requests.session을 따로 close() 해주지 않아도 알아서 없어진다. 참고로 Reference counting 방식은 어떤 객체의 참조 수가 0이 되면 커널에서 해당 객체에 대한 메모리를 해제할 수 있도록 이벤트 큐에 넣어서 전달하고, 이를 OS가 해지하는 방식으로 작동한다. PyPy PyPy는 개별로 설치가 필요하다. 기존 Python이 interperter 방식이라 속도가 떨어지는 점을 보완하기 위해서 JIT(Just In Time) Compiliing 방식을 적용한 Python이..

[TIL] 파이썬 Retry 방식 요약 backoff_factor, status_forcelist

파이썬의 requests.Retry 스펙은 대략 이렇다. retry = Retry( total=retries, read=retries, connect=retries, backoff_factor=backoff_factor, status_forcelist=status_forcelist) 서버간 또는 서버 - 클라이언트간 통신에서 서버에 요청을 보냈는데, 500대 에러가 떨어지면서 정상적인 응답을 하지 못하는 경우 Retry를 적용한다. 보통은 서버가 잠시 네트워크 지연이 있거나, 너무 과도한 로드가 걸려있는 경우에 시행한다. Http Status Code = 500, 502, 503, 504 정도에 대해 시행한다. [TIL][link] HTTP 상태 코드별 내용 정리 total은 총 요청 횟수이다. 2 = ..

[TIL] prviate, public 메서드 테스트 기준, Exception 테스트 기준

정석인 내용은 아니며, 회사 시니어분들께 배운 내용 기록 1. private, public 테스트 기준 public은 테스트, private은 테스트하지 않는 것을 기본으로 한다. private 일지라도 매우 중요한 로직이고, 테스트가 필요할 것 같다면 public method로 wrapping하여 테스트한다. 테스트 커버리지는 60~80 사이로 한다. 이 사이에서 적절한 커버리지를 찾되, 각 팀원에게 커버리지 정도를 강요하긴 어렵다. 2. Exception 테스트 기준 exception의 결과가 예상 가능하고 정상적인 상황일 때는 테스트한다. 예외적인 케이스에 대해서까지 테스트하는 것은 보통의 프레임워크가 처리해주는 범위를 건드리는 것이고 과한 커버리지 일 수 있다.

[TIL] Deepcopy, dict 순서 유지

1. Deepcopy: dict 어떤 원본 값을 변형하지 않고 다음 로직에서 사용하기 위해서는 deepcopy를 사용하여 참조되는 값의 변경이 일어나지 않도록 해줘야한다. some_value = _get_some_value( ... ) # some_value = {"a": 1, "b": 2} another_result = _get_another_result(some_value=some_value) def _get_another_result(some_value): result = some_value result["a"] = 3 return result 위 코드처럼 간단한 경우에는 한눈에 _get_another_result를 실행하면서 some_value 값도 변경된다는 것을 인지할 수 있으나 코드가 복잡해..

[TIL] python csv writer StringIO, BytesIO for AWS boto3

문제상황 AWS boto3가 BytesIO로 저장 양식이 정해졌을 때를 상정해서, python의 csv를 import하여 csv 파일을 만들 때 BytesIO를 이용하여 바로 csv.writer를 생성하면 byte 데이터를 넣어줘도 에러가 난다. data = ["a", "b"] writer = csv.writer(io.BytesIO()) b_data = [str(ch).encode() for ch in data] writer.writerow(b_data) 원인 AWS boto3는 BytesIO로 입력을 받는데 csv는 writer로 StringIO만 받기 때문이다. 해결책 converting 과정을 추가한다. data = ["a", "b"] str_buffer = io.StringIO() writer =..