본문 바로가기
DEV/Web 개발

Web 개발 :: DRF 리뷰, 파이썬 and와 &의 차이 _TIL#51

by 올커 2022. 11. 16.

■ 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를 사용하는 습관을 가져야겠다. 서로 사용목적이 다른 것이기 때문에 구분하여 사용해야 오류를 최소화 할 수 있을 것 같다.

반응형

댓글