강의영상

- (1/7) 튜플을 쓰는 이유

- (2/7) 인덱스고급: 스트라이딩 (1)

- (3/7) 인덱스고급: 스트라이딩 (2)

- (4/7) 컴프리헨션고급 (if문이 포함된 컴프리헨션)

- (5/7) 함수고급 (조건부리턴), len함수

- (6/7) summary of str/list/tupel, 딕셔너리 (모티브, 선언, 원소추출, 원소추가, 원소변경, 삭제)

- (7/7) 숙제설명

some minor comments: str, list, tuple

(리스트가 아니고) 튜플을 쓰는 이유

- 책의 설명 (이 설명이 꼭 파이썬에 한정되는 것은 아님. 모든 언어에 존재하는 불변형 객체에 적용가능한 설명)

  • 실수방지
  • 빠르다, 다중작업에 유리하다, 여러사람과 작업하기에 유리하다, 깊은복사/얕은복사시 원하지않는 오류(side effect이라고 함)를 방지할 수 있다, 메모리관리에도 유리함...
  • 느낌: 불변형은 기능제한이 있는데 가볍고 빠른, 가변형은 기능은 풍부하지만 약간 느리고 무거운 느낌임 (불변형:라면사리, 가변형:라면)

- 내 설명

  • 튜플의 장점은 소괄호의 생략에 있음 (이것은 파이썬과 줄리아만 가능)
  • 이것이 언패킹구문과 결합하여 어마무시한 가독성을 제공
def mycal(a,b):
    return a+b, a-b, a*b, a/b  #여러개의 값을 리턴하는듯 보임. -> 사실은 길이가 4인 튜플 1개를 리턴
mycal(2,3)
(5, -1, 6, 0.6666666666666666)
_, _, mulrslt, _ = mycal(2,3) # 병렬할당 
mulrslt
6

- 의문: 왜 튜플만 괄호를 생략할 수 있지?

- 내망상

  • 튜플을 먼저 만들고, 괄호를 생략하는 문법을 추가한것은 아닐것임
  • 원래 괄호없이 컴마만 대충찍어서 선언가능한 아주간단한 타입의 벡터형을 만들고 싶었을 것임.
  • 왜? 괄호없는 벡터를 만들고 + 언패킹을 사용하면 여러가지 구문들이 엄청나게 간단해짐.
  • 컴마컴마로 선언하는 벡터는 한 두번 쓰고 버리는 경우가 많으며 대부분 이름도 필요없음 $\to$ 원소에 접근해서 sorting하여 순서를 바꾸고 싶다던가 원소를 추가할 이유가 없음 $\to$ 비싼 가변형으로 만들 이유가 없다는 것..
  • 우리가 필요한것: 데이터가 벡터의 형태로 모여있기만 하면 된다!

- 다른사람들 의견 (컴공과 인터뷰)

  • 튜플 + 언패킹에 충격 $\to$ 파이썬 편하더라..

인덱싱고급 (스트라이딩)

- 스트라이딩 [start:stop:step]

lst = list('abcdefgh')
lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
lst[0:8:2]
['a', 'c', 'e', 'g']

- 생략

lst[::2]
['a', 'c', 'e', 'g']
lst[0::2]
['a', 'c', 'e', 'g']
lst[:8:2]
['a', 'c', 'e', 'g']

- 예제: 짝수/홀수 원소 추출

lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
lst[::2] # 1,3,5,7, ... 
['a', 'c', 'e', 'g']
lst[1::2] # 2,4,6,8, ... 
['b', 'd', 'f', 'h']

- step = -1 이면?

lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
lst[::-1]
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
  • reverse와 같은 기능

(reverse)와 비교

관찰1: reverse 메소드는 리스트 자체를 변화시킴

lst = list('abcdefgh')
lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
lst.reverse() #리버스는 
lst
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

관찰2: [::-1]는 리스트는 변화시키지 않음

lst = list('abcdefgh')
lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
lst[::-1]
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
lst
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

- 사실 -step은 쓰는 것이 조금 까다롭다.

(예제) 처음과 끝을 생략하지 않고 아래와 동일한 효과를 주는 코드를 만들어 보자.

lst = list('abcdefgh')
lst[::-1]
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

(풀이)

결국 lst[?:?:-1]의 꼴에서 적당히 ?의 값을 채우면 된다.

lst[-1::-1] # 일단 첫 시작은 제일 마지막 원소 
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
lst[-1:0:-1] # 앗 마지막 인덱스는 포함 안되는거였지? 
['h', 'g', 'f', 'e', 'd', 'c', 'b']
lst[-1:-1:-1] # 앗 마지막 인덱스는 포함 안되는거였지? 
[]

잠깐 인덱스를 생각해보자.

a b c d e f g h
0 1 2 3 4 5 6 7
-8 -7 -6 -5 -4 -3 -2 -1
lst[-1:-9:-1] # 아..
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

(예제)

lst[2::2]
['c', 'e', 'g']
lst[-2::-2]
['g', 'e', 'c', 'a']
lst[-2:2:2]
[]
lst[2:2:2]
[]
lst[2:2:-2]
[]

결론: -step을 자주 쓰진 말자?

컴프리헨션 고급 (if문이 포함된 컴프리헨션)

- 예제: 제곱수중에서 12로 나누어 떨어지는 수만 원소로 가지는 리스트를 만들고 싶다.

  • 제곱수: 1,4,9,16,25,36, ...
  • 12로 나누어 떨어지는 수: 36, ...

(예비학습)

12 % 4 # %는 나머지를 계산하는 연산자, 12를 4로 나누면 나머지가 0
0
12 % 5 # %는 나머지를 계산하는 연산자, 12를 5로 나누면 나머지가 2
2

(풀이1)

lst = [] 
for i in range(1,101): 
    if (i**2 % 12 == 0): 
        lst.append(i**2)
lst
[36,
 144,
 324,
 576,
 900,
 1296,
 1764,
 2304,
 2916,
 3600,
 4356,
 5184,
 6084,
 7056,
 8100,
 9216]

(풀이2)

[i**2 for i in range(1,101) if (i**2 % 12 == 0)]
[36,
 144,
 324,
 576,
 900,
 1296,
 1764,
 2304,
 2916,
 3600,
 4356,
 5184,
 6084,
 7056,
 8100,
 9216]

함수고급 (조건부리턴)

- 홀수/짝수를 판별하는 함수 만들기 1

def test(a):
    if a % 2 ==0: 
        return 'even'
    else:
        return 'odd'
test(1)
'odd'
test(2)
'even'
test(3)
'odd'
test(4)
'even'
[test(a) for a in range(1,11)]
['odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even']

- 홀수/짝수를 판별하는 함수 만들기 2

def test(a):
    return 'even' if a%2 ==0 else 'odd'
test(3)
'odd'
[test(a) for a in range(1,11)]
['odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even']

len함수

- 0차원 자료형은 len함수가 동작하지 않음

a=1 
len(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [44], in <cell line: 2>()
      1 a=1 
----> 2 len(a)

TypeError: object of type 'int' has no len()
a=True
len(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [45], in <cell line: 2>()
      1 a=True
----> 2 len(a)

TypeError: object of type 'bool' has no len()
a=3.14
len(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [46], in <cell line: 2>()
      1 a=3.14
----> 2 len(a)

TypeError: object of type 'float' has no len()

Note: 이것이 어떠한 수학적인 의미를 가지거나 0차원의 본질적진리를 뜻하는 것은 안미. R에서는 1,3.14,TRUE의 길이가 1로 존재함.

- 1차원 자료형은 len함수가 동작

a='guebin'
len(a)
6
a=[1,2,3,4,5,6]
len(a)
6
a=1,2,3,4,5,6 
len(a)
6
a=range(10)
len(a)
10

- 길이가 1인 1차원 자료형과 0차원 자료형은 다른것임

a='g'
len(a)
1
a=[1] 
len(a)
1
a=(1,)
len(a)
1
a=range(1)
len(a)
1

- 길이가 0인 1차원 자료형도 존재함

a=''
len(a)
0
a=[]
len(a)
0
a=()
len(a)
0
a=range(0)
len(a)
0

summary: str, list, tuple

- str, list, tuple은 모두 시퀀스형이라는 공통점이 있다. $\to$ 원소의 위치번호로 인덱싱이 가능

lst = [1,2,3,4]
lst[0] # 위치번호=0
1
lst[-1] # 위치번호=-1
4

- str, list, tuple은 차이점도 존재함. 잠깐 정리해보자.

시퀀스형의 카테고리

  • 컨테니어형: list, tuple
  • 균일형: str
  • 가변형: list
  • 불변형: tuple, str

표로 정리하면

컨테니어형 균일형
가변형 list .
불변형 tuple str

- 시퀀스형이 아닌 1차원 자료형도 있을까? 원소의 위치번호로 인덱싱이 불가능한 자료형

- 왜 이런게 필요할까?

  • 벡터에서 원소를 뽑는것은 정보의 모임에서 정보를 검색하는 것과 같다.
  • 정보를 순서대로 나열한뒤에 그 순서를 이용하여 검색하는 방법은 유용하다.
  • 하지만 경우에 따라서는 키워드를 기억해서 그 키워드를 바탕으로 정보에 접근하는 방법이 유용할 수 있다.

카카오톡 대화내용검색

(상황1) 오늘아침에 와이프가 뭔가를 카톡으로 부탁했었음. 그런데 그 뭔가가 기억안남.

(상황2) 개강전에 동료교수와 함께 저녁약속을 카톡으로 잡았었음. 그런데 그게 언제인지 기억안남.

(상황3) 오늘아침 동료교수와 함께 점심약속을 카톡으로 잡았었음. 그런데 그 장소가 기억나지 않음.

- 순서대로 정리된 자료를 검색할때는 시퀀스형이 유리하다. 그런데 키워드로 검색하고 싶을 경우는 딕셔너리 타입이 유리하다.

딕셔너리

선언

- 방법1

score={'guebin':49, 'iu':80}
score
{'guebin': 49, 'iu': 80}
type(score)
dict

- 방법2

score=dict(guebin=49, iu=80)
score
{'guebin': 49, 'iu': 80}
type(score)
dict

- 방법3

_lst = [['guebin',49],['iu',80]]
_lst 
[['guebin', 49], ['iu', 80]]
dict(_lst)
{'guebin': 49, 'iu': 80}

- 방법4

_tpl = ('guebin',49), ('iu',80)
_tpl
(('guebin', 49), ('iu', 80))
dict(_tpl)
{'guebin': 49, 'iu': 80}

원소추출

score = {'guebin':49, 'iu':80}
score
{'guebin': 49, 'iu': 80}

guebin의 점수를 추출하고 싶다면?

score[0] # 이렇게 뽑는것이 아니고! 
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Input In [71], in <cell line: 1>()
----> 1 score[0]

KeyError: 0
score['guebin'] 
49

- 리스트로 저장했다면?

score=[['guebin',49],['iu',80]]
score
[['guebin', 49], ['iu', 80]]

guebin의 점수를 추출하고 싶다면?

(방법1)

score[0][1] # guebin의 점수를 출력하란 의미
49

(방법2)

_keys = [score[i][0] for i in range(len(score))] # 리스트컴프리헨션
_keys
['guebin', 'iu']
[score[i][1] for i in range(len(score)) if score[i][0] =='guebin' ] 
[49]
  • 어지럽죠?

원소추가, 변경, 삭제

score={'guebin':49, 'iu':80}
score
{'guebin': 49, 'iu': 80}

- 원소에 접근

score['guebin']
49

- 추가

score['hynn'] = 99 # 추가 
score 
{'guebin': 49, 'iu': 80, 'hynn': 99}

- 변경

score['iu'] = 99  # 변경 
score 
{'guebin': 49, 'iu': 99, 'hynn': 99}

- 삭제

(방법1)

score={'guebin':49, 'iu':80, 'hynn':99}
del score['guebin']  
score
{'iu': 80, 'hynn': 99}

(방법2)

score={'guebin':49, 'iu':80, 'hynn':99} 
score.pop('guebin')
49
score
{'iu': 80, 'hynn': 99}

- 참고로 리스트였다면 이러한 삭제작업역시 비효율적이었을 것임

score = [['guebin',49],['iu',80],['hynn',99]] 
score
[['guebin', 49], ['iu', 80], ['hynn', 99]]
score = [[key,val] for key,val in score if key != 'guebin'] 
score
[['iu', 80], ['hynn', 99]]

(숙제) 길이가 4인 dictionary를 생성

  • len 함수를 이용하여 길이를 측정
  • key를 이용하여 각 원소에 접근하여 보기