[python] lazy evaluation?

Mun Lee·2020년 6월 30일
1

Generator(제너레이터)는 함수고 값을 반환은 하지만, 산출(yield)를 한다는 차이점이 있다. 이터레이터를 생성해주는 함수라고 볼 수 있다.

yield는 값(변수)을 지정한다. yield 값

0,1,2 세 숫자를 출력하는 코드를 만들어보자

def number_generator():
	yield 0
    yield 1
    yield 2
for i in number_generator():
	print(i)

을 하면은

0
1
2

이 출력되어 나온다. 이렇게 함수로 만든 객체가 정말 이터레인지 확인하는 방법은 dir함수로 확인해볼수 있다.
g= number_generator()
print(g)

<generator object number_generator at 0x7fb0c5034120>

print(dir(g))을 하면

['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] 

사용가능한 메서드들이 들어있고 거기에 iternext가 들어있는 걸로 봐서 이터레이터인걸 알 수 있다.

다음 함수는 숫자 1을 반환하고 반환하기 전에 return 1 문자열을 출력한다.

def return_one():
	print("return 1")
    return 1

그 다음에 return_one 10번 수행을 통해 숫자 1을 10개 담는 리스트도 만들 수 있다.

one_list = [return_one() for x in range(10)]

저기서 return_one()함수가 실행이 되는 것이고, 실행되면서 print문은 실행되고 return 1을 통해 리스트에 1이 넣어진다.
list에 들어있는 값을 출력해보면

for one in one_list:
	print(one)

이번에는 리스트로 하지마로 generator을 활용해보자

def return_two():
    print("숫자 2를 반환합니다.")
    return 2
    
print("제너레이터로 만들어보자구!")
two_generator = (return_two() for x in range(10))

print("프린터가즈아~")
for two in two_generator:
    print(two)

for 문을 [] 에서 ()로 바꾸면 제너레이터가 된다.
[] -> 리스트 {} -> 셋 () -> 제너레이터 : 기억해라~
이렇게 실제로 값을 출력하기전에 함수를 실행하지 않다가 수행하는 순간 출력이 되는 것을 알수 있다. 실제로 값을 사용하지 않고 사용될때만 쓴다면 시간과 메모리를 절감할 수 있다. 이게 lazy_evaluation의 특징이자 장점이라고 할 수 있다.

L = [1,2,3]
import time

def print_iter(iter):
    for element in iter:
        print(element)

def lazy_return(num):
    print("sleep 1s")
    time.sleep(1)
    return num

이러한 예가 있는데

print("comprehension_list=")
comprehension_list = [ lazy_return(i) for i in L ]
print_iter(comprehension_list)

list로 받아주었고 결과를 보면

comprehension_list=
sleep 1s
sleep 1s
sleep 1s
1
2
3

반면에 이렇게 제너레이터로 해주게 된다면

print("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)
generator_exp=
sleep 1s
1
sleep 1s
2
sleep 1s
3

이렇게 된다.
list 컴프리헨션과 제너레이터의 차이점은 [] 와 ()로 별로 커보이지 않을수가 있지만, 나중에 코드양이 어마어마하게 늘어나게 되었을때는 메모리의 효율성은 중요한 부분이기 때문에 앞으로 만나게 되더라도 당황하지않고 제너레이터구나 인지하고 사용할줄 아는 개발자가 되도록하자.

profile
개발자가 되고자 하는 30살

0개의 댓글