6. 객체신원과 타입
is 연산자를이용해두객체의신원을비교하는여러가지방법
# 두 객체를 비교한다
def compare(a, b):
if a is b:
print("a 와 b 는 동일한 객체")
if a == b:
print("a 와 b 는 동일한 값")
if type(a) is type(b):
print("a 와 b 는 동일한 타입")
>>> a = 42
>>> b = 30
>>> compare(a, b)
a 와 b 는 동일한 타입
6
7. 객체신원과 타입
객체타입은객체의클래스라고 하며그 자체도객체로존재
타입객체는고유하게 정의
주어진타입의모든인스턴스에대해서항상동일
타입은is 연산자로비교 가능
>>> item = 10
>>> s = [1, 2, 3]
>>> if type(s) is list:
... s.append(item)
...
>>> s
[1, 2, 3, 10]
7
8. 객체신원과 타입
타입은클래스를통해특수화(specialization)가 가능하기 때문에
isinstance(object, type) 을사용하여검사하는것이좋음
isinstance() 함수는클래스상속관계를인식하여타입검사수행
>>> item = 10
>>> s = [1, 2, 3]
>>> if isinstance(s, list):
... s.append(item)
...
>>> s
[1, 2, 3, 10]
8
9. 참조횟수와쓰레기 수집
모든객체는참조횟수(referencecount)를유지하며, 이값이0이되면
쓰레기 수집(garbagecollection) 단계를거쳐메모리를반납
참조횟수를증가시키는경우
객체가 새로운이름에대입
리스트, 튜플, 사전같은컨테이너에추가
>>> import sys
>>> a = 42
>>> sys.getrefcount(a)
9
>>> b = a
>>> sys.getrefcount(a)
10
>>> c = [a]
>>> sys.getrefcount(a)
11
9
10. 참조횟수와쓰레기 수집
참조횟수를감소시키는경우
del연산자사용
참조가 유효범위를벗어날경우
>>> import sys
>>> a = 42
>>> sys.getrefcount(a)
9
>>> b = a
>>> sys.getrefcount(a)
10
>>> del b
>>> sys.getrefcount(a)
9
인터프리터는숫자나문자열같은변경 불가능한객체에의해사용되는
메모리를절약하기 위해이들을여러곳에서최대한공유
10
11. 참조횟수와쓰레기 수집
순환참조가 존재할경우에는참조횟수를줄일수가 없어메모리를계속점유
>>> import sys
>>> a = {}
>>> b = {}
>>> sys.getrefcount(b)
2
>>> a['b'] = b
>>> sys.getrefcount(b)
3
>>> del a
>>> sys.getrefcount(b)
2
>>> a = {'b': b}
>>> b['a'] = a
>>> del a
>>> sys.getrefcount(b)
3
11
14. 참조와복사
>>> a = [1, 2, 3, 4]
>>> b = a
>>> b is a
True
>>> b[2] = 42
>>> a
[1, 2, 42, 4]
a와b가 동일한객체를참조하기 때문에두변수중하나에가해진변화가
다른변수에서도그대로나타남
이러한영향을방지하려면객체에대한참조가 아니라복사본을생성해서사용
14
16. 얕은복사
a와b는서로다른리스트객체이지만, 그 안의원소는공유
b의한원소에가한변화는a에서도그대로나타남
>>> a = [1, 2, [3, 4]]
>>> b = list(a) # a 에 대한 얕은 복사본 생성
>>> b is a
False
>>> b.append(42) # b 에 새로운 원소 추가
>>> b
[1, 2, [3, 4], 42]
>>> a # a 에 아무런 변화 없음
[1, 2, [3, 4]]
>>> b[2][0] = 100 # b 안에 있는 리스트 중 첫번째 원소 변경
>>> b
[1, 2, [100, 4], 42]
>>> a # a 도 변경됨
[1, 2, [100, 4]]
16
17. 깊은복사
>>> import copy
>>> a = [1, 2, [3, 4]]
>>> b = copy.deepcopy(a) # 깊은 복사를 거쳐 b 생성
>>> b[2][0] = 42
>>> b
[1, 2, [42, 4]]
>>> a # a 가 변경되지 않음
[1, 2, [3, 4]]
17
18. 1급 객체
파이썬에서모든객체는'1급 (first class)' 객체
식별자로명명될수있는모든객체는동일한지위를가짐
이름을가질수있는모든객체는데이터로서취급 가능
>>> items = {
... 'number': 42, # 일반적인 정수형 데이터
... 'text': 'Hello, World!' # 문자열 데이터
... }
>>> items["func"] = abs # abs() 함수 추가
>>> import math
>>> items["math"] = math # 모듈 추가
>>> items["error"] = ValueError # 예외 타입
>>> nums = [1, 2, 3, 4]
>>> items["append"] = nums.append # 다른 객체 메서드 추가
위예제코드에서보는것처럼함수나모듈, 예외타입등모든객체를
데이터로서취급하는것이가능
18
19. 1급 객체
다양한객체를사전에넣고 이를이용해코드실행
>>> items["func"](-42) # abs(-42) 실행
42
>>> items["math"].sqrt(16) # math.sqrt(16) 실행
4.0
>>> try:
... x = int("invalid")
... except items["error"] as e: # except ValueError as e:
... print("Convert failed")
...
Convert failed
>>> items["append"](42) # nums.append(42) 실행
>>> nums
[1, 2, 3, 4, 42]
19
20. 1급 객체
문자열을타입객체리스트를이용해변환하는방법
>>> s = "HELLO,100,3.14"
>>> types = [str, int, float]
>>> values = s.split(",")
>>>
>>> fields = [ty(val) for ty, val in zip(types, values)]
>>> print(fields)
['HELLO', 100, 3.14]
문자열안에있는필드각각을나타낼수있는타입리스트먼저생성후
(타입, 값) 쌍을만들어타입(값) 형태로필드생성
20
28. 모든순서열에공통적인연산
항목 설명
s[i] 순서열의원소i를반환
s[i:j] 조각을반환
s[i:j:stride] 확장분할에의한조각을반환
len(s) s 에있는원소개수
min(s) s 의최솟값
max(s) s 의최댓값
all(s) s 에있는모든항목이True인지검사
any(s) s 에있는아무항목이나True인지를검사
28
29. 모든순서열에공통적인연산
>>> s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> s[5]
6
>>> s[2:6] # 조각을 반환
[3, 4, 5, 6]
>>> s[1:8:2] # 1에서 8까지 2씩 증가시키면 조각 반환
[2, 4, 6, 8]
>>> len(s)
10
>>> min(s)
1
>>> max(s)
10
>>> sum(s, 0) # s 항목들의 합, 두 번째 인자에 초기값 지정
55
>>> all(s) # s 에 있는 모든 항목이 True 인지 검사
True
>>> any(s) # s 에 있는 아무 항목이나 True 인지 검사
True
29
30. 변경 가능한순서열에적용할수있는연산
항목 설명
s[i] = v 항목대입
s[i:j] = t 조각 대입
s[i:j:stride] 확장분할에의한조각 대입
dels[i] 항목삭제
dels[i:j] 조각 삭제
dels[i:j:stride] 확장분할에의한조각 삭제
30
31. 변경 가능한순서열에적용할수있는연산
>>> s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> s[0] = 42 # 항목 대입
>>> s
[42, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> s[3:6] = [100, 200, 300] # 조각 대입
>>> s
[42, 2, 3, 100, 200, 300, 7, 8, 9, 10]
>>> s[0:5:2] = [20, 40, 60] # 확장 분할 이용 조각 대입
>>> s
[20, 2, 40, 100, 60, 300, 7, 8, 9, 10]
>>> del s[0] # 항목 삭제
>>> s
[2, 40, 100, 60, 300, 7, 8, 9, 10]
>>> del s[0:2] # 조각 삭제
>>> s
[100, 60, 300, 7, 8, 9, 10]
>>> del s[0:7:2] # 확장 분할 이용 조각 삭제
>>> s
[60, 7, 9]
31
32. 리스트
메서드 설명
list(s) s 를리스트로변환
s.append(x) s 의끝에새로운원소x 추가
s.extend(t) s 의끝에새로운리스트t 추가
s.count(x) s 에서x 가 출현한횟수
s.index(x [, start [, stop]]) s[i]==x 인가장작은i반환
s.insert(i, x) 색인i의위치에x 삽입
s.pop([i]) 리스트에서원소i를제거하면서반환
s.remove(x) s 에서x 를찾아서제거
s.reverse() s 의항목들을그 자리에서뒤집음
s.sort([key [, reverse]]) s 의항목들을그 자리에서정렬
32
33. 리스트
내장함수인list(s) 는반복가능한타입을리스트로변환
s 가 이미리스트이면s 의얕은복사본으로새로운리스트생성
s.append(x) 는리스트끝에새로운원소x 추가
s.index(x) 는리스트에서처음으로나타나는x 를검색
x 가 없을경우에는ValueError 예외발생
s.remove(x) 는리스트에서처음으로나타나는x 를제거
x 가 없을경우에는ValueError 예외발생
s.extend(t) 는t 에있는원소를추가해리스트s 확장
s.sort() 는리스트원소를정렬
s 에있는항목은모두동일한타입이여야함
key 함수를지정해비교를수행할때사용할값 지정가능
reverse플래그를지정해역순정렬가능
s.reverse() 는s 의항목들을뒤집어저장 33
34. 리스트메서드실행
>>> s = list((1, 2, 3, 4)) # 튜플을 이용해 리스트 생성
>>> s
[1, 2, 3, 4]
>>> s.append(10) # 리스트 끝에 10 추가
>>> s
[1, 2, 3, 4, 10]
>>> s.extend([20, 30, 40]) # 다른 리스트를 추가해 확장
>>> s
[1, 2, 3, 4, 10, 20, 30, 40]
>>> s.count(10) # s 안에 있는 10 원소 횟수
1
>>> s.index(10) # s 에서 10이 나타나는 위치
4
>>> s.insert(4, 100) # 4번째 위치에 100을 추가
>>> s
[1, 2, 3, 4, 100, 10, 20, 30, 40]
34
35. 리스트메서드실행
>>> s.pop() # 가장 마지막 원소 삭제
40
>>> s
[1, 2, 3, 4, 100, 10, 20, 30]
>>> s.remove(100) # 100 원소를 찾아 삭제
>>> s
[1, 2, 3, 4, 10, 20, 30]
>>> s.reverse() # s 의 항목을 뒤집어 저장
>>> s
[30, 20, 10, 4, 3, 2, 1]
>>> s.sort() # s 의 원소를 오름차순 정렬
>>> s
[1, 2, 3, 4, 10, 20, 30]
35
47. 문자열메서드: 문자열내부검사
>>> "ABCD".isupper() # 모든 문자열이 대문자인지 검사
True
>>> "abcd1234".isalnum() # 문자열이 알파벳과 숫자로만 이루어졌는지 검사
True
>>> "ABCD".islower() # 모둔 문자열이 소문자인지 검사
False
>>> "".isalnum() # 비어 있는 문자열일 경우에는 False 반환
False
>>> "".isupper() # 비어 있는 문자열일 경우에는 False 반환
False
47
48. 문자열메서드: 검색
find() 메서드는부분문자열을찾지못하면‑1을반환하고
index() 메서드는부분문자열을찾지못하면ValueError 예외발생
>>> s = "hello, world!"
>>> s.find("world") # 지정한 문자열이 처음 나타나는 위치
7
>>> s.find("there") # find() 는 문자열을 찾지 못하면 -1
-1
>>> s.index("world")
7
>>> s.index("there") # index() 는 문자열을 찾지 못하면 예외
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
48
49. 문자열메서드: 검색
>>> s = "hello, world. hello, programmer"
>>> s.find("hello")
0
>>> s.rfind("hello")
14
>>> s.index("hello")
0
>>> s.rindex("hello")
14
>>> s.rfind("there")
-1
>>> s.rindex("there")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
rfind() 와rindex() 는부분문자열을뒤에서검색하여위치를반환
49
50. 문자열메서드: 분리
>>> s = " name email country state city "
>>> s.split()
['name', 'email', 'country', 'state', 'city']
>>> s.rsplit()
['name', 'email', 'country', 'state', 'city']
>>> s.split(None, 3)
['name', 'email', 'country', 'state city ']
>>> s.rsplit(None, 3)
[' name email', 'country', 'state', 'city']
split(), rsplit() 첫번째인자로분리할문자를지정하고
두번째인자로분리할문자열갯수지정
split() 은왼쪽에서분리할문자열을생성하고
rsplit() 은오른쪽에서분리할문자열을생성
50
51. 문자열메서드: 분리
>>> s = "FIELD-VALUE-OPTION"
>>> s.partition("-")
('FIELD', '-', 'VALUE-OPTION')
>>> s.rpartition("-")
('FIELD-VALUE', '-', 'OPTION')
partition(), rpartition() 메서드는분리자부분문자열을검색한후
분리자앞쪽텍스트, 분리자, 그리고 분리자뒤쪽텍스트로분할
partition() 은왼쪽에서처음나오는분리자부분문자열을검색
rpartition() 은오른쪽에서처음나오는분리자부분문자열을검색
51
54. 문자열메서드: 포맷지정
>>> s = "Your name is {0} and your age is {1}"
>>> s.format("Mike", 40)
'Your name is Mike and your age is 40'
>>> s = "Your name is {name} and your age is {age}"
>>> s.format(name="Mike", age=40)
'Your name is Mike and your age is 40'
54
55. 문자열메서드: 포맷지정
>>> s = "Your name is {item[name]} and
your age is {item[age]}"
>>> person = {"name": "Mike", "age": 40}
>>> s.format(item=person)
'Your name is Mike and your age is 40'
포맷문자열안에있는자리표시자{item} 은간단한색인검색이나
속성검색을포함하는것도가능
{item[n]}: 순서열검색을통해문자열치환
{item[key]}: 사전검색을통해문자열치환
{item.key}: item의속성attr 을이용해문자열치환
55
62. 사전의메서드와연산
>>> person = {"name": "Mike", "age": 40}
>>> person["name"]
'Mike'
>>> person["location"] # 키를 못 찾을 경우 KeyError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'location'
>>> person.get("location", "No data") # 못 찾을 경우 기본 값
'No data'
>>> person.update({"location": "Seoul"})
>>> person
{'name': 'Mike', 'age': 40, 'location': 'Seoul'}
>>> len(person)
3
>>> person.pop("location") # 항목 값을 반환하면서 삭제
'Seoul'
>>> person
{'name': 'Mike', 'age': 40}
62
63. 사전의메서드와연산
>>> m = dict.fromkeys(["name", "age"]) # 키를 가져와 생성
>>> m
{'name': None, 'age': None}
>>> m["name"] = "Mike"
>>> m["age"] = 40
>>> n = m.copy() # 매핑 객체에 대한 얕은 복사본
>>> n["name"] = "David"
>>> m
{'name': 'Mike', 'age': 40}
>>> n
{'name': 'David', 'age': 40}
63
69. 집합타입메서드와연산
>>> a = {1, 3, 5, 7}
>>> b = {1, 2, 4, 6}
>>> len(a)
4
>>> a.difference(b) # 집합 연산 a - b
{3, 5, 7}
>>> a.intersection(b) # 집합 연산 a ∩ b
{1}
>>> a.union(b) # 집합 연산 a ∪ b
{1, 2, 3, 4, 5, 6, 7}
>>> a.symmetric_difference(b) # 집합 연산 a ∪ b - (a ∩ b)
{2, 3, 4, 5, 6, 7}
69
70. 집합타입메서드와연산
>>> a = {1, 3, 5}
>>> b = {1, 3, 5, 7, 9}
>>> a.issubset(b) # a ⊂ b
True
>>> b.issuperset(a) # a ⊂ b
True
>>> a.isdisjoint(b) # a ∩ b is ∅ ?
False
>>> a = {1, 3, 5}
>>> b = {2, 4, 6}
>>> a.isdisjoint(b) # a ∩ b is ∅ ?
True
70
73. 집합타입메서드와연산
변경 가능한집합에사용가능한메서드
>>> a = {1, 3, 5}
>>> b = {2, 3, 5, 7}
>>> a.add(9) # a 집합에 항목 추가
>>> a
{1, 3, 5, 9}
>>> a.difference_update(b) # a := a - b
>>> a
{1, 9}
>>> c = {1, 10}
>>> a.intersection_update(c) # a := a ∩ c
>>> a
{1}
73
74. 집합타입메서드와연산
변경 가능한집합에사용가능한메서드
>>> a = {1, 3, 5, 7}
>>> a.update({1, 1, 3, 3, 5, 9})
>>> a
{1, 3, 5, 7, 9}
>>> a.pop() # 원소를 반환하면서 집합에서 제거
1
>>> a.pop()
3
>>> a
{5, 7, 9}
>>> a.remove(10) # 없는 값을 지정할 경우 KeyError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 10
>>> a.discard(10) # 없는 값을 지정할 경우 무시
74
101. 객체비교와순서매기기
객체는하나이상의관계 연산자를구현하는것이가능
각 메서드는두개의인수를받아어떤종류의객체든반환가능
메서드 설명
__lt__(self,other) self< other
__le__(self,other) self≤ other
__gt__(self,other) self> other
__ge__(self,other) self≥ other
__eq__(self,other) self== other
__ne__(self,other) self!= other
== 로비교하거나사전키로사용하려면__eq__() 메서드구현
객체를정렬하거나min(), max() 를사용하려면__lt()__ 메서드구현
101