파이썬 복습 2

2024. 9. 2. 17:54카테고리 없음

1. 이터러블? 이터레이터? 제네레이터?

가장 먼저 이터러블에 대해 이해해보자. 이터러블은 내부 요소를 하나씩 리턴할 수 있는 객체를 말한다.

우리가 흔히  for을 사용하는 자료형들, 리스트 , 딕셔너리, 셋을 떠올릴 수 있다.

시퀀스 타입이든 ,컬렉션 타입이든 내부 요소를 하나씩 리턴할 수 있다면 이를 이터러블이라고 말할 수 있다.

 

이터레이터는 클래스에서 선언된 __next__() 함수나 내장함수 next()를 통해 원소를  순차적으로 반환할 수 있는 객체들을 말한다.

이터러블은 __iter()__를 통해 이터레이터를 반환할 수 있고 그후 반환받은 이터레이터의 next를 통해 순차적으로 내부요소를 반환할 수 있다.

list = [1,2,3,4]
type(list) # list
iter = iter(list)
type(iter) # list_iterator
next(iter) # 1
next(iter) # 2
next(iter) # 3
next(iter) # 4
next(iter) # StopIteration

iter2 = list.__iter__()
type(iter2) # list_iterator

위는 이터러블인 list 자료형을 이터레이터로 만들어 사용한 예제이다.

 

그리고 확장해서 for문을 사용할때 우리는 이터러블을 이용하는데 이때 내부적으로 받은 이터러블을 이용해 이터레이터를 생성한 후 next를 이용해 StopIteration이 일어나기전까지 순회하는 것을 유추할 수 있다.

우리가 클래스를 만들때 __iter__() 메소드를 내부적으로 만들지 않는다면 for문을 이용할수없다.

dir, hasattr 같은 내장함수로 객체에 __iter__이나 __next__ 가 정의되어있는지 확인할 수 있고 객체의 __iter__ 를 이용해 얻은 객체에 __next__ 가 정의되어있는지 확인해 있다면 이를 이용하는 방식으로 사용될 것이라고 생각했다. 여기서 c언어 배열처럼 그냥 인덱스로 반복문을 사용하지 않는 이유가 궁금했었는데 여러 컬렉션 타입, 시퀀스 타입 객체들을 포괄하여 동작시킬수있는 가장 효율적인 방식이고 여러 자료형들의 메모리가 모두 붙어있다는 보장이 없다는 것을 깨닫고 의문을 지울수있었다.

 

제네레이터의 경우 이터레이터처럼 next로 동작한다. 다른 차이점이 있다면 yield를 통한 동작과정에 있다.

일반적인 이터레이터를 생각해보자.

list = [1,2,3,4,5,6,7,8,9,10] 같이 이미 모든 값이 메모리에 올라가있는경우 이터레이터를 이용해 반복을 수행할 수 있다.

하지만 메모리에 모두 올라간 데이터만을 우리가 처리하지 않는다.

10만개의 수를 만들고 이를 모두 2씩 곱하는 연산을 수행하고 싶을때 미리 리스트를 만들어 메모리에 10만을 준비하여 연산하는 것 보다

그때 그때 수를 만들고 할당된 메모리에 이를 넣는 방식으로 수행할 수 있는 것이다. 이런 수행에 필요한 것이 제네레이터이다.

미리 준비할 필요없이 필요한 데이터만 준비하니 메모리를 효율적으로 사용할 수 있다.

 

일반 반복자는 메모리에 있는 데이터를 보고 하나씩 호출한다.

제네레이터의 경우 필요한 데이터 한가지를 생성,반환하고 다음 호출까지 대기한다. 그리고 next가 일어날때 그다음 데이터를 생성, 반환하고 대기한다. 이와같이 필요한 하나하나씩 반환하고 다음으로 넘어가기때문에 메모리에 저장하는 과정이 따로 필요없게된다. 

 

sum1 = sum([num ** 2 for num in range(1000000)])

sum2 = sum((num ** 2 for num in range(10000000)))

위와같은 경우 sum 매개변수가 메모리에 저장시킬 필요가 없으니 메모리를 위해 리스트 컴프리핸션보다 제네레이터 컴프리핸션을 이용하는 것이 좋을 수 있다.

 

2. 메모리

a = list(range(100000))
a2 = list()

for i in a:
    a2.append(i*2)

1번

 

temp = [x*2 for x in range(100000)]

2번

 

a = list(range(100000))
a2 = map(lambda n: n*2, a)

3번

 

두 예시 중 append로 계속해서 메모리를 재할당 시키는 1번보단 이터러블을 이용한 2번 리스트 컴프리핸션이 유용하다.

3번같은 경우 map 함수가 내부적으로 c로 짜여있어 빠르게 동작하여 효율성이 좋다.


3.  파이썬 가비지컬렉터

일단 가비지컬렉터의 기본적인 틀을 이해하는게 필요하다. 참조횟수 기반으로 동작하는 가비지컬렉터를 제외하고 가비지컬렉터가 수행되려면 응용프로그램이 멈추기때문에 성능에 영향을 미칠 수 있다. 따라서 존재하는 객체의 개수, 동작 주기와 메모리 공간이 어느정도 점유되었을때 동작시킬건지 등 여러 부분을 고려하여 트리거 되는 시점을 정해야한다.

 

당장 가비지컬렉터를 우리가 만든다면 어떻게해야할까?

객체의 참조횟수만 세면 동작시킬수 있지 않을까? 라는 생각을 할 수 있다. 실제로도 참조횟수를 세면서 가비지 컬렉터가 동작한다. 해당 방식은 순환참조가 일어나는 경우 대응하지 못하는 단점이 있고 또 참조횟수를 관리하는것도 비용이 많이들수있다. 장점은 실시간으로 메모리를 해제할 수 있어 다른 방식들과 달리 프로그램이 멈추지 않는다.

#순환참조 예시
a = test() ## a의 참조횟수 1
b = test() ## b의 참조횟수 1
a.test = b ## b의 참조횟수 2
b.test = a ## a의 참조횟수 2

del a
del b

#객체가 사라졌는데 a와 b의 참조횟수는 모두 1

 

다른 방식으로 살아있는 객체에서 참조할 수 있는 모든 곳을 마크하고 존재하는 모든 객체에 마크가 안되어있는 부분을 해제하는 마크앤 스윕방식도 있다. 해당 방법은 순환 참조문제 또한 해결할 수 있다.

또 복사 방식도 있다. 메모리 공간을 두 부분으로 나누고 한쪽만 사용하다가 메모리가 다차면 살아있는 객체만 나머지 한쪽으로 옮기고 찬부분을 한번에 회수하는 방식이다.

이를 혼합한 방식으로 세대별 가비지컬렉터가 있는데 짧은 생명 주기를 가진 세대와 긴 생명 주기를 가진 세대로 나눠  짧은 생명 주기를 가진 세대는 복사 방식을, 긴 생명 주기를 가진 세대는 마크앤 스윕을 채택하는 것을 생각해볼 수 있다.

이러한 방식들은 프로그램 메모리를 스캔하고 선별하는 만큼 복잡하고 프로그램이 멈추게 된다.

 

파이썬의 경우 참조 횟수 기반 가비지 컬렉터와 세대별 가비지 컬렉터를 사용한다. 파이썬은 3세대로 객체를 관리하고 세대별 객체 개수를 넘으면 세대별 가비지 컬렉터가 동작된다.

 

 

 

파이썬 리스트 내부 구조

C언어의 배열과 파이썬의 리스트는 같은 자료형이지만 파이썬의 리스트가 훨씬 사용하기 편리하다. 그 이유는 아래와 같다.

seoyeonhwng.medium.com

 

 

파이썬 클린 코드 - 7장 (제너레이터)

1. 제너레이터 만들기 제너레이터는 파이썬에서 고성능이면서도 메모리를 적게 사용하는 반복을 위한 방법이다. 제너레이터는 한 번에 하나씩 구성요소를 반환해주는 이터러블을 생성해주는

monsterkos.tistory.com

 

파이썬(python) - 이터레이터(Iterator)

이터레이터(Iterator)란? 이터레이터는 순서대로 다음 값을 리턴할 수 있는 객체를 의미합니다. 자체적으로 내장하고 있는 next 메소드를 통해 다음 값을 가져올 수 있습니다. 여기서 '순서대로'라

tibetsandfox.tistory.com

 

03) 제너레이터

[TOC] ## 잘못된 일처리 방식 어떤 빵가게에서 제빵사가 빵을 굽고 점원이 이를 포장하고 있습니다. 제빵사는 빵가게 문을 열기 전까지 빵 100개를 만들어야 하는데 빵이…

wikidocs.net

 

 

Memory Management in Python (2) - Python 가비지 컬렉터

https://www.honeybadger.io/blog/memory-management-in-python/ Memory Management in Python Understanding memory management is a superpower that will help you design memory-efficient applications and make it easier to debug memory issues. Join Rupesh Mishra f

sysgongbu.tistory.com

 

 

 

[Python] 반복자(Iterator), 제너레이터(Generator)에 대한 이해

파이썬에는 원소를 받을 수 있는 다양한 자료구조가 있다. 특히 리스트, 딕셔너리 등은 여러 원소를 처리하는 대표적인 자료구조이다. 원소는 기본적으로 정적으로 만들어져서 반복 가능한 반

cheony-y.tistory.com

 

 

10_메모리 관련

##메모리 주소 알아내기 ``` >>> id(2) 4484212032 ``` 16진법으로 나타내면 다음과 같다. ``` >>> hex(id(2)) ‘0x10b47a…

wikidocs.net