파이썬 알고리즘 인터뷰
📚📚📚👈🏻 책 구매 링크
🤴🏻👸🏻👵🏻👴🏻 👈🏻 소스코드 깃허브
😥😱🤪👈🏻 책 정오표
🏓📡📺 👈🏻 유투브 채널
파이썬
귀도 반 로섬 Guido Van Rossum 1989년 12월 새로운 언어를 만들기로 결심한다.
원칙은 간단하다.
1. 읽기 쉬어야 한다.
2. 사용자가 원하는 모듈 패키지를 만들 수 있어야 한다. 다른 프로그램에서 사용할 수 있어야 한다.
3. 독특하고 약간 신비로운 이름을 원한다.
(70년대 세계를 풍미한 영국의 코미디 그룹 몬티 파이썬의 이름을 따서 붙였다.)
30여 년이 지난 지금 파이썬은 세상에서 가장 인기있는 프로그래밍 언어가 되었다.
파이썬은 '실행 가능한 수도코드 Executable Pseudocode' 라는 별칭으로도 불린다.
원래 수도코드란 실행이 되지 않는, 알고리즘만을 기술하는 코드를 말하는데,
파이썬은 알고리즘만을 기술할 정도로 간결하면서도 실행까지 가능했다.
또한, 파이썬은 입문용으로 초등학생들도 배우는 반면, 컴퓨터과학 박사들이 세계 최고 수준의 학회에 제출할 논문을 작성하는 데 사용하고 있다. 어떠한 언어도 이뤄내지 못한 일들을 파이썬은 하고 있다.
파이썬에 대한 이해
파이썬을 코딩 테스트에 활용하긴 하지만, 언어에 대한 숙지를 기반하지 않으면 무용지물이다.
어설프게 알고 있는 것은 더욱 위험하다.
이 책은 파이썬의 공식 인터프리터 Interpreter 인 CPython 을 기준으로 한다. 인터프리터에는 이외에도 Pypy(파이파이)를 비롯한 여러 훌륭한 제품이 있다.
PEP Python Enhancement Proposals : 파이선 개선 제안서, 새로운 기능을 제안하고 커뮤니티의 의견을 수렴하여 파이썬의 디자인 결정을 문서화하는 파이썬의 주요 개발 프로세스를 일컫는다. PEP는 나름 규칙으로 번호를 부여한다.
1~15까지는 메타 PEP이다. PEP에 대한 PEP로써, 대표적인 스타일 가이드인 PEP 8 은 여기에 해당한다.
전체 PEP 목록은 여기에서 확인 할 수 있다.
문법
Indent 인덴트 :
PEP 8 따라 공백 4칸을 원칙으로 한다. (강제는 아니다.)
Naming Convention 네이밍 컨벤션 :
자바와 달리 각 단어를 밑줄(_)로 구분하여 표기하는 스네이크 케이스를 따른다.(Snake Case) 이는 변수, 함수에도 해당한다. 파이썬다운 방식 Pythonic Way 를 추구한다.
파이썬의 PEP 8 및 철학에 따라 스네이크 코딩을 지향한다고 얘기할 수 있어야 한다.
Type Hint 타입 힌트 :
파이썬은 동적 타이핑 언어임에도, 타입을 지정할 수 있는 타입힌트가 PEP 484 문서에 추가되었다.
Python 3.5부터 사용가능하다.
a : str = "1"
b : int = 1
원래 파이썬에서 함수의 파라미터를 변수 타입 선언 없이 사용할 수 있다.
하지만 이러한 방식은 오류를 많이 불러오기 때문에 직접 변수 타입을 선언 가능하게 해주는 것이다.
def f(a):
....
def f(a: int) -> bool:
....
* mypy 를 사용하면, 타입 힌트에 오류가 없는지 자동으로 확인해준다. 코테중 사용하면 좋다.
pip install mypy
List Comprehension 리스트 컴프리헨션 :
기존 리스트를 기반으로 새로운 리스트를 만드러내는 구문을 뜻한다.
파이썬은 map, filter 같은 함수형Functional 기능을 지원하고, Lambda표현도 지원한다.
(python 94년부터 람다를 지원, java는 2014년 java 8부터 람다를 지원했다.
파이썬이 더 빨리 수용하였다. )
하지만,파이썬을 쓰다보면 람다보다 리스트 컴프리헨션이 더 유용하다.
[ n*2 for n in range(1, 10+1) if n %2 == 1]
>>> [ 2, 6, 10, 14, 18 ]
list(map(lambda x : x +10 , [ 1,2,3] ))
>>> [ 11, 12, 13 ]
처음에는 리스트에만 사용이 가능했지만, 버전 2.7 이후로는 딕셔너리 등도 사용 가능해졌다.
a = {}
for key, value in original.items():
a[key] = value
####
a = {key: value for key, value in original.items()}
이러한 컴프리헨션을 왜 사용하는가, 이유는 간단하다. 가독성 때문이다. ( 쉽게 읽혀야 한다.)
Generator 제너레이터 :
루프의 반복(iteration) 동작을 제어할 수 있는 루틴 형태를 말한다.
임의의 조건으로 숫자 1억 개를 만들어내 계산하는 프로그램을 작성하였을 때, 제너레이터가 없다면 메모리 어딘가에 만들어낸 숫자 1억 개를 보관하고 있어야 한다. 그러나 제너레이터가 있다면, 필요할 때 언제든 숫자를 만들어 낼 수 있다.
Yield 구문 : yield 를 사용하면, 제너레이터를 리턴할 수 있다.
기존이 함수는 return 을 통해 값을 내보내고 종료된다.
그러나 yield는 제너레이터가 여기까지 실행 중이던 값을 내보낸다는 의미이다. (양보하다라는 뜻이다.)
중간값을 리턴한 다음 함수는 종료되지 않고 계속해서 맨끝에 도달할 때까지 실행된다.
def get_number():
n = 0
while True:
n += 1
yield n
g = get_number()
for _ in range(0, 10):
print(next(g))
# 1 2 3 4 5 ... 98, 99, 100 이 출력된다.
Range 범위 :
range(시작점, 끝점 ) , range(끝점) 등으로 표현된다.
Enemerate 열거 :
순서가 있는 자료형 인덱스를 포함한 객체로 리턴해준다.
// 나눗셈 연산 :
나눗셈의 표현은 / 이지만, 해당 연산을 사용하면 결과가 Float형태로 출력된다. 내림을 통해서
딱 몫을 구하기 위해서는 // 연산을 사용하여 나눗셈을 한다. // 을 사용하기 싫다면, /연산에 int()로 감싸주면된다.
나머지는 % 연산으로 사용한다.
print :
코테에서 print()를 통해서 디버깅을 하는 경우가 많다.
실무에서는 이러한 방법은 좋지 않다.
간단한 print기능을 보자.
print('a' , 'b')
# a b
print('a', 'b', sep = ',')
# a,b
print('a', end = ' ')
print('b')
# a b
end를 사용하여 줄바꿈을 방지할 수 있다. sep을 통해서 구분의 기준을 만들어 줄 수 있다.
sample = ['a', 'b']
print(' '.join(smaple))
# a b
index = 1
fruit = 'apple'
print('{0}: {1}'.format(index + 1, fruit))
# 2: apple
print(f'{index+1}: {fruit}')
# 2: apple
f-string의 경우 파이썬 3.6+ 버전에서만 사용 가능하다. (formated string literal)
%, .format을 사용하는 방식보다 간결하고 속도도 빠르다.
pass :
틀을 잡아두고 코딩을 하거나, 함수명을 선언하고 빈 칸으로 두고 진행해두고 싶은 경우 사용한다.
즉, 함수를 정의하고 기능을 집어넣기 전에 비어있는
(null, none)상태를 코드에서는 인정을 하지 않지만 pass를 사용하면 가능하다.
class MyClass(obj):
def aa(self):
pass
def bb(self):
print('hello')
c = MyClass()
locals :
로컬 심볼 테이블 딕셔너리를 가져오는 메소드이다. 업데이트 또한 가능하다.
디버깅에 도움이 된다.
클레스의 특정 메소드 내부에서나 함수 내부의 로컬 정보를 조회해 잘못 선언한 부분이 없는지 확인하는 용도로 활용할 수 있다.
변수명을 일일히 찾아낼 필요 없이 로컬 스코프에 정의된 모든 변수를 출력하기 때문에 편리하다.
import pprint
pprint.pprint(locals())
보기 좋게, 줄바꿈을 하여 출력해주어 가독성을 높일 수 있다.
코딩 스타일
좋은 코드는 가능한 한 많은 사람이 좋아하며 선호하는 방식을 택하는 것이 중요하다.
개발은 혼자서만 하는 것이 아니며, 좋은 코드란 모두가 이해할 수 있을 때 더 높은 가치를 발휘하기 때문이다.
변수명과 주석
클리코드책에서는 코드에 주석을 달지 말라고 주장하지만,
특히 자바가 아닌 다른 언어에서 주석을 달지 않는 코드를 작성하는 건 여전히 논란의 여지가 있다.
(개인의 취향이지만, 주석을 달아야 다른 사람이 보기에 더 수월해진다. 주석이 속도를 느리게 하는 것은 아니다.)주석은 영어로 다는 습관을 들이는 것이 좋다. 최소한 영어로 주석을 읽고 다는데에 부담이 없어야 한다.
리스트 컴프리헨션 List Comprehension
무조건 짧은 코드가 가독성이 좋은 것은 아니다. 분명 파이썬에서 리스트 컴프리헨션은 좋은 기능이지만,
남용하면 오히려 가독성을 떨어트릴 수 있다.
대체로 이 표현식은 2개를 넘지 않도록 해야한다.
( 당연하다.)
구글 파이썬 스타일 가이드
이미 파이썬 PEP 가이드가 있지만, 구글에서 따로 만든 가이드도 참고하면 좋다.
먼저, 함수의 기본 값으로 가변 객체 Mutable Object 를 사용하지 않아야 한다.
함수가 객체를 수정하면 기본값이 변경되기 때문이다.
기본 값으로 [] 나 {} 를 사용하는 것은 지양하자.
대신 다음과 같이 불변 객체 Immutable Object 를 사용하여 None을 명시적으로 할당하는 것도 좋은 방법이다.
# NO!!
def foo(a, b=[]):
...
# YES !!
def foo(a, b= None):
if b is None:
b = []
True, False 를 판별할 때는 암시적 Implicit 인 방법을 사용한 편이 간결하다.
이런 방식은 가독성을 높인다.
즉, 굳이 False임을 if foo != [] : 같은 형태로 판별할 필요 없다.
if foo: 으로도 충분하다는 것이다.
# YES!!
if not users:
print('no user')
if foo == 0:
self.handle_zero()
if i % 10 == 0:
print('blah')
# NO!!!
if len(users) == 0:
print('no users')
if foo is not None and not foo:
print('굳이 이렇게..?')
if not i % 10 :
print('이것도 이상하다.')
여기서 하는 말은, 굳이 값이 없다는 말을 숫자 혹은 길이 등으로 표현 할 필요 없이
not users 등으로 표현하면 된다는 것이다.
암시적으로 거짓 여부를 판별하기 보다는 두번째 YES와 같이 정수값을 직접 비교하는 편이 덜 위험하다.
i % 10 == 0 처럼 명시적 implicit 하게 비교하는 편이 좋다.
'Algorithm > Algorithm' 카테고리의 다른 글
🧩 코딩 테스트 정복기 @21#B*04 (0) | 2021.01.31 |
---|---|
🧩 코딩 테스트 정복기 @21#B*02 (0) | 2021.01.28 |
🧩 코딩 테스트 정복기 @21#B*01 (0) | 2021.01.28 |