Python

[Python] Python 반복문 개선하기

메바동 2021. 11. 16. 23:05
728x90

 지난 포스팅에 코드 실행시간을 측정하는 방법을 찾아보게 된 이유가 어떤 Python 코드의 동작 시간이 오래 걸렸다는 이슈가 있어 찾아보게 되었다고 했었는데, 그 이슈 때문에 내가 작성했던 Python 코드도 다시 한번 보게 되었다.

 

물론 해당 이슈는 반복문을 돌면서 돌 때마다 요청을 보내고 응답을 기다린 뒤 응답을 처리하는 과정을 거치기 때문에 속도 문제가 발생한 것이고, 내가 작성했던 코드에서는 요청을 한 번 보내고 받아온 응답을 반복문을 돌면서 처리하기 때문에 그와 같은 문제는 발생하지 않을 것 같았다.

아직 실제 테스트를 해보지 않아서 어떤 문제가 발생할지는 모른다...

 

 

 

1. 기존 코드

문제는 없을 것 같았지만 내가 짠 코드에 가장 큰 문제점은 가독성이었는데 (다른 문제도 많을 것이지만 현재 내 수준에서 보이는 문제는 그렇다. 공부를 더 열심히 해야지) 이렇게 짰던 이유는

 

우선 가장 큰 문제는 내 수준이 부족한 탓이다.

 

그걸 알면 공부를 열심히 해야 하는데...

 

SDK 문서만 보고 WSDL 웹 서비스 요청을 보내고, 응답 데이터 중에 필요한 부분만 가져와 데이터를 수정하고 다시 웹 서비스로 수정 요청을 보내면 되는 과정이었다.

 

요청을 보내면 json 형식처럼 생긴 리스트들을 받아오게 되는데, 당시에는 SDK 문서에 해당 오브젝트를 만드는 생성자가 있어

'생성자로 오브젝트를 새로 만들고 거기에 다른 데이터를 그대로 넣고, 원하는 부분만 수정하면 되겠다!'

라고 생각을 하고 뿌듯하게 생각했다.

 

 

대충 비슷한 상황을 만들기 위해 python으로 랜덤 하게 device json 목록을 만들어 보았다.

 

def device_info_item():
    return {
        "ip": None,
        "port": None,
        "device_cpu": None,
        "device_memory": None,
        "device_company": None,
        "password": None,
        "comment": None
    }

 

WSDL에 해당 Object를 반환하는 함수가 있었기 때문에 위와 같이 비슷하게 json 형식을 반환하는 함수를 만들어주고

 

file_path = './sample.json'

with open(file_path, 'r') as f:
    device_list = json.load(f)

find_device = []

for device_info in device_list:
    if device_info['ip'] == '220.54.75.2' and device_info['port'] == 22:
        device = device_info_item()
        device['ip'] = device_info['ip']
        device['port'] = device_info['port']
        device['device_cpu'] = device_info['device_cpu']
        device['device_memory'] = device_info['device_memory']
        device['device_company'] = device_info['device_company']
        device['password'] = 'new_password'
        device['comment'] = device_info['comment']
        find_device.append(device)

 

이렇게 원하는 목록을 찾아 새로운 object를 생성해 값을 입력하고 원하는 부분만 변경하는 식으로 만들었었다.

 

원하는 IP와 Port로 찾아 패스워드를 변경한 뒤 찾은 device를 리스트에 넣는 방법인데 지금 보니 참 한심하게 짠 코드인 것 같다.

 

 

 

 

 

2. list, map, filter로 코드 정리하기

이번에 코드를 다시 보게 되면서 이렇게 길고 뭘 하는지도 한눈에 들어오지 않는 코드는 절대 절대 좋지 않을 것이라는 생각이 들었다.

빨리 구입해둔 실용주의 프로그래머와 클린 코드를 읽어야지

 

생각해보니 웹 서비스에 요청해서 데이터를 받아왔으니 그냥 filter로 찾아낸 뒤 map을 사용해 패스워드를 변경하는 함수로 처리한 뒤 list로 다시 묶어주면 된다는 생각이 들었다.

 

def change_password(item):
    item['password'] = 'new_password'
    return item

 

그래서 이렇게 password를 변경하는 함수를 만들어준 뒤

 

with open(file_path, 'r') as f:
    device_list = json.load(f)

find_device = list(map(change_password, filter(lambda device: device['ip'].startswith('220.54.75.2')
                                                          and device['port'] == 22, device_list)))

 

list, map, filter 그리고 lambda를 사용하여 코드의 길이를 확 줄일 수 있었다.

지금은 예시로 만든 데이터라 이전에 Object에 대입하는 코드의 길이가 몇 줄 되지 않았지만 실제로 작성했던 코드는 10줄 이상이 있었다.

Java에서 stream을 유용하게 쓰고 있던 터라 꽤나 직관적으로 보이고 코드 길이를 줄일 수 있었다는 점에서 매우 뿌듯하였다.

 

이전을 워낙 멍멍이판으로 짜놓고 뿌듯해하고 있었다.

 

물론 더 좋은 코드가 있겠지만 말이다.

 

 

 

3. List Comprehension 사용하기

그런데 찾아보다 보니 Python에서 map과 filter를 사용하는 건 전혀 Python 스럽지 않다는 글을 보게 되었다.

 

Pyhton 다운게 뭔데!!!

 

Python에는 List Comprehension이라는 게 존재하고 map과 filter를 사용하는 것보다 for... if 식으로 처리하는 게 더 Python 스럽다고 한다.

뭐 찾아보니 리스트 컴프리헨션이 속도면에서도 이득이라고 하지만 우선 내 상황에서는 크게 차이는 없었다.

 

file_path = './sample.json'

with open(file_path, 'r') as f:
    device_list = json.load(f)

find_device = [change_password(device) for device in device_list if
                device['ip'].startswith('220.54.75.2') and device['port'] == 22]

 

그래서 뭐 결국 내 코드는 최종적으로 이렇게 수정되게 되었다.

 

 

 

이게 더 나은 코드 인지도 모르겠고 맞는 건지도 모르겠지만 우선 보기 좋아졌다는 것만으로도 나는 만족한다.

 

하면 할수록 내가 제대로 하고 있는지도 모르겠고 어떻게 해야 될 지도 더 막막한 것 같다.

 

 

더 열심히 해야지...

728x90