딥상어동의 딥한 생각

파이썬을 효과적으로 사용하기 위한 몇가지 방법들

by 딥상어동의 딥한생각

본격적으로 글을 적기전에 시간 측정을 위한 간단한 데코레이터를 먼저 하나 만들고 시작하겠다.

 

def check_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        check_func = func(*args, **kwargs)
        total_time = time.time() - start
        print(f'이 함수 {func.__name__} 를 실행하는데 {total_time}초가 걸렸습니다.')
        return total_time
    return wrapper

 

1. 상수는 한번만 연산하자.

 

상수는 한번만 연산하는 것이 좋다. for loop안에서 상수가 반복될 경우 속도가 느려질 수 있다.

@check_time
def for_inside_constant(constant: int):
    empty = []
    for i in range(10000000):
        a = 3
        empty.append(a*3)
    print(empty[:5])


@check_time
def for_outside_constant(constant: int):
    empty = []
    a = 3
    for i in range(10000000):
        empty.append(a*3)
    print(empty[:5])
    

for_inside_constant(3)
for_outside_constant(3)

위 두 함수를 비교해보자. 

상수를 포문 밖에서 선언한 for_outside_constant가 조금 더 빠르다.

 

2. collection 모듈 활용하기

 

파이썬에는 collection 모듈이라는 것이 있다. collection 모듈 내부에는 여러 자료 구조들이 있는데, 이번 글에서는 예시로 OrderedDict에 대해서 다루어 보려고 한다. 말 그대로 dictionary를 정렬하여 반환하는 자료구조이다.

 

1. dictionary 생성후 정렬하는 방법

2. 처음부터 orderedDict로 생성하는 방법 두 가지를 비교해 볼 것이다.

 

1의 경우, 정렬 알고리즘에 따라서 속도 차이가 있을 수 있다는 점 참고 부탁드림..

@check_time
def sort_dict1(dict_array: dict):

    dict_origin = {}
    for i, j in zip(dict_array[0], dict_array[1]):
        dict_origin[i] = j

    sort_keys = sorted(dict_origin, key=dict_origin.get)

    dict_with_sort = {}

    for key in sort_keys:
        dict_with_sort[key] = dict_origin[key]

    return dict_with_sort


@check_time
def sort_dict2(dict_array: dict):
    ordered_dict = OrderedDict()
    for i, j in zip(dict_array[0], dict_array[1]):
        ordered_dict[i] = j

    return ordered_dict
    

sort_dict1(sample_data)
sort_dict2(sample_data)

OrderedDict로 생성했을 때가 조금 더 빠르다. 

 

3. List Comprehension 이용하기

 

For loop를 이용하는 것 보다는 List Comprehension을 이용하는 것이 좀 더 빠르다.

@check_time
def for_list_comprehension(num: int):
    return [i for i in range(num)]


@check_time
def for_just_loop(num: int):
    temp_list = []
    for i in range(num):
        temp_list.append(i)
    return temp_list
    

for_list_comprehension(1000000)
for_just_loop(1000000)

 

4. 빌트인 함수

 

빌트인 함수가 있는 경우 빌트인 함수를 사용하는 것이 더 좋다. max를 구하는 경우를 비교해보자. 빌트인 max와 직접 만든 max 함수 속도를 비교할 것이다. 직접 만든 max 함수의 경우 정렬해야 하는 상황을 가정하였다.

 

@check_time
def max_built(num_list):
    print(max(num_list))
    return max(num_list)


@check_time
def max_made(num_list):
    print(sorted(num_list)[-1])
    return sorted(num_list)[-1]


max_built(range(10000000, 0, -1))
max_made(range(10000000, 0, -1))

 

5. Numpy의 위대함

 

Numpy는 위대하다.. 왜냐하면, Numpy는 BroadCasting 연산을 지원하기 때문이다.

https://python-course.eu/numerical-programming/numerical-operations-on-numpy-arrays.php

그 위력은 참으로, 강력하다고 할 수 있는데, 오른쪽은 (3, 3) 왼쪽은 (1, 3) 행렬이다. 이때, (1, 3) 행렬을 (3, 3) 구조에 맞게 확장시켜 연산을 가능하게 하는 것이 BroadCasting이다.

 

List의 경우 이러한 Broadcasting 기능이 없기 때문에 객체 내 원소 하나 하나 접근하여 값을 수정해야 한다.

 

@check_time
def list_calculation(num_list):
    empty_list = []
    for i in num_list:
        empty_list.append(i*3)
    return empty_list


@check_time
def numpy_calculation(num_list):
    return np.array(num_list) * 3
    
    
list_calculation(range(100000000))
numpy_calculation(range(100000000))

 

역시, Numpy가 빠르다.. 갓넘파이

블로그의 정보

딥상어동의 딥한생각

딥상어동의 딥한생각

활동하기