Python Lazy Evaluation
Lazy Evaluation
어떤값이 실제로 쓰일때 까지 그값의 계산을 뒤로 미루는 동작 방식이다.
이는 Generator라는 배경지식이 있어야 선행되어야 이해하기 수월하다.
다음과 같은 코드가 있다.
def return_one():
print("return 1")
return 1
print("[let's make one_list !]")
one_list = [return_one() for x in range(10)]
print("[let's print one_list !]")
for one in one_list:
print(one)
출력결과
[let's make one_list !]
return 1
return 1
return 1
return 1
return 1
return 1
return 1
return 1
return 1
return 1
[let's print one_list !]
1
1
1
1
1
1
1
1
1
1
one_list를 출력하기 전에 미리 함수 10번이 실행되어 값을 다 만들어 리스트에 저장해놓았다.
이번에는 리스트대신 generator로 값을 생성한다.
list comprehension에서 대괄호만 소괄호로 바꾸어주면 generator expression이 된다.
그후 실행한 결과이다.
[let's make one_generator !]
[let's print one_generator !]
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
return 1
1
이전의 경우와 달리 실제로 값을 출력하기 전에는 ‘return_one’함수가 한 번도 실행되지 않았다.
generator를 사용했을 때에는,
실제로 one_generator의 값을 사용하는 순간에만 함수를 수행하고있다.
즉, 값이 실제로 사용되지 않으면 연산 또한 하지 않으므로 시간과 메모리를 절약할 수 있다.
다른 예제로 예를 들어 본다.
import time
import random
counter = random.randrange(1, 11) # 1부터 10사이의 랜덤 값 생성
print("counter: {}".format(counter))
def return_one_after_five_sec():
print("please wait for 5 seconds")
time.sleep(5)
print("return 1")
return 1
print("[let's make one_list !]")
one_list = [return_one_after_five_sec() for x in range(10)]
# counter 숫자만큼 값 출력
print("[let's print one_list !]")
for item in one_list:
counter -= 1
print(item)
if counter == 0:
break
실행 결과
counter: 1
[let's make one_list !]
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
please wait for 5 seconds
return 1
[let's print one_list !]
1
Process finished with exit code 0
50초에 걸쳐서 리스트를 미리 만들어놨는데 단 한개의 값만 사용했다.
비효율적이다. 이와같은 상황의 경우 list보다는 generator로 만들어놓는게 효율적이다.
import time
import random
counter = random.randrange(1, 11) # 1부터 10사이의 랜덤 값 생성
print("counter: {}".format(counter))
def return_one_after_five_sec():
print("please wait for 5 seconds")
time.sleep(5)
print("return 1")
return 1
print("[let's make one_generator !]")
one_generator = (return_one_after_five_sec() for x in range(10)) # generator 생성
# counter 숫자만큼 값 출력
print("[let's print one_generator !]")
for item in one_generator:
counter -= 1
print(item)
if counter == 0:
break
실행결과
counter: 1
[let's make one_generator !]
[let's print one_generator !]
please wait for 5 seconds
return 1
1
단 한번만 실행되는경우인데, 미리 값을 만들어놓지 않은 덕분에 5초만에 작업을 마무리했다.
list로 값을 만들었을때에 비해 무려 9배의 성능 향상이 발생한것이다.
사소해보이지만 이런것들을 미리 알고있다면 필요한 상황에 적재적소로 사용할수있을것이다.
하지만 모든 요소가 , 혹은 대부분의 요소가 사용될것으로 확실한 상황이라면
list 로 미리 연산해두는것이 효과적이다.
그러니 나는 전부 Lazy Evaluation 으로 만들꺼야 ! 하면서 generator 를 남발해선안된다.
출처: https://itholic.github.io/python-lazy-evaluation/