: 여러 데이터를 효과적으로 사용, 관리하기 위한 구조 (str, list, dict 등)
: 객체(클래스)에 속한 함수
-> 객체의 상태를 조작하거나 동작을 수행
print('banana'.find('a')) #1
print('banana'.find('z')) #-1
print('banana'.index('a')) #1
print('banana'.index('z')) #없으면 ValueError
string1 = 'Hello'
string2 = '123'
string3 = '12a3'
print(string1.isalpha()) #True
print(string2.isalpha()) #False
print(string3.isalpha()) #False
string1 = 'HELLO'
string2 = 'Hello'
print(string1.isupper()) #True
print(string2.isupper()) #False
print(string1.islower()) #False
print(string2.islower()) #False
text = 'Hello, world!'
new_text = text.replace('world', 'Python')
print(new_text) #Hello, Python!
text = ' Hello, world! '
new_text = text.strip()
print(new_text) # 'Hello, world!'
text = 'Hello, world!'
words = text.split(',')
print(words) #['Hello', ' world!']
words = ['Hello', 'world!']
text = '-'.join(words)
print(text) # 'Hello-world!'
text = 'heLLo, woRld!'
new_text1 = text.capitalize()
new_text2 = text.title()
new_text3 = text.upper()
new_text4 = text.swapcase()
print(new_text1) #Hello, world!
print(new_text2) #Hello, World!
print(new_text3) #HELLO, WORLD!
print(new_text4) #HEllO, WOrLD!
*메서드는 이어서 사용 가능함
text = 'heLLo, woRld!'
new_text = text.swapcase().replace('l', 'z')
print(new_text)
my_list = [1, 2, 3]
my_list.append(4)
print(my_list) #[1, 2, 3, 4]
my_list = [1, 2, 3, 4]
my_list.append([4, 5, 6])
print(my_list) #[1, 2, 3, 4, [4, 5, 6]] - 요소가 풀리지 않고 그대로 들어감
my_list = [1, 2, 3, 4]
my_list.extend([4, 5, 6])
print(my_list) #[1, 2, 3, 4, 4, 5, 6] - 요소가 풀려서 들어감
my_lst = [1, 2, 3]
my_lst.insert(1, 5)
print(my_lst) #[1, 5, 2, 3]
my_lst = [1, 2, 3]
my_lst.remove(2)
print(my_lst) #[1, 3]
my_lst = [1, 2, 3]
my_lst.remove(5)
print(my_lst) #ValueError
my_lst = [1, 2, 3, 4, 5]
item1 = my_lst.pop()
item2 = my_lst.pop(0)
print(item1) #5
print(item2) #1
print(my_lst) #[2, 3, 4]
my_lst = [1, 2, 3]
my_lst.clear()
print(my_lst) #[]
my_lst = [1, 2, 3]
index = my_lst.index(2)
print(index) #1
my_lst = [1, 3, 2, 8, 1, 9]
my_lst.reverse()
print(my_lst) #[9, 1, 8, 2, 3, 1]
my_lst = [3, 2, 1]
my_lst.sort()
print(my_lst) #[1, 2, 3]
#내림차순
my_lst.sort(reverse=True)
print(my_lst) #[3, 2, 1]
my_lst = [1, 2, 2, 3, 3, 3]
count = my_lst.count(3)
print(count) #3
: 파이썬에서는 데이터의 분류에 따라 복사가 달라짐
: "변경 가능한 데이터 타입"과 "변경 불가능한 데이터 타입"을 다르게 다룸
a = [1, 2, 3, 4]
b = a
b[0] = 100
print(a) #[100, 2, 3, 4]
print(b) #[100, 2, 3, 4]

a = 20
b = a
b = 10
print(a) #20
print(b) #10

original_lst = [1, 2, 3]
copy_lst = original_lst
copy_lst[0] = 'hello'
print(original_lst)
*할당 연산자(=)를 통한 복사는 해당 객체에 대한 객체 참조를 복사
a = [1, 2, 3]
b = a[:]
print(a, b) #[1, 2, 3] [1, 2, 3]
b[0] = 100
print(a, b) #[1, 2, 3] [100, 2, 3]
*예시) 슬라이싱을 통해 생성된 객체는 원본 객체와 독립적으로 존재
*얕은 복사의 한계: 2차원 리스트와 같이 변경 가능한 객체 안에 변경 가능한 객체가 있는 경우
a = [1, 2, [1, 2]]
b = a[:]
print(a, b) #[1, 2, [1, 2]] [1, 2, [1, 2]]
b[2][0] = 100
print(a, b) #[1, 2, [100, 2]] [1, 2, [100, 2]]

import copy
original_lst = [1, 2, [1, 2]]
deep_copied_lst = copy.deepcopy(original_lst)
deep_copied_lst[2][0] = 100
print(original_lst) #[1, 2, [1, 2]]
print(deep_copied_lst) #[1, 2, [100, 2]]
*예시) 내부에 중첩된 모든 객체까지 새로운 객체 주소를 참조하도록 함
