Python 개발자라면 파이프라인 이라는 용어를 들어보셨을 것입니다 . 파이프라인이란 정확히 무엇이며 왜 유용한지 개념, 작동 방식, 더 깔끔하고 효율적인 코드를 작성하는 데 어떻게 도움이 되는지 살펴보겠습니다.
파이프라인이란?
파이프라인은 메서드에 인자를 넣었을때 출력값을 바로 다음 메서드에 넣어서 출력값을 얻고 또 그 값을 여러 메서드를 거쳐 최종값을 얻는 방식입니다.
예를 들어, 숫자 목록이 있고 숫자 목록에 대해 다음 작업을 수행하려고 한다고 가정합니다.
- 홀수를 필터링하세요.
- 각 숫자에 10을 곱하세요.
- 각 숫자에 5를 더하세요.
- 결과 숫자의 평균을 계산합니다.
보통 위의 조건의 로직을 코딩할때 목록을 반복하고 각 작업을 하나씩 적용하여 중간 결과를 새 목록에 저장하는 루프를 작성합니다.
code ex).
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = []
for n in numbers:
if n % 2 == 0:
filtered.append(n)
multiplied = []
for n in filtered:
multiplied.append(n * 10)
added = []
for n in multiplied:
added.append(n + 5)
total = 0
count = 0
for n in added:
total += n
count += 1
average = total / count
print(average)
위 코드는 작동하지만 효율적이지는 않습니다. 메모리를 차지하고 코드 읽기를 어렵게 만드는 새로운 목록을 생성합니다. 또한 4개의 루프를 작성해야해서 오류가 발생하기 쉽습니다.
이를 수행하는 더 좋은 방법은 파이프라인을 사용하는 것입니다. 파이프라인을 사용하면 중간 목록이나 루프를 만들지 않고도 작업을 함께 연결할 수 있습니다. lambda를 이용해 익명함수로 간결하게 만들고 map과 filter를 사용하여 한줄로도 만들 수 있습니다.
code ex).
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
average = sum(map(lambda n: n + 5, map(lambda n: n * 10, filter(lambda n: n % 2 == 0, numbers)))) / len(numbers)
print(average)
위 코드는 이전 코드보다 훨씬 짧고 간결합니다. 하지만 map을 중첩 사용하여 가독성이 좋지 않습니다.
파이프라인을 작성하는 더 나은 방법은 toolz 라이브러리에서 pipe함수를 사용하는것을 추천드립니다. 초기 값과 일련의 함수를 취하고 각 함수를 이전 함수의 출력에 적용하여 최종 결과를 반환합니다.
code ex).
from toolz import pipe
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
average = pipe(numbers,
filter(lambda n: n % 2 == 0),
map(lambda n: n * 10),
map(lambda n: n + 5),
lambda x: sum(x) / len(x))
print(average)
위 코드는 이전 코드보다 훨씬 더 가독성이 좋습니다. 데이터에 적용되는 작업 순서를 명확하게 보여주며 중첩된 호출이나 중간 목록을 사용하지 않습니다. 이 pipe함수를 사용하면 코드가 한 함수에서 다음 함수로 데이터가 흐르는 파이프라인처럼 보입니다.
파이프라인을 사용하는 이유는 무엇일까요?
파이프라인의 장점:
- 가독성 : 파이프라인은 중간 변수나 루프로 코드를 복잡하게 만들지 않고도 한 작업에서 다음 작업으로의 데이터 흐름을 보여주기 때문에 코드를 더 읽기 쉽고 이해하기 쉽게 만듭니다. 파이프라인은 또한 각 작업을 쉽게 테스트하고 다양한 컨텍스트에서 재사용할 수 있는 별도의 함수로 정의할 수 있으므로 코드를 더욱 모듈화하고 재사용 가능하게 만듭니다.
- 효율성 : 파이프라인은 메모리를 차지하고 실행 속도를 늦추는 중간 목록이나 반복 가능 항목을 생성하지 않으므로 코드 효율성을 향상시킬 수 있습니다. 또한 파이프라인은 지연 평가를 허용합니다. 즉, 데이터가 필요할 때만 작업이 실행되고 이전에는 실행되지 않습니다. 이는 특히 크거나 무한한 데이터 소스를 처리할 때 시간과 리소스를 절약할 수 있습니다.
- 유연성 : 파이프라인은 나머지 코드에 영향을 주지 않고 작업 순서를 추가, 제거 또는 변경할 수 있으므로 쉽게 수정하거나 확장할 수 있습니다. 또한 파이프라인은 필터링, 매핑, 축소, 집계, 그룹화, 정렬 등과 같은 다양한 유형의 작업을 지원하며 이를 다양한 방식으로 결합하여 다양한 결과를 얻을 수 있습니다.
Python에서 파이프라인을 사용하는 방법은 무엇입니까?
Python에서 파이프라인을 생성하고 사용하는 방법:
- 내장 함수 사용: Python은 map, filter, reduce, zip, enumerate, sorted, 등과 같은 파이프라인을 생성하는 데 사용할 수 있는 여러 내장 함수를 제공합니다. reversed이러한 함수는 함수와 반복 가능 항목을 인수로 사용하고 적용되는 새로운 반복 가능 항목을 반환합니다. 원래 iterable의 각 요소에 대한 함수입니다.
- List comprehensions 사용 : List comprehensions는 수학 표기법과 유사한 구문을 사용하여 Python에서 List를 만드는 간결한 표현 방법입니다. List comprehension은 iterable의 각 요소에 작업을 적용하고 새 List에 결과를 수집하여 파이프라인을 만드는 데에도 사용할 수 있습니다.
- generator expressions 사용 : generator expressions는 List comprehensions와 유사하지만 List 대신 generator 개체를 반환합니다. generator 개체는 요소를 메모리에 저장하지 않고 요청에 따라 생성하는 반복 가능 개체입니다. generator expressions는 반복 가능 항목의 각 요소에 일련의 작업을 적용하고 결과를 generator로 생성하여 파이프라인을 생성하는 데에도 사용할 수 있습니다.
이상 파이프라인이 무엇인지, Python에서 파이프라인을 사용하는 방법을 이해하는 데 도움이 되었기를 바랍니다.