JavaScript 다음으로 만난 두 번째 언어, Python.
자료형 9가지, 문자열 다루기, 그리고 출력 서식(%, format, f-string)과 리스트까지.
JS를 먼저 배운 덕분에 코딩 자체에는 어느 정도 적응이 된 편이다. Python은 JS와 비슷한 것도 있고, 다른 것도 있고, 없는 것도 있었다. 오늘 배운 내용은 이렇다.
% 서식 문자, format(), f-string| 자료형 | 이름 | 예 |
|---|---|---|
int | 정수 | 3 |
float | 실수 | 10.4 |
complex | 복소수 | 3+4j |
bool | 불린 | True, False |
str | 문자열 | 'Python' |
list | 리스트 | [1, 2, 3] |
tuple | 튜플 | (4, 2, 4) |
set | 집합 | {1, 23, 4} |
dict | 사전(딕셔너리) | {'name': 'gildong', 'id': 3} |
# 데이터 타입
str1 = 'Python'
float1 = 10.4
int1 = 3
bool1 = True
list1 = [str1] # list는 대괄호
tuple1 = 4, 2, 4
set1 = {1, 23, 4} # 중괄호로 집합 형태
dict1 = {'name': 'gildong', 'id': 3} # JS의 객체와 비슷한 모양
# 데이터 타입 출력
print(type(str1)) # <class 'str'>
print(type(bool1)) # <class 'bool'>
print(type(float1)) # <class 'float'>
print(type(int1)) # <class 'int'>
print(type(list1)) # <class 'list'>
print(type(tuple1)) # <class 'tuple'>
print(type(dict1)) # <class 'dict'>
print(type(set1)) # <class 'set'>
파이썬은 모든 것이 객체다. str1 = 'Python'이라고 쓰면 문자 자체가 객체가 되고, 그 객체에 다양한 속성(변수)과 행동(함수)이 붙어 있다. JS의 typeof에 해당하는 것이 type()이다.
JS와 비교하면서 눈에 띈 부분을 표로 모아 둔다.
| 항목 | JavaScript | Python |
|---|---|---|
| 주석 | // | # |
| 변수 선언 | let, const | 키워드 없이 x = 3 |
| 불린 | true, false | True, False (첫 글자 대문자) |
| 타입 확인 | typeof(x) | type(x) |
| 키-값 구조 | 객체 { } | dict { } |
| 배열 | 배열 [ ] | 배열이 없고 list [ ] |
| 거듭제곱 | Math.pow(3, 4) | 3 ** 4, pow(3, 4) |
| 문장 끝 | ; | 필요 없음 |
빈 중괄호
{}는 집합(set)이 아니라 빈 딕셔너리다. 빈 집합은set()으로 만든다.
# 숫자형 연산자: +, -, *, /, %
i1 = 30
i2 = 944
big_int1 = 12345678123567891231234213546351356
big_int2 = 99999999999999999999999999999999999999
print(i1 + i2) # 974
print(big_int1 + big_int2) # 정수 크기에 제한이 없다 (메모리가 허용하는 범위까지)
print(3 ** 4) # 81 (n ** m = n의 m승)
JS에서는 정수가 어느 크기를 넘으면 정확하게 표현할 수 없었지만, Python의 int는 크기 제한이 없다.
# 실수의 사칙연산
f1 = 1.234
f2 = 5.678
print(f1 + f2) # 6.912
print(f1 - f2) # -4.444
print(f1 * f2) # 7.006652
print(f1 / f2) # 0.2173300457907714
a = 3.
b = 10
c = .5
d = 12.5
print(type(a), type(b), type(c), type(d)) # 한 줄에 여러 개를 출력할 수 있다
# <class 'float'> <class 'int'> <class 'float'> <class 'float'>
# 정수 → 실수
print(float(b)) # 10.0 (변환할 객체를, 바꾸고 싶은 클래스로 감싼다)
# 실수 → 정수
int(c) # c 자체가 바뀌지는 않는다
print(c) # 0.5
print(int(c)) # 0 (0.5 → 0, 소수점 이하가 버려진다)
# bool → 숫자
print(int(True)) # 1
print(float(True)) # 1.0
print(int(False)) # 0
print(float(False)) # 0.0
3.처럼 소수점 뒤를 비워도, .5처럼 앞을 비워도 실수로 인식된다. float()나 int()처럼 변환하고 싶은 클래스 이름으로 감싸는 방식이 JS의 Number(), parseInt()와 비슷하다. True는 1, False는 0이다.
# 수치 함수
print(abs(-42)) # 42 (절댓값)
print(pow(3, 4)) # 81 (밑수와 지수)
Python에서도 =는 대입 연산자다.
| 코드 | 의미 |
|---|---|
\n | 개행 문자 (엔터) |
\t | 탭 |
\\ | 문자 \ 자체 |
\' | 작은따옴표 (작은따옴표로 감싼 문자열 안에 '를 넣을 때) |
\" | 큰따옴표 (위와 동일) |
\000 | \ 뒤에 8진수를 붙여 해당 아스키 문자를 표현 (거의 쓰지 않음) |
print('Hello\nWorld') # Hello (줄바꿈) World
print('Hello\tWorld') # Hello World
print('Hello\\World') # Hello\World
print('Hello\'World') # Hello'World
print('Hello\"World') # Hello"World
print('Hellod\063World') # Hellod3World (8진수 063 = 아스키 '3')
print('\000') # 화면에 보이지 않는 null 문자
print('python welcome')
print("python welcome")
print('''python
wel
come''') # 여러 줄에 걸쳐 출력할 때 유용
print("""python
wel
come""") # 위와 동일
print() # 빈 줄(엔터)
print("Python's favorite food is perl")
# 큰따옴표 안에 작은따옴표를 넣어도 된다
# print('Python's favorite food is perl')
# 작은따옴표 안에 작은따옴표를 넣으면 오류 발생
say = '"Python is very easy" he says'
# 반대로 큰따옴표를 출력하고 싶으면 작은따옴표로 감싼다
print(say)
작은따옴표(')와 큰따옴표(")는 JS처럼 둘 다 문자열을 만들 수 있어서, 안에 들어갈 따옴표와 다른 쪽으로 감싸면 이스케이프가 필요 없다. 따옴표 세 개(''', """)로 감싸면 여러 줄 문자열이 된다. JS의 템플릿 리터럴(백틱) 중 줄바꿈 기능과 비슷하다.
len()은 문자열의 길이를 구하는 함수다. 띄어쓰기도 포함해서 센다. 파이썬도 숫자를 0부터 센다.
str1 = 'Python interesting'
print(str1[7]) # i
print(str1[0:3]) # Pyt (0~2)
print(str1[:]) # Python interesting (처음부터 끝까지)
print(str1[:4]) # Pyth (0~3)
print(str1[4:]) # on interesting (인덱스 4부터 끝까지)
print(len(str1)) # 18
print(str1[:len(str1)]) # 전체 (0부터 길이-1까지)
print(str1[1:-2]) # ython interesti (인덱스 1부터 -2 미만까지)
print(str1[-4:-2]) # ti
print(str1[1:4:2]) # yh (인덱스 1부터 3까지, 2칸씩 점프)
슬라이싱은 [시작:끝:증감] 형태다. 뒤에 오는 숫자(끝)는 "미만"이라는 점을 기억해야 한다. 음수 인덱스는 뒤에서부터 센다(-1이 마지막 글자). 세 번째 값은 건너뛰는 간격이다.
JS에서 substring, slice, charAt으로 따로 하던 것을 Python은 대괄호 하나로 한다.
# 주민번호를 연월일 부분과 뒤 숫자 부분으로 나누어 출력
pin = '881120-1068234'
yyyymmdd = '19' + pin[:6] # 앞에 '19'를 붙여서 1988이 되도록
num = pin[7:]
print(yyyymmdd) # 19881120
print(num) # 1068234
# 뒷자리 첫 번째 숫자(성별을 나타내는 숫자)
print(pin[7]) # 1
% 서식 문자 (C 스타일)| 서식 | 의미 |
|---|---|
%s | 문자열 |
%d | 정수 |
%f | 실수 |
%c | 문자 1개 |
print('문자열 %s와 문자열 %s가 있다.' % ('one', 'two'))
# 문자열을 끝내고, 배치할 값을 % 뒤 괄호에 한 번에 정리
print('%d %f %s' % (3, 7.6, 'abc')) # 3 7.600000 abc
%f는 기본적으로 소수 6자리까지 출력한다.print('%10s' % 'hello') # 10칸에서 오른쪽 정렬 (앞에 공백 5칸)
print('%-10sBut' % 'go home') # 10칸에서 왼쪽 정렬, 뒤에 But
print('%d,%d' % (4, 6)) # 4,6
print('%20s' % 'python') # 20칸에서 오른쪽 정렬
print('%.4f' % 3.1424885) # 3.1425 (3.1424가 아니라 반올림되어 3.1425)
print('%10.4f' % 3.1424885) # ' 3.1425' (10칸, 소수점 4자리, 오른쪽 정렬)
print('%.5s' % 'python javascript') # pytho (5글자까지만 출력, 절삭)
print('%06.2f' % 3.1475861254) # 003.15 (총 6칸, 소수 2자리, 빈칸은 0으로)
% 앞의 -는 왼쪽 정렬, .숫자는 소수점 자릿수(문자열이면 글자 수), 앞에 0을 붙이면 빈 공백을 0으로 채운다.
x = 30
y = 50
z = 17650
name = 'Kim'
ex1 = '%s %f %d' % (name, z, (x + y))
print(ex1) # Kim 17650.000000 80
print(type(z)) # <class 'int'> (z 자체는 정수 그대로)
%f로 출력했어도 z가 실수로 바뀌는 것은 아니다. 출력 모양만 바뀐다.
필기 코드에서는 위의
name자리에str='Kim'처럼str을 변수 이름으로 썼다.str은 Python이 이미 쓰고 있는 이름(문자열 클래스)이라, 이렇게 덮어쓰면 뒤에서str(60)처럼 형 변환에 쓸 때'str' object is not callable오류가 난다. 위 코드에서는name으로 바꿨고, 아래 f-string 예제도 같다.
format() 함수print('I eat {0} apples.'.format(3))
# format은 문자, 실수, 정수를 구분하지 않는다. 소속된 순서(0~n)대로 들어간다
print('{} {}'.format('one', 'two')) # one two (번호를 굳이 안 써도 된다)
print('{1} {0}'.format('one', 'two')) # two one (0부터 시작하니 순서가 바뀐다)
print('{0} {1}'.format(1, 2)) # 1 2 (숫자, 문자 섞어도 된다)
{:정렬 칸수} 형태이고, 정렬 앞에 문자를 쓰면 그 문자로 빈 칸을 채운다.
| 형태 | 의미 |
|---|---|
{:>10} | 10칸, 오른쪽 정렬 |
{:<10} | 10칸, 왼쪽 정렬 |
{:^10} | 10칸, 가운데 정렬 |
{:->20} | 20칸, 오른쪽 정렬, 빈칸은 - |
{:+<10} | 10칸, 왼쪽 정렬, 빈칸은 + |
print('%10s' % 'python') # 오른쪽 정렬 (% 서식)
print('{:>10}'.format('python')) # 같은 결과 (format)
print('%-10s' % 'python') # 왼쪽 정렬
print('{:<10}'.format('python')) # 같은 결과
print('{0:<10}'.format('die')) # 왼쪽 정렬
print('{0:>10}'.format('hello')) # 오른쪽 정렬
print('{0:^10}'.format('oasis')) # 가운데 정렬
print('%20s' % 'script')
print('{0:->20}'.format('script')) # 오른쪽 정렬, 여백을 -로 채우기
print('{0:+<10}'.format('script')) # 왼쪽 정렬, 여백을 +로 채우기
print('{0:_<10}'.format('python')) # 왼쪽 정렬, 여백을 _로 채우기
print('{0:.^10}'.format('python')) # 가운데 정렬, 여백을 .으로 채우기
% 서식은 %가 따옴표 밖에 있고('%10s' % 'python'), format은 문자열 뒤에 .format()을 붙이는 구조다.
name = '홍길동'
age = 70
msg = f'나의 이름은 {name}입니다. 나이는 {age}입니다.'
print(msg) # 나의 이름은 홍길동입니다. 나이는 70입니다.
문자열 앞에 f를 붙이고, { } 안에 변수나 식을 바로 쓴다. JS의 템플릿 리터럴(${name})과 거의 같은 역할이다.
같은 문장을 세 방식으로 비교해 보면 이렇다.
x = 10
y = 30
z = 'Lee'
# C 스타일 (서식 문자)
test1 = 'z=%s,sum=%d' % (z, (x + y))
print(test1) # z=Lee,sum=40
# format 함수
test2 = 'z={z}, sum={sum}'.format(z=z, sum=(x + y))
print(test2) # z=Lee, sum=40
# 0, 1 같은 번호가 아니라 이름을 쓰면 format 안에서 이름=값으로 지정해야 한다
# f-string
test3 = f'z={z},sum={x + y}'
print(test3) # z=Lee,sum=40
# f가 이미 format을 뜻하므로 뒤에 .format()을 붙일 필요가 없다
| 방식 | 모양 | 특징 |
|---|---|---|
% 서식 | '%s %d' % (a, b) | C 스타일. 값은 따옴표 뒤에 모아서 쓴다 |
format() | '{} {}'.format(a, b) | 번호나 이름으로 지정 |
| f-string | f'{a} {b}' | 변수와 식을 바로 쓴다. 가장 짧다 |
print(f"{'hello':<10}") # hello (hello 포함 10글자, 왼쪽 정렬)
print(f"{'hello':^10}") # hello (10글자, 가운데 정렬)
n = 50
print(f'{n:^10}') # 10칸에 n을 가운데 정렬
print(f'{n:@<20}') # 20칸, 왼쪽 정렬, 빈칸은 @
print(f'{n:@>10}') # 10칸, 오른쪽 정렬, 빈칸은 @
print(f'{n:-<10}') # 10칸 확보, 빈칸을 -로 채우기 (왼쪽 정렬)
print(f'{n:#>20}') # 20칸 확보, 빈칸을 #로 채우기 (오른쪽 정렬)
format에서 배운 :정렬칸수 규칙이 f-string에서도 그대로 쓰인다. 문자열은 따옴표 안에 따옴표가 들어가니 바깥을 큰따옴표로 감싼 것(f"{'hello':<10}")에 주의한다.
Python에는 배열이 없다. 그 자리를 리스트가 대신한다.
리스트의 특징은 순서가 있고(o), 중복을 허용하고(o), 수정할 수 있고(o), 삭제할 수 있다(o).
list1 = []
list2 = list() # [] (list 객체로 만든 빈 리스트)
print(list1, list2) # [] []
print(type(list1), type(list2)) # <class 'list'> <class 'list'>
list3 = [60, 100, 98, 95]
list4 = [1000, 1000, 'Tom', 'Amy']
list5 = [1000, 1000, ['red', 'green', 'blue']] # 리스트 안에 리스트를 넣을 수 있다
list6 = [3.42, 'python', 3, 1] # 자료형이 섞여도 된다
print(list3, list4, list5)
필기에는
list2 = list(1, 2)라고 하면 1, 2를 값으로 가진 리스트가 된다고 적혀 있었는데, 실제로는list(1, 2)가 오류(list expected at most 1 argument, got 2)다.list()는 인자를 하나만 받고, 그 인자는 리스트나 튜플처럼 순회할 수 있는 것이어야 한다. 값 두 개로 리스트를 만들려면list((1, 2))나 그냥[1, 2]를 쓴다.
print(list3[0]) # 60
print(list4[0] + list4[1] + list4[1]) # 3000 (같은 숫자 타입이라 더해진다)
print(list4[-1]) # Amy (뒤에서 첫 번째)
print(list5[-1][1]) # green (마지막 요소 ['red','green','blue']의 인덱스 1)
리스트 안에 리스트가 있으면 [ ][ ]로 겹쳐서 접근한다.
print(list4[0:3]) # [1000, 1000, 'Tom']
print(list4[2:]) # ['Tom', 'Amy'] (인덱스 2부터 끝까지)
print(list5[2][1:3]) # ['green', 'blue'] (안쪽 리스트의 인덱스 1부터 3 미만)
문자열 슬라이싱과 똑같은 규칙이다.
print(list3 + list4) # 리스트 합치기
print(list3 * 3) # list3을 3번 반복
# print(list3[0] + 'hi') # 에러: 60은 문자열이 아니라서 더할 수 없다
print(str(list3[0]) + 'hi') # 60hi (str()로 형 변환)
print(list4[2] + 'hi') # Tomhi (이미 문자열이라 더할 수 있다)
JS에서는 60 + 'hi'가 알아서 '60hi'가 되었지만, Python은 숫자와 문자열을 +로 더하면 오류가 난다. 직접 str()로 바꿔야 한다. JS와 가장 크게 다른 부분 중 하나다.
list3[0] = 4
print(list3) # [4, 100, 98, 95] (원래 60이었음. 원본이 바뀐다)
list3[1:2] = ['a', 'b', 'c']
print(list3) # [4, 'a', 'b', 'c', 98, 95]
# list3[1:2] = [['a','b','c']] 처럼 한 겹 더 감싸면 리스트 안에 리스트가 들어간다
list3[1:2] = [] # 인덱스 1 구간을 빈 리스트로 바꾼다 = 삭제
print(list3) # [4, 'b', 'c', 98, 95]
값을 대입해서 리스트를 수정할 수 있다. 슬라이스([1:2])에 대입하면 그 구간이 대입한 리스트의 요소로 통째로 바뀐다. 요소 하나를 여러 개로 늘릴 수도 있고, 빈 리스트를 대입해서 지울 수도 있다.
del list3[3] # 인덱스 3의 값을 삭제
print(list3) # [4, 'b', 'c', 95] (98이 삭제됨)
print(list4) # [1000, 1000, 'Tom', 'Amy']
같은 값이 두 번 들어 있어도 그대로 출력된다. 리스트는 중복을 허용한다.
오늘 교육에서 중요한 것으로 짚은 것은 f-string, format 함수, 리스트의 특징과 함수였다.
a = [5, 3, 2, 4, 1]
a.append(6) # 인수를 리스트 끝에 추가 (원본 변경)
print(a) # [5, 3, 2, 4, 1, 6]
a.sort() # 오름차순 정렬 (원본 변경)
print(a) # [1, 2, 3, 4, 5, 6]
a.reverse() # 거꾸로 정렬 (원본 변경)
print(a) # [6, 5, 4, 3, 2, 1]
print(a.index(5)) # 1 (5의 인덱스를 찾는다)
a.insert(2, 7) # 인덱스 2에 7을 삽입 (원본 변경)
# 인덱스 2의 값을 바꾸는 게 아니라, 그 자리에 끼워 넣고 기존 값들은 뒤로 밀린다
print(a) # [6, 5, 7, 4, 3, 2, 1]
a.reverse() # 다시 뒤집기 (원본 변경)
print(a) # [1, 2, 3, 4, 7, 5, 6]
a.remove(1) # 괄호 안의 값을 삭제. 같은 값이 여러 개면 첫 번째 것만 삭제
print(a) # [2, 3, 4, 7, 5, 6]
a.pop() # 마지막 요소를 제거
print(a) # [2, 3, 4, 7, 5]
print(a.pop()) # 5 (pop은 제거한 값을 돌려준다)
print(a) # [2, 3, 4, 7]
print(a.count(4)) # 1 (4의 개수)
print(a.count(1)) # 0 (없으면 0)
ex1 = [8, 9]
a.extend(ex1) # a 리스트 뒤에 ex1의 요소를 이어 붙인다
print(a) # [2, 3, 4, 7, 8, 9]
| 메소드 | 동작 | 원본 |
|---|---|---|
append(x) | 끝에 요소 추가 | 변경 |
insert(i, x) | 인덱스 i에 x를 끼워 넣기 | 변경 |
extend(리스트) | 끝에 다른 리스트의 요소를 이어 붙이기 | 변경 |
remove(x) | 값 x를 찾아 삭제 (첫 번째만) | 변경 |
pop() | 마지막 요소 제거 (제거한 값을 반환) | 변경 |
sort() | 오름차순 정렬 | 변경 |
reverse() | 순서 뒤집기 | 변경 |
index(x) | 값 x의 인덱스 반환 | 유지 |
count(x) | 값 x의 개수 반환 | 유지 |
JS의 push, pop, sort, reverse와 같은 일을 하지만 이름과 쓰임이 다르다. push가 append, 맨 앞을 건드리는 unshift는 insert(0, x)에 해당한다.
한 가지 조심할 점이 있다. Python의 sort()와 reverse()는 원본만 바꾸고 None을 반환한다. Day.5에서 n = ary.sort()로 정렬된 배열을 받았던 JS와 달리, a = a.sort()라고 쓰면 a가 None이 되어 버린다.
li4 = [3, 3, 'Tom', 'Amy']
li5 = [1, 3, ['바나나', '사과', '파인애플']]
# li4의 마지막 값 출력
print(li4[3]) # Amy
# li5의 사과 출력
print(li5[2][1]) # 사과
# li4를 거꾸로 출력
li4.reverse()
print(li4) # ['Amy', 'Tom', 3, 3]
# 같은 방식: print(li4[::-1])
# 처음과 끝을 비우면 전체이고, 증감이 -1이라 뒤에서부터 출력한다
a = 'abcdefg'
print(a[0:5:2]) # ace (초기 인덱스 : 끝 인덱스(미만) : 증감)
li4.reverse()는 원본을 뒤집고, li4[::-1]은 원본은 그대로 두고 뒤집은 복사본을 만든다는 차이가 있다.
Python을 JS와 나란히 놓으면 비슷한 것, 다른 것, 없는 것이 구분된다.
let, const 없이 x = 3으로 만들고, 불린은 True/False로 대문자로 시작한다.+로 숫자와 문자열을 더하면 오류가 난다.[시작:끝:증감]은 끝이 "미만"이고, 음수 인덱스는 뒤에서부터 센다.%, format(), f-string 세 가지가 있고, 정렬 규칙(:<10, :^10, :>10, 채울 문자)은 format과 f-string에서 같다.sort()와 reverse()는 None을 반환한다.Tags: Python 자료형 문자열 슬라이싱 f-string format 리스트 개발자 학습기록