■ JITHub 개발일지 51일차
□ TIL(Today I Learned) ::
Django Rest Framework 프로젝트 리뷰, 파이썬 and와 &의 차이
- 플레이리스트 기능에 대한 구현을 복기하는 중에 문제가 발생했다.
- 해당 기능은 여러개의 곡을 한꺼번에 업로드할 시, 중복된 곡이 있을 경우 중복된 곡은 제외하고 등록할 수 있도록 if문을 사용하여 조건에 따라 분기시키는 기능이다.
class PlaylistDetailView(APIView):
permission_classes = [IsAuthenticated]
#플레이리스트에 노래 여러 개 추가(serializer를 못씀...)
def post(self, request, playlist_id):
song_list = list(request.data["id"]) #id값으로 전달
playlist_detail = get_object_or_404(Playlist, id=playlist_id).playlist_detail #해당 플레이리스트 가져옴
exist_list = [] #중복 곡
add_list =[] #추가 곡
for i in range(len(song_list)):
song = Song.objects.get(id=song_list[i])
if playlist_detail.filter(id=song_list[i]).exists():
exist_list.append(song) #중복 곡 존재하면 exist_list에 추가
else:
add_list.append(song) #없으면 add_list에 추가
playlist_detail.add(song) #해당 플레이리스트에 곡 추가
if len(exist_list) == 1 & len(add_list) == 0:
return Response(f"'{exist_list[0].singer}의 {exist_list[0].title}'(이)가 플레이리스트에 이미 추가되어있음", status=status.HTTP_200_OK)
elif len(exist_list) == 1 & len(add_list) == 1:
return Response(f"'{exist_list[0].singer}의 {exist_list[0].title}'(이)가 플레이리스트에 이미 추가되어있며 '{add_list[0].singer}의 {add_list[0].title}'곡이 추가되었음", status=status.HTTP_200_OK)
elif len(exist_list) == 1 & len(add_list) > 1:
return Response(f"'{exist_list[0].singer}의 {exist_list[0].title}'(이)가 플레이리스트에 이미 추가되어있며 {len(add_list)}곡이 추가되었음 ", status=status.HTTP_200_OK)
elif len(exist_list) > 1 & len(add_list) == 0:
return Response(f"'{exist_list[0].singer}의 {exist_list[0].title}' 외 {len(exist_list)-1} 곡이 플레이리스트에 이미 추가되어있음", status=status.HTTP_200_OK)
elif len(exist_list) > 1:
return Response(f"'{exist_list[0].singer}의 {exist_list[0].title}' 외 {len(exist_list)-1} 곡이 플레이리스트에 이미 추가되어있으며 {len(add_list)}곡이 추가되었음", status=status.HTTP_200_OK)
return Response(f"플레이리스트에 노래 {len(add_list)}곡이 추가됨", status=status.HTTP_200_OK)
- 코드를 확인해보면 if 문에서 2가지 기준을 갖고 있다. 이미 존재하는 곡(exist_list)과 추가할 곡(add_list)이다.
- 그런데 문제는 이미 존재하는 곡을 등록하려 했을 때(exist_list == 1, add_list == 0일 경우) 첫 번째 조건은 아래 첫번째 코드의 분기에 해당되어 리턴되어야 하는데 그러지않고 두번째 코드의 분기를 따라 리턴되었다.
if len(exist_list) == 1 & len(add_list) == 0:
elif len(exist_list) > 1 & len(add_list) == 0:
- 각 단계별로 print(exist_list), print(add_list)를 찍어보아도 exist_list == 1, add_list == 0으로 문제가 없었다.
마지막으로 결국 and 조건에 문제가 있지 않은가 검사해보았다.
- 구글링해보니 이런 내용이 있었다.
1) and는 논리연산자이고 &는 비트연산자이다.
2) 논리연산자 and는 Boolean을 다루어 두 조건이 True이면 True를 리턴하고, 둘 중 하나라도 False라면 False를 리턴한다.
3) 비트연산자 &는 두 개의 이진수에서 동일한 위치의 bit가 1인 것들만 1로 계산한다.
- 처음에는 위의 내용을 보고 왜 에러가 났는지 정확하게 이해할 수 없었다. 그런데 해답은 연산 순서에 있었다.
if 1 == 1 and 2 == 2:
print("True")
else:
print("False")
"""
True
"""
if 1 == 1 & 2 == 2:
print("True")
else:
print("False")
"""
False
"""
- 위의 두 코드를 보았을 때 분명 동일해보이지만 결과값이 다르다. 이는 &는 "연산자"라는 특징 때문에 그렇다.
실제로 두 번째 코드는 아래와 같은 순서로 계산되고 있다고 볼 수 있다.
if ((1 ==(1 & 2)) == 2):
print("True")
else:
print("False")
- 1&2는 비트연산결과 0이 된다. (*1은 0001, 2는 0010이기 때문) 1&2를 마친 후 1, 그리고 2와 순서대로 비교하여도 같지 않기 때문에 False가 나온다.
if (1 == 1) & (2 == 2):
print("True")
else:
print("False")
"""
True
"""
- 그렇기 때문에 비트연산자를 사용할 때에는 아래와 같이 괄호를 묶어주면 해결할 수 있다. 하지만 논리 연산의 경우 &가 아닌 and를 사용하는 습관을 가져야겠다. 서로 사용목적이 다른 것이기 때문에 구분하여 사용해야 오류를 최소화 할 수 있을 것 같다.
'DEV > Web 개발' 카테고리의 다른 글
Web 개발 :: 딥러닝 이미지 처리(유화제작) 프로젝트 구현_TIL56 (0) | 2022.11.23 |
---|---|
Web 개발 :: 딥러닝 프로젝트 주제 선정 _TIL55 (0) | 2022.11.23 |
Web 개발 :: DRF 리뷰 _TIL#50 (0) | 2022.11.15 |
Web 개발 :: DRF 리뷰 _TIL#49 (0) | 2022.11.14 |
Web 개발 :: AWS 인스턴스에 도커(Docker) 셋팅 _TIL#48 (1) | 2022.11.11 |
댓글