파이썬의 이터레이터(iterator)

파이썬의 이터레이터(iterator)

파이썬의 이터레이터는 next() 라는 특별 메소드를 호출함으로써 컨테이너 안에 있는 값들을 차례대로 순회할 수 있는 객체이다.

iterator의 원리

파이썬의 iter() 내장 함수는 객체의 __iter__ 메소드를 호출하며, __iter__ 메소드는 해당 컨테이너의 iterator를 리턴해야 한다. 그리고 __iter__로 반환된 iterator는 __iter__와 __next__를 구현해야만 한다. 역으로 iter와 next를 둘 다 구현하고 있는 객체를 iterator의 객체라고 볼 수 있다!

iterator의 특성

iterator 객체는 반드시 __next__ 메소드를 구현해야 한다. 파이썬 내장함수 iter()는 iterable 객체에 구현된 iter를 호출함으로써 그 iterable 객체의 iterator 객체를 리턴한다. 이때 iter() 메소드가 리턴하는 iterator는 동일한 클래스 객체가 될 수도있고 따로 작성된 iterator 객체가 될 수도 있다!!

주의!

구현하는 클래스가 iterator 이려면 __iter__와 __next__를 함께 구현해야하고

단순히 iterable 하기만 해도 된다면 __iter__만 있어도 된다

클래스에 __iter__가 구현되어 있다면 iterable 객체이다.

1
2
3
4
5
6
7
8
import collections

class A:
def __iter__(self):
return self

a = A()
isinstance(a, collections.abc.Iterable) # True

__iter__ 메소드는 iterator 객체를 반환해야만 한다!!

클래스를 구현하면서 iter 메소드가 리턴하는 iterator에는 두 가지 방법이 있다

  • iterable이자 iterator인 클래스라면 __iter__는 self를 리턴한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# NewRange 클래스는 iterable 이면서 iterator 이다
class NewRange:

def __init__(self, end):
self.start = 0
self.end = end

def __iter__(self):
return self

def __next__(self):
if self.start < self.end:
value = self.start
self.start += 1
return value
else:
raise StopIteration

num_list = NewRange(11)
for n in num_list:
print(n, end=' ') # 0 1 2 3 4 5 6 7 8 9 10
  • 단지 iterable한 클래스라면 __iter__ 함수는 따로 구현된 iterator를 리턴하는 객체를 리턴해야한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 위의 NewRange 클래스에 이어서...

# newRangeFactory 클래스는 iterable 하며 내부의 __iter__ 메소드는
# iterator 객체를 리턴해야 한다
class NewRangeFactory():

def __init__(self, end):
self.start = 0
self.end = end
def __iter__(self):
return NewRange(self.end)

a = NewRangeFactory(11)
a_iter = iter(a)

for n in a_iter:
print(n, end=' ') # 0 1 2 3 4 5 6 7 8 9 10

[참고]

https://www.flowdas.com/blog/iterators-in-python/index.html

http://pythonstudy.xyz/python/article/23-Iterator%EC%99%80-Generator

Share

파이썬3의 iterable과 iterator

파이썬의 iterable과 iterator

iterable

iterable은 반복 가능한 것을 의미한다. 대표적인 iterable한 타입은 list, tuple, set, dict, str, bytes, range가 있다. 즉, 반복 연산이 가능하며 요소를 하나씩 리턴할 수 있는 객체를 의미한다.

iterable 객체 - 반복 가능한 객체

range()도 iterable 하기 때문에 for _ in range(1, 11): 과 같은 표현이 가능했던 것이다.

객체가 iterable 한지 판별하기 위해서 collections.Iterable의 인스턴스인지 확인해보면 된다.

1
2
3
4
5
6
7
8
9
10
11
import collections

first = range(1, 11)
isinstance(first, collections.Iterable) # True

# 파이썬 3.8부터 collections가 deprecated 되기 때문에
# collections.abc를 import 하는게 좋다
import collections.abc

second = 345
isinstance(second, collections.abc.Iterable) # False

iterator

iterator는 next() 함수로 데이터를 순차적으로 호출 할 수 있는 객체이다. next()로 데이터를 순회하다가 더 이상 멤버가 존재하지 않을 시 StopIteration 예외를 발생시킨다.

iterator를 만드는 방법에는 두 가지가 있다.

  • iterable한 객체에 파이썬 내장함수 iter()를 사용해서 만든다.
1
2
3
a = [1, 2, 3]
a_iter = iter(a)
type(a_iter) # list_iterator
  • iterable 객체의 메소드를 사용한다.
1
2
3
4
5
6
b = 1, 2, 3
dir(a)
# ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

b_iter = b.__iter__()
type(b_iter) # tuple_iterator

다시 말해, iterator는 iterator protocol를 준수해야하며 __iter__와 __next__ 메소드가 있어야 한다!!

그렇다면 list는 iterator 객체일까?

list가 iterator인지 확인해보기 위해 next() 메소드를 호출해보자

1
2
3
a = [1, 2, 3]
next(a)
# TypeError: 'list' object is not an iterator

list 객체는 iterator가 아니라고 TypeError가 발생한다. 즉 파이썬의 list는 iterator가 아니다. iterator가 아니지만 어떻게 데이터를 순회하면서 차례대로 요소를 반환할 수 있는 것일까?

1
2
3
4
5
6
a = [1, 2, 3]
for n in a:
print(n)
# 1
# 2
# 3

iterator가 어떻게 동작하는 지 이해한다면 for 루프의 작동방법을 이해하는 데에도 도움이 된다.

1
2
3
num_list = [1, 2, 3, 4, 5]
for n in num_list:
print(n, end=" ") # 1 2 3 4 5

num_list는 list이기 때문에 iterator가 아니며 순회하면서 값을 하나씩 반환할 수 없다고 생각할 것이다. 하지만 for문은 for * in iterable 형태로써 받은 iterable 객체의 __iter__을 호출해서 임시적으로 iterator를 생성 후 사용하기 때문에 iterator가 아닌 객체도 for 루프에서 사용 가능한 것이다.

iterable 객체이지만 iterator 객체는 아닐 수도 있음에 주의하자!!!!!!

iterator가 데이터를 순회하며 값을 하나씩 반환한다는 것의 의미

iterator는 __iter__와 __next__가 구현되어 있는 객체를 말하고 __next__ 메소드를 사용함으로써 데이터를 순회하면서 요소 하나씩을 리턴할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a = [1, 2, 3]
a_iter = iter(a)

next(a_iter) # 1
next(a_iter) # 2
next(a_iter) # 3
next(a_iter) # StopIteration

a_iter2 = a.__iter__()

a_iter2.__next__() # 1
a_iter2.__next__() # 2
a_iter2.__next__() # 3
a_iter2.__next__() # StopIteration

짧게 정리해보자면,

list와 같은 컨테이너는 iterable 객체이지만 iterator 객체는 아니다. 즉, 반복 가능하지만 iterator 객체는 아닐수도 있다는 점이다!!!


[참고]
https://kkamikoon.tistory.com/91
https://python.bakyeono.net/chapter-7-4.html
https://github.com/python/cpython/blob/master/Objects/listobject.c
https://bluese05.tistory.com/55
http://pythonstudy.xyz/python/article/23-Iterator%EC%99%80-Generator
https://hackersstudy.tistory.com/9
https://ziwon.dev/post/python_magic_methods/
https://suwoni-codelab.com/python%20%EA%B8%B0%EB%B3%B8/2018/03/07/Python-Basic-Iterable-iterator/
https://offbyone.tistory.com/83
https://haerakai.tistory.com/34
https://www.flowdas.com/blog/iterators-in-python/index.html
https://mingrammer.com/translation-iterators-vs-generators/
https://dojang.io/mod/page/view.php?id=2412
https://www.youtube.com/watch?list=PLa9dKeCAyr7iWPMclcDxbnlTjQ2vjdIDD&v=1jo5dj672-M
https://dojang.io/mod/page/view.php?id=2412

Share

ubuntu 16.04 LTS에 uwsgi 서비스 등록하기

ubuntu 16.04 LTS에 uwsgi 서비스 등록하기

nginx + uwsgi + django를 배포하다보면 uwsgi를 수동으로 구동하곤한다. 단지 배포과정을 공부하는 입장에서는 이 정도면 충분하다고 생각했다. 하지만 문제점이 있었는데 서버를 재부팅하면 nginx는 저절로 구동되지만 uwsgi는 그렇지 않았다. 그리 복잡하지 않았기에 수동으로 돌려주고 터미널을 끄는 식으로 하곤했지만 현재 운영하고 있는 서비스의 안정성을 위해서 systemd에 등록하는 방법으로 변경했던 과정을 정리한다.

uWSGI 자동실행하기

uWSGI 서비스 설정파일 작성

리눅스 서비스에 등록하기 위해서는 서비스 파일을 작성해야한다. 파일 경로는 /etc/systemd/system/uwsgi.service 에 하면된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=uWSGI
After=syslog.target

[Service]
ExecStart=/root/uwsgi/uwsgi --ini /etc/uwsgi/sites/myproject.ini # ini의 경로로 입력
# Requires systemd version 211 or newer
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target

uwsgi의 systemd 공식문서를 참고했다. uwsgi를 미리 만들어준 ini파일과 실행하는 부분에 집중하자. 쉘에서 uwsgi를 실행하기 위해 입력하는 명령어와 다른 점은 uwsgi의 경로를 절대경로로 적어준 것이다. 그냥 uwsgi로만 적게되면 absolute path가 아니라는 에러가 발생하게 되는데 이게 주된 이유인지는 확실하지 않다. 어찌됐든 uwsgi가 설치된 절대경로를 통해 실행해야 한다는 것에 유의하자.

1
2
# uwsgi가 설치된 절대경로와 옵션으로 입력할 ini 파일의 절대경로에 주의하며 적자.
ExecStart=/root/uwsgi/uwsgi --ini /etc/uwsgi/sites/myproject.ini

서비스 파일 작성을 마쳤다면 이 파일을 가지고 등록과정을 거치면 된다. 여러가지 방법이 있는 것 같은데 간단하게 등록할 수 있는 방법을 먼저 익혀보았다.

1
2
sudo systemctl start uwsgi.service # uwsgi.serivce 실행
sudo systemctl enable uwsgi # 심볼릭 링크 생성

enable 명령은 심볼릭 링크를 생성해주며 서비스에 등록되어 시스템을 재부팅하게 될 경우 uwsgi.service를 다시 실행시켜주는 것 같다.

Share