[python]리스트 컴프리핸션에서 if문 사용하기

리스트 컴프리핸션(list comprehension)이란 pythonic 하다고 표현되는 대표적인 문법 중에 하나이다. 꽤 간단한 방법으로 리스트를 만들 수 있다는 장점이 있다. 기본적으로 for문을 사용하기 때문에 반복할 수 있는 iterator나 generator와 함께 사용되는 것이 일반적이다.

list comprehension을 사용할때 if문을 사용하면 조건에 맞는 데이터를 가지고 리스트를 만들 수 있는데 이때 if문을 사용하는 방법에는 두 가지 정도가 있는 것 같다. 이 두 가지 방법에 대해서 정리한다.

조건에 맞는 리스트 만들기

만약 a라는 리스트에서 짝수인 데이터만 가지고 새로운 리스트(b)를 만들어야 한다면 아래와 같이 할 수 있다.

1
2
3
4
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

b = [num for num in a if num % 2 == 0]
# [2, 4, 6, 8, 10]

for문 뒤에 if문을 적어주면 된다.

삼항연상 이용

if ... else ... 삼항연산을 이용하면 조건에 해당할 때와 해당하지 않을때에 대해서 리스트 컴프리핸션을 사용할 수 있다. 짝수면 그대로 두고 홀 수 일때 10을 곱하는 컴프리핸션은 다음과 같이 작성할 수 있다.

1
2
3
4
5
6
7
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

b = [
num if num % 2 == 0 else num * 10
for num in a
]
# [10, 2, 30, 4, 50, 6, 70, 8, 90, 10]

정리

리스트를 만들때 조건이 복잡하지 않다면 리스트 컴프리핸션을 사용하는 것이 권장된다. 간단한 조건이라면 삼항연산과 함께 리스트 컴프리핸션을 사용해도 되지만 그렇지 않을 경우 조건을 판단하는 함수를 따로 만들어서 삼항 연산을 대체하거나 다른 방법을 찾는 것이 좋을 것 같다.

Share

[Django]values와 values_list의 차이

Django ORM 최적화 중 하나로서 필요한 필드의 값만 가져오기 위해 values()values_list()를 사용한다. 각 메소드의 결과는 어떻게 생겼고 차이점이 무엇인지 정리해본다.

values()

쿼리셋의 값을 딕셔너리 형태로 반환한다. queryset에 대해서 사용하기 때문에 순서는 그닥 상관 없는 것 같다.

1
2
3
4
5
Post.objects.values().filter(id__lt=8)
# <QuerySet [{'id': 5, 'title': 'post #1'}, {'id': 6, 'title': 'title #1'}, {'id': 7, 'title': 'title #2'}]>

Post.objects.filter(id__lt=8).values()
# <QuerySet [{'id': 5, 'title': 'post #1'}, {'id': 6, 'title': 'title #1'}, {'id': 7, 'title': 'title #2'}]>

만약 아래와 같이 values() 메소드에 인자로서 필드명을 넣으면 필드: 값의 형태로 가져올 수 있다.

1
2
Post.objects.filter(id__lt=8).values('title')
# <QuerySet [{'title': 'post #1'}, {'title': 'title #1'}, {'title': 'title #2'}]>

values_list()

쿼리셋의 값을 튜플 형태로 반환한다.

1
2
Post.objects.filter(id__lt=8).values_list()
# <QuerySet [(5, 'post #1'), (6, 'title #1'), (7, 'title #2')]>

마찬가지로 values_list()에 인자로서 필드를 넣으면 해당 필드의 값만 튜플로 반환한다.

1
2
Post.objects.filter(id__lt=8).values_list('title')
# <QuerySet [('post #1',), ('title #1',), ('title #2',)]>

values_list()에는 필드명 이외에 flat이라는 인자를 사용할 수 있다. flat은 Boolean 타입이며 기본값은 False이다. flat의 역할은 튜플이 아닌 리스트로 필드의 값을 반환하는 것이다. 주의사항으로 flat 인자는 필드가 여러개일때 사용할 수 없다.

1
2
3
4
5
Post.objects.filter(id__lt=8).values_list(flat=True)
# <QuerySet [5, 6, 7]>

Post.objects.filter(id__lt=8).values_list('title', flat=True)
# <QuerySet ['post #1', 'title #1', 'title #2']>

정리

ORM을 사용하면 매우 편리하게 DB를 사용할 수 있어서 좋지만 때로는 비합리적으로 동작할때가 있어 대용량 데이터를 다룰때 문제가 될 수 있다. values()values_list()는 ORM 쿼리 최적화의 방법 중 하나로서 필요한 필드의 값만 가져올 수 있고, 따라서 DB에 부하를 줄일 수 있다는 점을 알고 있자.

Share

[Django]not 연산으로 조건 부정하기

Django에서 not 연산을 사용하기 위해서는 다음과 같은 연산자를 사용한다.

  1. not
  2. ~

if문과 같은 조건절이라면 not을 사용할 수 있지만 queryset.filter()queryset.get()에서는 어떻게 해야할까?

Django에서 not 연산을 사용하기 위해서는 아래의 두 메소드를 사용하면 된다.

  1. exclude()
  2. filter(~Q(조건))

exclude()의 경우 queryset에서는 기본적으로 사용가능하며, ~Q(조건)의 형태로 사용하려면 Q를 임포트해야한다.
(from django.db.models import Q 임포트 문을 통해 가져올 수 있다.)

exclude()

기본적으로 queryset의 객체라면 not 연산을 사용하기 위해서 exclude() 메소드를 사용할 수 있다.

1
projects = Project.objects.exclude(title__startswith='hello')

~Q(condition)

Q를 임포트하여 ~ 기호를 사용해 not 연산을 할 수 있다.

1
2
3
from django.db.models import Q

projects = Projects.objects.filter(~Q(title__startswith='hello'))

[참고]
https://django-orm-cookbook-ko.readthedocs.io/en/latest/notequal_query.html

Share