파이썬에서 list는 가장 많이 사용하는 자료구조 중에 하나라고 할 수 있습니다.


tuple은 list에 비해 빈번하게 이용되지는 않지만 tuple 만의 장점을 가지고 있는 자료구조입니다.


이 두 자료구조에 대해 자세히 알아보도록 하겠습니다.






자료구조를 공부해야하는 이유는 궁극적으로 좋은 성능을 내는 코드를 작성하기 위해서 입니다.



현재 개발하고 있는 프로그램에 맞는 자료구조를 선택함으로써 성능을 높일 수 있습니다. 빈번한 데이터 변환은 프로그램의 성능을 떨어뜨리기 때문입니다.


사실 성능을 고려한 프로그래밍에서는 어떤 데이터를 어떻게 다룰를 고민하고, 그 상황에서 빠르게 작동하는 자료구조를 선택하는 일이 큰 비중을 차지합니다.


그래서 어떤 상황에서 리스트를 사용하고, 튜플을 사용하는지 어떻게 동작하는지 공부해야합니다.





리스트와 튜플은 배열이라고 하는 자료구조의 한 종류입니다.



C 언어에서 처럼 배열은 


어떤 정해진 순서에 따라서 데이터를 나열해 둔 것입니다. 그렇기 때문에 순서를 알고 있으면 O(1) 시간 복잡도로 데이터에 접근할 수 있습니다.


리스트와 튜플은 배열의 한 종류로 리스트는 동적으로 생성되는 배열이고, 튜플은 정적으로 생성되는 배열입니다.



배열이 할당되면 시스템 메모리에 블록이 할당되고, 정해진 순서에 따라 각 블록에 데이터를 가리키는 주소를 저장합니다.


+ 리스트의 경우는 메모리에 리스트의 길이까지도 저장합니다.



위에서 언급한 것 처럼 기본적으로 순서를 알고 있다고 가정하면 시간 복잡도는 O(1)이기 때문에 배열의 길이에 상관없이 접근하는 시간은 거의 비슷합니다.




하지만, 위 상황과 다르게 순서를 모른다면 원하는 데이터를 찾기 위해 선형적으로 배열에 접근해야 하기 때문에


최악의 경우(찾지 못하는 경우 마지막 인덱스 까지 탐색) O(n)의 시간복잡도를 갖습니다.




그렇다면 더 효율적인 탐색을 위해서는 어떻게 해야 할까요?


그 동안 많이 들어왔던 이진 탐색을 이용하면 시간복잡도가 O(logn) 이지만 이는 정렬된 리스트에서만 이용할 수 있습니다.



정렬이 되어 있다는 전제하에 O(logn)의 시간복잡도로 데이터의 인덱스를 얻을 수 있습니다.


리스트를 정렬하는 방법으로는


1) quick sort

2) merge sort

3) bubble sort 

4) inser sort 


등 이있고,


list 의 멤버함수인 list.sort 의 경우 Tim Sort를 이용합니다. (tim sort는 insert sort와 merge sort를 조합해서 사용합니다.)



+ 정렬이 되어 있다는 전제하에 bisect 모듈을 이용하면 이진 탐색 기법으로 인덱스를 찾고, 또 정렬을 유지하면서 데이터를 삽입할 수 있습니다.


이는 나중에 기회가 된다면 따로 공부하여 포스팅 할 예정입니다.




이제 list와 tuple 을 본격적으로 비교해 보도록 하겠습니다.



먼저 대다수 분들이 알듯이


list 는 동적 배열이기 때문에 배열을 추가하거나 변경할 수 있습니다.


이에 반해, tuple은 정적 배열로 배열을 추가하거나 변경 할 수 없습니다.



여기 까지만 생각하면 생각없이 list를 사용하는 것이 좋습니다. 배열을 바꿀 경우가 아주 빈번하게 있기 때문이죠.


하지만 list가 가지고 있는 단점과 tuple이 가지고 있는 장점이 있습니다.



1)  list는 동적 배열이기 때문에 배열의 늘어날 것을 대비해서 미리 여분의 메모리 공간을 할당해 놓습니다.


    그렇기 때문에 10개의 항목인 리스트를 생성해도 16개 항목만큼 메모리를 사용하게 됩니다. 


    배열의 개수가 10,000개 라고 하면 160,000개의 항목만큼의 메모리를 사용하게 됩니다.


    하지만, tuple은 딱 100,000개의 항목만큼의 메모리를 사용합니다.



2) tuple은 크기가 20이하인 경우 파이썬의 캐싱 메모리에 저장되기 때문에 GC(Garbage collector)에 의해서 메모리가 회수되지 않기 때문에


    재사용하는 경우 빠르게 생성이 가능하다.


 


- 참조자료


*고성능파이썬 

http://www.yes24.com/searchcorner/Search?keywordAd=&keyword=&domain=ALL&qdomain=%C0%FC%C3%BC&Wcode=001_005&query=%B0%ED%BC%BA%B4%C9+%C6%C4%C0%CC%BD%E3


* askdjango 강의자료 ( http://nomade.kr )



잘못된 내용이 있거나 부족한 내용이 있으면


 댓글로 알려주시면 감사하겠습니다.



감사합니다.











 파이썬에서 class에는 3가지 함수 형식이 있다는 것을 모두 알고 계셨나요?


저 같은 경우는 프로젝트나 책을 공부하면서 @staticmethod , @classmethod 등을 자주 만나기는 했지만 이렇게 나눠져 있다는 것을 잘 모르고 있었습니다.


이번 기회에 정리하면 좋을 것 같아서 정리하게 됐습니다.


 

파이썬 클래스의 3가지 함수 



1 . Instance method 


: instance 를 통한 호출. 즉 , 클래스로 생성한 인스턴스의 멤버함수 동작한다고 생각할 수 있습니다.


  첫 번째 인자로 instance가 자동으로 지정되어 self에 대입 됩니다.



instance 함수와 같은 경우 각 instance 가 독립적으로 수행이 필요한 경우 사용 하면 좋을 것 같습니다.


예를 들면 , 유저의 패스워드를 check 하는 함수는 password를 입력 받아 각 인스턴스의 패스워드와 비교해야 하기 때문에


인스턴스 별로 독립적으로 수행되어야 합니다. (실제 패스워드를 체크 하는 경우 hashing 작업 후 비교해야 하기 때문에 밑의 예시 처럼 동작하지 않습니다.)


class User(object):


~~~~~~~~~~~


@예시

def check_password(self, password):

if self.password == password

return True



2. static method


: class를 통해 호출 됩니다. 자동으로 지정되는 인자가 없고, 활용은 class method와 동일하게 사용됩니다.



User 를 예로들면 개발시에 한 번에 여러 인스턴스를 생성할 수 있으면 편리합니다.


아래 예시는 flask 코드입니다. forgery_py 라는 객체 생성시 적당한 값을 채워주는 라이브러리를 이용해서 


유저 100명을 한 번에 생성할 수 있습니다.


class User:

@staticmethod
def generate_fake(count=100):
from sqlalchemy.exc import IntegrityError
from random import seed
import forgery_py

seed()
for i in range(count):
u = User(email=forgery_py.internet.email_address(),
user_name=forgery_py.internet.user_name(True),
password=forgery_py.lorem_ipsum.word(),
confirmed=True,
name=forgery_py.name.full_name(),
location=forgery_py.address.city(),
about_me=forgery_py.lorem_ipsum.sentence(),
member_since=forgery_py.date.date(True))
db.session.add(u)
try:
db.session.commit()
except IntegrityError:
db.session.rollback()



3. class method


: static method와 같이 class를 통해 호출합니다. 첫 번째 인자로 class가 자동 지정되어 cls 예 대입되어 집니다.


위의 코드가 class method를 이용해서 작성 시 밑에와 같이 작성되어 질 수 있습니다.

장점은 재사용할 수 있지 않을까 생각이 됩니다. 다른 모델 class 에서도 사용할 수 있기 때문에

재사용 가능한 클래스 함수일 경우는 class method로 작성하는 것이 좋을 것 같다는 생각이 듭니다.

@classmethod
def generate_fake(cls, count=100):
from sqlalchemy.exc import IntegrityError
from random import seed
import forgery_py

seed()
for i in range(count):
u = cls(email=forgery_py.internet.email_address(),
user_name=forgery_py.internet.user_name(True),
password=forgery_py.lorem_ipsum.word(),
confirmed=True,
name=forgery_py.name.full_name(),
location=forgery_py.address.city(),
about_me=forgery_py.lorem_ipsum.sentence(),
member_since=forgery_py.date.date(True))
db.session.add(u)
try:
db.session.commit()
except IntegrityError:
db.session.rollback()




파이썬 클래스의 3가지 함수 형식에 대해 공부해봤습니다.


항상 조언이나 궁금하신게 있으시면 남겨주세요.


감사합니다.





Django 나 flask에서 장식자를 사용하는 경우 


from functools import wraps 


@wraps 를 사용하는 것을 자주 볼 수 있습니다. 


예를 들어, flask 에서 user의 permission 을 검사하는 장식자 코드를 보면


def permission_required(permission):

    def decorator(f):

        @wraps #여기 왜 wraps 를 넣어줘야 하지...

        def decorated_function(*args, **kwargs):

            if not g.current_user.can(permission):

                return forbidden('insufficient permissions')

            return f(*args, **kwargs)

        return decorated_function

    return decorator


다음과 같이 작성합니다.


하지만, 저기서 @wraps 를 쓰지 않아도 decorator의 동작은 같습니다.



결론부터 이야기하면 @wraps 를 사용하면 debugging 시에 유리합니다 !



무슨 말인지 코드를 통해 확인해 보겠습니다.



어떤 함수의 결과에 i를 더해주는 장식자를 만들어서 적용했습니다.


@wraps 를 사용하지 않으면


decorated function 즉, 장식자를 적용해서 실제 수행하는 함수의 이름과 정보를 알 수가 없습니다.





반면에, @wraps를 이용하면, decorated function의 이름과 그리고 정보를 그대로 전달 받을 수 있기 때문에 디버깅시에 유리합니다.


@wraps의 역할은 쉽게 생각하면 wrapper 함수의 정보를 사용할 수 있도록 전달해주는 역할을 한다고 생각하면 될 것 같습니다.



조언이나 피드백은 언제나 환영입니다. 


감사합니다. 





+ Recent posts