내장자료형 중에서는 아무래도 리스트를 가장 많이 쓰고 for문 등 반복문을 쓸 일이 있을 때도 전체 '리스트'를 리스트로 만든 다음에 코드를 쓰게 되는 것 같습니다. 그 외 집합은 주로 중복을 쉽게 제거하거나 차집합을 구할 때 쓰게 되는 거 같은데, 튜플은 리스트와 달리 변경을 할 수 없다는 튜플만의 특색을 알고 있음에도 불구하고 그래서 어디에 써야되는지 잘 모르겠더라고요. 어차피 변경이 불필요하면 list에 굳이 제가 append나 pop 등 list 자체를 건드리는 메서드를 쓸 일도 없고, 그럼 튜플을 굳이 써야할 필요가 없는 거 같은데 리스트 대신 튜플을 써야만 하는, (또는 쓰면 좋은) 상황이 어떤 상황이 있을까요? 사실 전혀 쓴 기억이 없다고 생각했는데 이 글 적으면서 생각해보니 머신러닝 좀 공부할 때 사이킷런으로 데이터셋을 test셋과 training셋으로 나눌 때에는 함수 자체가 튜플형으로 반환되어서 a, b, c, d = test_split~~ 이런 식으로 튜플형으로 나오는 결과값을 튜플형 원소 하나하나를 변수 하나하나에 할당해주는 식으로 접했던 적이 있는 거 같긴 합니다...사실 이것도 함수 결과가 그냥 튜플형으로 나온것뿐, 제가 필요해서 쓴 건 아니긴 하네요..
좋은 질문이네요. 저도 어떤 경우에 '반드시' 튜플을 쓰면 좋을까 한참을 생각해봤습니다. 튜플이 가지고 있는 특징이 수정, 추가, 삭제가 불가하다, 즉 immutable 하다는거죠. 바뀔 수가 없으므로 프로젝트 내에서 다른 누군가와 협업을 할 때 튜플을 사용하면 '얘는 건들지 마, 값 바뀌면 안 돼' 라고 따로 커뮤니케이션을 하지 않아도 되겠지요. 물론 그마저도 리스트로 바꿔서 다시 수정해버리면 그만이지만.. 사실 우리가 언제 튜플을 써야 하나, 보다는 파이썬을 하다 보면 자연히 튜플을 사용하게 되는 것 같습니다. 다음과 같이 enumerate 을 쓸 때 for i, v in enumerate(['오예스', '몽쉘']): # i, v 튜플 print(i, v) for 로 받는 i, v 도 괄호는 없지만 콤마로 구분된 튜플 형태로 받아와서 값이 처리될 테구요. 말씀하신 것처럼 사이킷런에서 train / test 데이터 나눌 때도 모두 함수 반환이 튜플 형태로 되지요. 몫, 나머지를 반환해주는 divmod() 함수도 return 이 튜플이네요. ret = divmod(10, 3) print(type(ret)) # tuple 사실 요즘같이 컴퓨팅 파워가 좋은 환경에서는 과거만큼 크게 성능이나 메모리를 고려하지 않는듯도 합니다. 그래도 재미삼아 몇 가지 확인을 해봤는데요. 튜플은 값이 변경되지 않으므로, 상수라 보면 되지요. 그래서 이런 식으로 같은 값을 가지는 튜플을 반복 생성하면 똑같은 메모리 공간에 있는 값을 재사용하게 됩니다. # 튜플은 같은 값인 경우 같은 메모리 공간 (재사용) t1 = (1, 2, 3) t2 = (1, 2, 3) print(id(t1)) # 3149724065600 print(id(t2)) # 3149724065600 반면에 리스트는 그렇지 않으므로 생성할 때마다 다른 id 를 가지게 되구요 # 리스트는 같은 값이라도 다른 메모리 공간 l1 = [1, 2, 3] l2 = [1, 2, 3] print(id(l1)) # 1714090942912 print(id(l2)) # 1714090901056 이미 만들어진 튜플을 가지고 새롭게 튜플을 만들어도 역시 id 는 같네요. # 튜플은 같은 값 재사용 t3 = tuple(t1) print(id(t1), id(t3)) # 2372553350976 2372553350976 print(t1 is t3) # True 리스트는 역시 다릅니다. # 리스트는 같은 값도 새로 생성 l3 = list(l1) print(id(l1), id(l3)) # 2372553351616 2372553588160 print(l1 is l3) # False 그리고 크기에 있어서도 튜플은 딱 고정 크기로 할당이 되지만 리스트는 추가될 수 있는 상황을 고려해서 같은 값을 가지는 자료형을 생성해도 둘의 크기가 다르게 나와요. # 크기 비교 # 튜플 : 고정 크기 (딱 필요한 만큼만, 더도 말고 덜도 말고) # 리스트 : 가변 크기 (append 를 고려해서 조금 여유롭게) print(t1.__sizeof__()) # 48 print(l1.__sizeof__()) # 104 비슷하게 성능 체크도 해보니 확실히 생성에 있어서는 튜플이 빠른 것을 확인할 수 있었습니다. python -m timeit "x=[1,2,3,4,5,6,7,8]" 5000000 loops, best of 5: 50.5 nsec per loop python -m timeit "x=(1,2,3,4,5,6,7,8)" 20000000 loops, best of 5: 12.1 nsec per loop 이렇게 보면 튜플이 리스트보다 빠르고 메모리도 효율적으로 사용하고 다 좋아보이지만, 그럼에도 불구하고 저는 그냥 어떤 특별한 상황이라기보다는 코드 안에서 알게 모르게 튜플이 사용되고 있고, 누가 값을 안 바꿨으면 할 때 튜플을 쓰면 좋지 않을까 생각해봅니다. ^^
@@nadocoding 상세한 답변 대단히 감사합니다! 기본적으로 훨씬 더 효율적인 연산이 가능하고, 타인과 같이 작업하는 경우에 수정해선 안 되는 자료형의 경우 1차적으로 수정을 막아놓는 기능을 활용할 수도 있는 거네요. 이전에 적어놓은 코드 중에서 무작정 리스트로 쓴 걸 튜플로 바꿀 수 있는 게 있나 싶어서 한 번 뒤적거려봤는데 막상 보니까 죄다 리스트만 쓸 수 있는 것처럼 보이긴 하는데 앞으로 코드 쓸 때 참고해봐야겠습니다.
나도코딩님 감사합니다~~ # 질문있어요 tuple = ('Hello', 'World') print(tuple[0]) # ('Hello')가 아닌 Hello print(tuple[0:1]) # ('Hello')가 아닌 ('Hello',) 가 출력됩니다 원래 튜플의 특징이 그런가요? 리스트는 그렇지 않았던 거 같아서요:)
아.. 좋은 질문입니다. 코드가 다음과 같이 있을때, 괄호 속에 값이 하나만 있을때는 튜플로 인식되지 않습니다. 그래서 t1 은 타입을 찍어보면 int 가 되구요 t1 = (1) print(type(t1)) # int 이렇게 값이 하나만 있을땐 명시적으로 콤마를 뒤에 붙여줌으로써 "이건 튜플이야" 하고 알려줄 수 있습니다. 그래서 t2 는 튜플이 됩니다. t2 = (1, ) print(type(t2)) # tuple 값을 출력할때도 튜플임을 알려주기 위해서 값이 하나만 있을때는 뒤에 콤마를 붙여준답니다. 즉, 튜플의 특징이 맞습니다. ^^
자기 전에 1분씩 보면 오늘 하루 올바르게 산 거 같은 느낌ㅋㅋ 좋은 강의 감사합니다👍
"자기 전에 보는 채널 1위"
극강의 설명력입니다^^. 개봉금지 스티커!!!
리스트와 튜플을 확실히 구분하게 되었습니다. 감사합니다.
정말 당신은 설명왕…!! 심지어 마지막 퀴즈도 매번 진짜 핵심 정리만 담아서….ㅠㅠ 감사해요 흑흑
감사합니다.
아이쿠.. 감사합니다. 시원한 커피 한 잔 잘 마실게요 :)
내장자료형 중에서는 아무래도 리스트를 가장 많이 쓰고 for문 등 반복문을 쓸 일이 있을 때도 전체 '리스트'를 리스트로 만든 다음에 코드를 쓰게 되는 것 같습니다.
그 외 집합은 주로 중복을 쉽게 제거하거나 차집합을 구할 때 쓰게 되는 거 같은데,
튜플은 리스트와 달리 변경을 할 수 없다는 튜플만의 특색을 알고 있음에도 불구하고 그래서 어디에 써야되는지 잘 모르겠더라고요.
어차피 변경이 불필요하면 list에 굳이 제가 append나 pop 등 list 자체를 건드리는 메서드를 쓸 일도 없고, 그럼 튜플을 굳이 써야할 필요가 없는 거 같은데 리스트 대신 튜플을 써야만 하는, (또는 쓰면 좋은) 상황이 어떤 상황이 있을까요?
사실 전혀 쓴 기억이 없다고 생각했는데 이 글 적으면서 생각해보니 머신러닝 좀 공부할 때 사이킷런으로 데이터셋을 test셋과 training셋으로 나눌 때에는 함수 자체가 튜플형으로 반환되어서 a, b, c, d = test_split~~ 이런 식으로 튜플형으로 나오는 결과값을 튜플형 원소 하나하나를 변수 하나하나에 할당해주는 식으로 접했던 적이 있는 거 같긴 합니다...사실 이것도 함수 결과가 그냥 튜플형으로 나온것뿐, 제가 필요해서 쓴 건 아니긴 하네요..
좋은 질문이네요. 저도 어떤 경우에 '반드시' 튜플을 쓰면 좋을까 한참을 생각해봤습니다. 튜플이 가지고 있는 특징이 수정, 추가, 삭제가 불가하다, 즉 immutable 하다는거죠. 바뀔 수가 없으므로 프로젝트 내에서 다른 누군가와 협업을 할 때 튜플을 사용하면 '얘는 건들지 마, 값 바뀌면 안 돼' 라고 따로 커뮤니케이션을 하지 않아도 되겠지요. 물론 그마저도 리스트로 바꿔서 다시 수정해버리면 그만이지만..
사실 우리가 언제 튜플을 써야 하나, 보다는 파이썬을 하다 보면 자연히 튜플을 사용하게 되는 것 같습니다.
다음과 같이 enumerate 을 쓸 때
for i, v in enumerate(['오예스', '몽쉘']): # i, v 튜플
print(i, v)
for 로 받는 i, v 도 괄호는 없지만 콤마로 구분된 튜플 형태로 받아와서 값이 처리될 테구요. 말씀하신 것처럼 사이킷런에서 train / test 데이터 나눌 때도 모두 함수 반환이 튜플 형태로 되지요.
몫, 나머지를 반환해주는 divmod() 함수도 return 이 튜플이네요.
ret = divmod(10, 3)
print(type(ret)) # tuple
사실 요즘같이 컴퓨팅 파워가 좋은 환경에서는 과거만큼 크게 성능이나 메모리를 고려하지 않는듯도 합니다. 그래도 재미삼아 몇 가지 확인을 해봤는데요.
튜플은 값이 변경되지 않으므로, 상수라 보면 되지요. 그래서 이런 식으로 같은 값을 가지는 튜플을 반복 생성하면 똑같은 메모리 공간에 있는 값을 재사용하게 됩니다.
# 튜플은 같은 값인 경우 같은 메모리 공간 (재사용)
t1 = (1, 2, 3)
t2 = (1, 2, 3)
print(id(t1)) # 3149724065600
print(id(t2)) # 3149724065600
반면에 리스트는 그렇지 않으므로 생성할 때마다 다른 id 를 가지게 되구요
# 리스트는 같은 값이라도 다른 메모리 공간
l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(id(l1)) # 1714090942912
print(id(l2)) # 1714090901056
이미 만들어진 튜플을 가지고 새롭게 튜플을 만들어도 역시 id 는 같네요.
# 튜플은 같은 값 재사용
t3 = tuple(t1)
print(id(t1), id(t3)) # 2372553350976 2372553350976
print(t1 is t3) # True
리스트는 역시 다릅니다.
# 리스트는 같은 값도 새로 생성
l3 = list(l1)
print(id(l1), id(l3)) # 2372553351616 2372553588160
print(l1 is l3) # False
그리고 크기에 있어서도 튜플은 딱 고정 크기로 할당이 되지만 리스트는 추가될 수 있는 상황을 고려해서 같은 값을 가지는 자료형을 생성해도 둘의 크기가 다르게 나와요.
# 크기 비교
# 튜플 : 고정 크기 (딱 필요한 만큼만, 더도 말고 덜도 말고)
# 리스트 : 가변 크기 (append 를 고려해서 조금 여유롭게)
print(t1.__sizeof__()) # 48
print(l1.__sizeof__()) # 104
비슷하게 성능 체크도 해보니 확실히 생성에 있어서는 튜플이 빠른 것을 확인할 수 있었습니다.
python -m timeit "x=[1,2,3,4,5,6,7,8]"
5000000 loops, best of 5: 50.5 nsec per loop
python -m timeit "x=(1,2,3,4,5,6,7,8)"
20000000 loops, best of 5: 12.1 nsec per loop
이렇게 보면 튜플이 리스트보다 빠르고 메모리도 효율적으로 사용하고 다 좋아보이지만, 그럼에도 불구하고 저는 그냥 어떤 특별한 상황이라기보다는 코드 안에서 알게 모르게 튜플이 사용되고 있고, 누가 값을 안 바꿨으면 할 때 튜플을 쓰면 좋지 않을까 생각해봅니다. ^^
@@nadocoding 상세한 답변 대단히 감사합니다! 기본적으로 훨씬 더 효율적인 연산이 가능하고, 타인과 같이 작업하는 경우에 수정해선 안 되는 자료형의 경우 1차적으로 수정을 막아놓는 기능을 활용할 수도 있는 거네요. 이전에 적어놓은 코드 중에서 무작정 리스트로 쓴 걸 튜플로 바꿀 수 있는 게 있나 싶어서 한 번 뒤적거려봤는데 막상 보니까 죄다 리스트만 쓸 수 있는 것처럼 보이긴 하는데 앞으로 코드 쓸 때 참고해봐야겠습니다.
@@nadocoding 저도 편리한 리스트가 있는데 굳이 튜플을 사용하는 경우가 있을까? 라는 의문이 생겼는데 좋은 질문과 너무 친절한 답변에 궁금증이 해소 됐습니다. 감사합니다.
튜플은 딕셔너리의 키로 사용할 수 있습니다
리스트는 안되구요.
내부적으로 가능한 동작 불가능한 동작이 조금씩 다릅니다
그리고 튜플로 사용가능한 형태는 튜플로 짜시는게 내부적으로 훨씬 깔끔한 코드가 됩니다
나도코딩님 감사합니다~~
# 질문있어요
tuple = ('Hello', 'World')
print(tuple[0]) # ('Hello')가 아닌 Hello
print(tuple[0:1]) # ('Hello')가 아닌 ('Hello',)
가 출력됩니다
원래 튜플의 특징이 그런가요? 리스트는 그렇지 않았던 거 같아서요:)
아.. 좋은 질문입니다.
코드가 다음과 같이 있을때, 괄호 속에 값이 하나만 있을때는 튜플로 인식되지 않습니다. 그래서 t1 은 타입을 찍어보면 int 가 되구요
t1 = (1)
print(type(t1)) # int
이렇게 값이 하나만 있을땐 명시적으로 콤마를 뒤에 붙여줌으로써 "이건 튜플이야" 하고 알려줄 수 있습니다. 그래서 t2 는 튜플이 됩니다.
t2 = (1, )
print(type(t2)) # tuple
값을 출력할때도 튜플임을 알려주기 위해서 값이 하나만 있을때는 뒤에 콤마를 붙여준답니다. 즉, 튜플의 특징이 맞습니다. ^^
@@nadocoding 와 그렇군요!! 여쭈길 잘했네요:) 세심한 댓글 감사합니다😃👍
오늘도 좋은 영상 감사합니다. 오늘도 잘 봤어요:)
앞에서부터 복습하니 문제가 더 금방풀려요😁👍감사합니다
오늘도 감사 합니다 사부님!
오늘도 왔습니다~ 오늘 내용은 조금 헷갈렸네요 몇번 보고 이해를 했어요~ 그래도 코린이가 이해하기 쉽게 만들어 줘서 항상 감사합니다!
슬라이싱은 가능하군요.
여러 타입이 있는데 보통 리스트를 쓰더라구요.
각 타입이 쓰이는 실제 상황 실제 예시를 시간 되실때 들어줄 수 있으실까요?
시간 되실때요~
좋은 영상 감사합니다 :)
18일차 출석
영상 감사합니다
선생님 초보 개발자가 읽어야하는 책들 추천해주실 있나요??
글쎄요 ^^; 언어는 원하시는 것으로 공부하시면 되고 언어 하나 공부하셨다면 자료구조, 알고리즘 보시고, 이후에는 다른 언어로 확대해나가시면서 클린코드, 디자인패턴 같은것도 보시면 도움되겠네요
@@nadocoding 빠른 답변 감사드립니다 ^^ 선생님
부탁드립니다 ^^
오늘은 초코파이랑 몽쉘이랑 오예쓰 사먹어야겠다
튜플 언패킹!!!!!
출석합니당ㅇ
ㅘ!
4번!