파이썬 기초 문법을 익히면서 "오~ 이거 좀 신선하다 !!"라고 느꼈던 내용들을 정리해봤습니다 ㅎㅎ
JS와 다른 문법들 위주로 정리해봤으니까 가볍게 봐주세요 🙇🏻♀️
일반적으로 파이썬의 연산 횟수가 500,000,000 이상
이면 5초~15초
소요
-> 하지만 코테의 시간제한은 보통 1~5초
임 (문제에 명시되어있지 않다면 5초라고 생각)
=> 파이썬이 1초에 20,000,000번의 연산
만 처리할 수 있다고 가정하기
때때로 PyPy가 더 빠름 (늘 그런 건 아님. 오히려 파이썬보다 메모리 소요가 더 클 때도 있음)
-> 파이썬으로 코드 잘 짰는데도 시간 초과 발생하면 PyPy로도 한번 제출해보기 (해당 코테가 PyPy를 지원한다면...)
시간 제한에 따른 시간복잡도 기준
시간 제한 | n의 범위 | 시간복잡도 | 예상 소요 시간 |
---|---|---|---|
1초 | 500 | O(N^3) | 125,000,000 |
(=> 20,000,000 이하만 가능) | 2,000 | O(N^2) | 4,000,000 |
100,000 | O(NlogN) | 1,151,293 | |
10,000,000 | O(N) | 10,000,000 |
수행 시간 측정 소스 코드
import time
start_time = time.time() # 측정 시작
~작성한 코드 넣기~
end_time = time.time() # 측정 종료
print("수행 시간: ", end_time - start_time) # 수행 시간 출력
/
b: a 나누기 b의 값. 소수점까지 다 계산됨 -> 실수//
b: a 나누기 b의 몫. 나눗셈의 몫만 계산됨e
또는 E
: 10의 지수 의미
=> 계산된 결과는 실수 데이터
, 주로 임의의 큰 수를 표현할 때 사용
num1 = 1e8 # 1 * 10^9 = 1,000,000,000.0
num2 = 4e5 # 4 * 10^5 = 400,000.0
컴퓨터가 계산한 실수끼리의 계산 값과 특정 실수값은 다를 수 있음
ex) 0.3 + 0.6 != 0.9 (2진수 체계라서 완벽한 계산 불가)
-> round(실수, 남겨둘 소수점 개수)
함수를 사용해 반올림하여 계산
0.3 + 0.6 == 0.9 # False
round(0.3 + 0.6, 2) == 0.9 # True
let으로 선언한 배열 같은 느낌.,, 요소 값 변경 가능 !!
특정한 값으로 리스트 초기화하기 -> [값] * 요소 개수
n = 5
a = [0] * n # a = [0, 0, 0, 0, 0] (크기는 n, 원소들은 0인 리스트)
인덱싱
: 인덱스로 접근해서 원소 찾기
-> 음의 인덱스도 가능 !! (뒤에서부터 -1, -2 ,-3, ...)
슬라이싱
: 연속적인 원소들을 통으로 가져오는 것, 원본 변화 x
-> list.[start:end+1]
: start부터 end까지 잘라줌
=> [start:]
: end 생략 -> start부터 끝까지
=> [:end+1]
: start 생략 -> 처음부터 end까지
=> [:]
: 처음부터 끝까지
리스트 컴프리헨션
: 대괄호 안에 조건문 & 반복분을 사용해서 리스트 초기화시킴 (만족하는 대상만 리스트로 생성)
-> 한 줄로 표현 가능하면서 직관적이며 속도까지 빠름
=> [반복 요소 (for 변수 in 리스트) (if문)]
numArr = [i for i in range(5)] # [0, 1, 2, 3, 4]
evevFourNumArr = [i for i in range(10) if i % 2 == 0 if i % 4 == 0] # [4, 8]
sqrtNumArr = [i*i for i in range(1, 5)] # [1, 4, 9, 16]
리스트 컴프리헨션을 이용한 2차원 리스트 초기화
가능
-> 주의할 점: 리스트를 그저 단순 반복하는 잘못된 컴프리헨션을 사용하지 않아야함
-> 전체 리스트 안에 포함된 각 리스트가 모두 같은 객체로 인식되어 이상한 결과 반환
# n * m 크기의 2차원 리스트를 0으로 한방에 초기화
n= 4
m= 3
nmArr = [[0] * m for _ in range(n)] # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
nmArr[1][1] = 1 # [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 0, 0]]
# 잘못된 방법 -> 처음은 초기화된 것처럼 보이지만
# 반복되는 부분들은 모두 같은 값을 가지게 되어 하나의 값을 바꾸면 반복되는 부분의 값이 전부 변경됨
wrongArr = [[0] * m] * n # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
wrongArr[1][1] = 1 # [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
_
: 언더바, 반복을 수행하지만 반복을 위한 변수는 사용되지 않아 그 값을 무시하고 싶을 때 사용 (단순 반복)for _ in range (5): print("Hello World") # Hello World 5번 출력됨
리스트 관련 주요 메서드
함수 | 의미 | 시간복잡도 | 함수 | 의미 | 시간복잡도 |
---|---|---|---|---|---|
append() | 리스트 끝에 원소 하나 삽입 | O(1) | reverse() | 리스트의 순서를 반대로 뒤집음 | O(N) |
sort() | 오름차순 정렬 | O(NlogN) | sort(reverse = True) | 내림차순 정렬 | O(NlogN) |
insert(삽입 위치, 삽입할 값) | 삽입할 위치 인덱스에 해당 값 끼워넣음 | O(N) | count(특정한 값) | 리스트에서 특정한 값의 개수 | O(N) |
remove(특정한 값) | 리스트에서 맨 처음 만나는 특정한 값 하나 제거 | O(N) |
리스트에 존재하는 특정한 값을 모두 제거하고 싶은 경우
arr = [1, 2, 3, 4, 5, 5, 5]
removeNumsSet = {3, 5}
result = [i for i in arr if not in removeNumsSet] # [1, 2, 4], removeNumsSet에 속하지 않은 숫자들만 리스트로 반환
```
문자열 * 숫자(양의 정수)
: 숫자만큼 해당 문자열 더해짐(반복)
문자열도 인덱싱
, 슬라이싱
가능 (인덱스값 변경은 안 됨)
여러 줄 문자 표현하기: 좌우에 백틱 3개씩 쓰고, 그 사이에 적으면 됨
sentences = ```백틱 3개로
여러 줄의 문자를
표현할 수 있어요
공백 띄어쓰기 다 가능 !!```
문자열 메서드
메서드 | 의미 | 메서드 | 의미 |
---|---|---|---|
lower() | 문자열 소문자로 변환 | upper() | 문자열 대문자로 변환 |
capitalize() | 문장 첫 글자만 대문자로 변환 | title() | 각 단어의 첫글자 대문자로 변환 |
swapcase() | 대소문자 서로 반대로 변환 | split() | 문자열 분리 |
startswith() | 해당 글자로 시작하는지 판별 | endswith() | 해당 글자로 끝나는지 판별 |
strip() | 앞 뒤의 불필요한 ()안의 해당 부분 제거 //trim()과 비슷함 | replace(찾을 문자, 바꿀 문자, 바꿀 개수 (앞에서부터 셈) | 해당 단어 바꾸기 |
find() | 단어 위치 찾기 | center() | 양 옆에 ()안 문자 붙여줌 |
const로 선언한 배열 같은 느낌.,, 요소값 변경 불가능
튜플도 인덱싱
, 슬라이싱
가능 (인덱스값 변경은 안 됨)
리스트보다 제한된 기능만 사용 가능하기 때문에 리스트에 비해 공간 효율적(메모리 사용량 적음)
튜플 사용이 유리한 경우
(실수, 정수)
, (정수, 문자열)
, ...해싱(사전 자료형, 집합 자료형)의 키 값
으로 사용할 때 (해싱의 키 값은 변경 불가능한 값만 사용가능하기 때문)키(Key)와 값(Value)의 쌍
을 데이터로 가지는 자료형 (순서 없음)
-> 해시 테이블을 이용하므로 데이터 조회 및 수정
에 상수시간
소요
=> Map같은 느낌 !!
.keys()
: 키 데이터만 뽑아내는 함수 -> dict_keys([]).values()
: 값 데이터만 뽑아내는 함수 -> dict_values([])# dict()으로 정의하시
data = dict()
data["사과"] = "Apple"
data["바나나"] = "Banana"
data["코코넛"] = "Coconut"
# 객체 형식으로 바로 정의하기
objectDict = {
"체리": "cherry",
"레몬": "lemon"
}
print(data) # {"사과": "Apple", "바나나": "Banana", "코코넛": "Coconut"}
print(objectDict) # {"체리": "cherry", "레몬": "lemon"}
if "사과" in data: # True
if "망고" in data: # False
data_keys = data.keys() # dict_keys(['사과', '바나나', '코코넛'])
data_keys_list = list(data.keys()) # ['사과', '바나나', '코코넛']
data_values = data.values() # dict_values(['Apple', 'Banana', 'Coconut'])
중복을 허용하지 않고, 순서가 없는 자료형 -> 데이터의 존재 여부만을 체크함
-> 데이터 조회 및 수정
에 상수시간
소요
=> Set 같은 느낌 !!
집합 자료형의 연산
a | b
: A와 B의 합집합 (A U B)a & b
: A와 B의 교집합 (A n B)a - b
: A와 B의 차집합 (B - A도 가능)집합 자료형 관련 주요 함수
add()
: 새로운 원소 추가update([원소들])
: 새로운 원소 여러 개 추가remove()
: 특정한 값을 갖는 원소 삭제 -> 집합이라 어차피 1개뿐# set() 함수를 이용해 집합 자료형 초기화 (문자열, 리스트 이용)
a = set([1, 1, 2, 3, 4, 4, 5]) # {1, 2, 3, 4, 5}
# 원소 직접 삽입해 집합 자료형 초기화
b = {3, 3, 4, 5, 6, 6, 7} # {3, 4, 5, 6, 7}
print(a | b) # {1, 2, 3, 4, 5, 6, 7}
print(a & b) # {3, 4, 5}
print(a - b) # {1, 2}
print(b - a) # {6, 7}
a.add(8) # {1, 2, 3, 4, 5, 8}
a.update([9, 10]) # {1, 2, 3, 4, 5, 8, 9, 10}
a.remove(9) # {1, 2, 3, 4, 5, 8, 10}
형 변환 문법 | 의미 | 형 변환 문법 | 의미 |
---|---|---|---|
int() | 정수 | float() | 실수 |
str() | 문자열 | bool() | 불리언값 |
내림
됨False
0, "", None, []
, ...input()
: 한 줄의 문자열을 입력 받는 함수map()
: 리스트의 모든 원소에 각각 특정한 함수를 적용할 때 사용하는 함수split()
: 공백을 기준으로 데이터 구분n = int(input()) # 1줄만 입력 받기 가능 ex) 5
# 공백을 기준으로 구분된 데이터 입력 받기
# -> 입력받은 공백 기준 구분된 한 줄 데이터(input().split())를 전부 숫자로 바꾼 뒤(map(int, inputData)) 리스트로 반환
dataList = list(map(int, input().split())) # ex) [10, 11, 12, 13, 14]
# 공백을 기준으로 구분된 데이터 입력 받기 (데이터 개수 안 많을 때)
a, b, c = map(int, input().split()) # ex) 10, 11, 12
sys.stdin.readline()
: 최대한 빠르게 입력 받는 메서드, sys 라이브러리에 정의되어있음
-> 입력하는 Enter가 줄 바꿈 기호로 같이 입력되므로, rstrip()
메서드를 함께 사용해야함
=> 입력의 개수가 많은 문제는 입력받는 시간때문에 시간초과 발생 가능 (이진탐색, 정렬, 그래프 문제에서 주로 사용)
import sys
data = sys.stdin.readline().rstrip() # 한 줄로 입력된 문자열 입력받음
print()
: 기본 출력 함수, 자동 줄바꿈됨
-> 줄바꿈이 싫다면 end
속성 이용해 마지막 부분 바꾸기
print()의 옵션
옵션 | 의미 |
---|---|
sep = "구분자" | 해당 구분자를 끼워 요소들 출력 |
end = "구분자" | 서로 다른 print문을 연결할 때 구분자로 구분(기본 옵션 줄바꿈) |
파이썬은 문자열 + 정수
로 출력 불가
-> str(정수)로 바꿔서 연결해야함
a = 1
b = 2
print(a, b)
print(a, end=" ")
print(b, end=" ")
print("문자열과 숫자 " + str(a) + "를 연결해서 출력")
# 1 2
# 1 2 문자열과 숫자 1를 연결해서 출력
출력을 위한 문자열 포맷
f-string
: 문자열 앞에 f
를 붙여 사용, 숫자도 형변환 필요 없음 (파이썬 3.6 이상만 가능)print(f"문자열과 숫자 {a}를 연결해서 출력)
# 문자열과 숫자 1를 연결해서 출력
print(f"제가 좋아하는 과일은 {사과}, {망고}입니다.")
# 제가 좋아하는 과일은 사과, 망고입니다.
# {} + 포맷 -> 순서대로 매칭
print("제가 좋아하는 과일은 {}, {}입니다.".format(사과, 망고)) # 제가 좋아하는 과일은 사과, 망고입니다.
# {N} + 포맷 (N = 0, 1, 2, ...) -> 번호에 맞게 매칭됨
print("제가 좋아하는 과일은 {1}, {0}입니다.".format(사과, 망고)) # 제가 좋아하는 과일은 망고, 사과입니다.
블럭(Block)
: 한 기능을 수행하기 위한 코드의 묶음
-> 블럭 구분은들여쓰기(Indent)
으로 지정함 (같은 들여쓰기 부분이 한 블럭)range(시작값, 끝값+1)
=> 인자가 1개이면 시작값이 0으로 간주됨
if ~ elif ~ else문
: else if가 elif임
-> 조건문에서 실행되는 코드가 한 줄이면, 줄바꿈 하지 않고 한 줄에 써도 됨 !
삼항연산자: True일 때의 실행 코드 if 조건 else False일 때 실행 코드
파이썬의 부등식은 연속비교를 허용함 ex) 0 < x < 20
-> 다른 언어의 x > 0 and x < 20
과 같은 의미
=> 하지만 다른 언어와 동일한 문법을 쓰는 것을 추천
for 변수 in 데이터들(리스트, 튜플, ...)
: 데이터들에 포함된 원소를 첫 번째 인덱스부터 차례대로 방문
pass
: 그냥 통과시킬 코드 블럭, 기능을 하지 않고 일단 비워두는 부분
print("만점입니다." if score === 100 else "채점이 필요합니다.")
if score > 90:
pass # 해당 조건에 해당되어도 어떠한 기능 없이 다음으로 넘어감
elif score > 80:
print("80점이 넘는 점수입니다.")
print("B등급 입니다.")
else: print("C등급 입니다.") # 줄바꿈 없이 한 줄에 작성
print("채점 끝!")
논리 연산자
: 기호 대신 영어 단어를 씀 !!
논리 연산자 | 의미 |
---|---|
X and Y | 둘 다 참일 경우 (= &&) |
X or Y | 둘 중 하나만 참이어도 되는 경우 |
not X | X가 거짓이어야 참인 경우 |
멤버 연산자
: 여러 개의 데이터를 담는 자료형에 사용(리스트, 튜플, 문자열, 딕셔너리, ...)
멤버 연산자 | 의미 |
---|---|
x in 데이터 | 데이터 안에 x가 있어야 참 |
x not in 데이터 | 데이터 안에 x가 없어야 참 |
# 멤버 연산자 사용법
print("a" in "apple") # True
print("a" in [1, 2, 3, 4, 5]) # False
print("a" not in "apple") # False
print("a" not in "banana") # True
인자(args)
: 함수를 호출할 때 전달하는 값
ex) print(func(1, 2))매개변수(parameter)
: 함수를 생성할 때 받는 값
ex) def func(a, b): ~
파이썬은 파라미터의 변수를 직접 지정할 수 있음
-> 파라미터와 인자의 순서가 달라도 상관 없음 !!
global
: 함수 안에서 사용되는 전역 변수에 global 키워드를 붙이면 함수 바깥에 선언된 전역 변수값을 바로 참조하기 때문에, 함수 안에서 사용하려는 변수를 또 선언하지 않아도 바깥 전역 변수 사용 가능 (안에서 값 바꾸면 전역변수의 값도 바뀜)
=> 함수 안에서 함수 바깥에 선언된 전역변수를 바로 사용하겠다고 명시하는 키워드
-> 값 변경 / 새로운 값 대입
이 아닌 단순한 값 참조
의 경우에는 굳이 안 붙여도 됨
-> 전역 변수 리스트
에 append()로 단순히 값 추가할 때도 없어도 됨
패킹
: 함수가 여러 개의 값을 한번에 반환하는 것 (반환된 순서에 맞게 값 저장됨)
def minus(a, b):
print(a - b)
minus(5, 2) # 3
minus(b = 2, a = 5) # 3
k = 0
l = [1, 2, 3, 4, 5]
def func():
print(k + 20) # 20, 단순히 값 참조하는 것이기 때문에 global 키워드 / 재정의 없어도 오류 안 뜸
l.append(6) # [1, 2, 3, 4, 5, 6], 단순한 값 추가라 오류 안 뜸
def func_1():
k = 0 # 이 구문 없으면 k가 정의되지 않았다는 오류 뜸
k += 1
print(k) # 1, func_2()와 같은 의미의 함수
def func_2():
global k
k += 1
print(k) # 1, func_1()와 같은 의미의 함수
l = [3, 4, 5]
l.append(6) # [3, 4, 5, 6], global 없으니 같은 이름이어도 함수 안에서 새로 정의된 같은 이름의 변수가 우선시됨
def packingFunc(a, b):
return a+b, a-b, a*b
plus, minus, multip = packingFunc(2, 1) # 3, 1, 2
특정한 기능을 수행하는 함수를 한 줄에 바로 작성할 수 있음
=> (lambda (매개변수): 반환 결과)(인자)
-> 이름없는 함수
라고도 불림
students = [("영희", 50), ("민호", 30), ("철수", 75)]
def scores(x):
return x[1]
print(sorted(students, key = scores)) # [("민호", 30), ("영희", 50), ("철수", 75)]
print(sorted(students, key = lambda x: x[1])) # [("민호", 30), ("영희", 50), ("철수", 75)]
list_1 = [1, 2, 3, 4, 5]
list_2 = [6, 7, 8, 9, 10]
result = map(lambda a, b: a + b, list_1, list_2) # [7, 9, 11, 13, 15]
내장 함수
: 별도의 import 필요 없음
=> 기본 입출력, 정렬 등 필수 기본 함수 제공
eval("(3+5) * 7") # 56, 수식의 형태를 계산해서 숫자로 반환해줌
itertools
: 반복되는 형태의 데이터를 처리하기 위한 기능
=> 특히 순열
, 조합
라이브러리가 모든 경우를 고려해야하는 문제에 사용됨(완전 탐색 문제)
data = ['A', 'B', 'C']
from itertools import permutations # 순열 import
permutation = list(permutations(data, 3)) # [('A','B','C'), ('A','C','B'), ('B','A','C'), ('B','C','A'), ('C','A','B'), ('C','B','A')]
# -> 모든 순열(3개를 선택해 순서대로 나열) 구해서 list로 반환
from itertools import product # 중복 순열 import
dupPermutation = list(product(data, repeat=2))
# -> 2개 뽑는 모든 순열 구하기 (중복 허용)
from itertools import combinations # 조합 import
combination = list(combinations(data, 2)) # [('A','B'), ('A','C'), ('B','C')]
# -> 2개를 뽑는 모든 조합 구해서 list로 반환
from itertools import combinations with_replacement # 중복 조합 import
dupCombination = list(combinations_ith_replacement(data, 2))
# -> 2개를 뽑는 모든 조합 구해서 list로 반환 (중복 허용)
heapq
: 힙(Heap) 자료구조 제공
=> 일반적으로 우선순위 큐를 구현하기 위해 사용됨 (다익스트라 같은 최단 경로 알고리즘)
bisect
: 기본적인 이진 탐색(Binary Search)
기능
collections
: 덱(deque), 카운터(Counter) 등의 자료구조 포함
=> Counter
: 반복 가능한 객체의 내부에 해당 원소가 등장한 횟수 세어줌
from collections import Counter # Counter import
counter = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
print(counter['blue']) # 3, 'blue'가 등장한 횟수
print(counter['green']) # 1, 'green'이 등장한 횟수
print(dict(counter)) # {'red': 2, 'blue': 3, 'green': 1}, 사전 자료형으로 각 요소별 개수 반환
math
: 필수적인 수학 기능