Python Code Snippet 리스트를 문자열로 바꾸면서 앞, 뒤에 문자열 추가하고 중간 중간에 들어갈 문자열도 직접 지정하기 iu = ["1", "2", "3"] print("", sep='') # 결과 : 리스트 2개 이상의 기준으로 정렬하기 iu = [[4,3],[2,1]] iu.sort(key=lambda x: (x[0], x[1])) print(iu) # [[2, 1], [4, 3]] 리스트에서 특정 단어 및 숫자의 인덱스가 여러개 있을 때 test_list = [1, 3, 4, 3, 6, 7] print("Original list : " + str(test_list)) res_list = list(filter(lambda x: test_list[x] == 3, range(len(test_..
파이썬 정규표현식 re 모듈 사용법 메타문자 파이썬에서는 특수한 기능을 하는 문자가 존재합니다. 이를 메타문자라고 하며 아래와 같이 존재합니다. $()*+.?[]\^{}| 정규표현식에 a는 문자 a와 매칭되지만 (는 (와 매칭되지 않습니다. 메타문자인 소괄호 (를 매칭하고자 하면 백슬래쉬인 \를 앞에 붙여 \(라 작성해야 문자 (와 매칭이 가능합니다. 이에 관한 설명은 여기를 참조하면 좋을 것 같습니다. re 모듈의 함수 match(pattern, string, flag) match()는 해당 패턴으로 문자열이 시작하는지를 판단합니다. import re print(re.match('a', 'ab')) print(re.match('a', 'bba')) print(re.match('a', 'ba')) # #..
문자열 내장 함수 upper() 문자열을 대문자로 변경합니다. >>> string = 'abc' >>> string.upper() 'ABC' lower() 문자열을 소문자로 변경합니다. >>> string = 'ABC' >>> string.lower() 'abc' capitalize() 첫 문자만 대문자로 변경하고, 나머지 문자들은 소문자로 변경합니다. >>> string = 'aBC' >>> string.capitalize() 'Abc' splitlines() 개행 문자를 기준으로 쪼갠다. >>> string = 'IU is \nvery pretty.' >>> string.splitlines() ['IU is ', 'very pretty.'] join() 리스트를 문자열로 바꿀 때 사용한다. >>> l..
리스트 append()와 extend()의 차이점 >>> a = [1,2,3] >>> b = [4,5] >>> a.append(b) >>> a [1, 2, 3, [4, 5]] 리스트에 또 다른 리스트를 삽입할 때 append()는 이처럼 리스트 전체를 또 다른 엘리먼트로 처리한다. >>> a = [1,2,3] >>> b = [4, 5] >>> a.extend(b) >>> a [1, 2, 3, 4, 5] 반면 extend()는 삽입 대상의 리스트를 풀어서 각각의 엘리먼트로 확장(Extend)해 삽입한다. 출처 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]
파이썬의 진법 표현 파이썬이 이진수(binary), 십진수(decimal), 16진수(hexadecimal)를 저장하고 표현하는 방법을 살펴보자. 먼저 이진수와 십진수는 다음과 같이 각각 bin()과 int()를 사용해서 서로 변환할 수 있다. >>> bin(87) '0b1010111' >>> int('0b1010111', 2) 87 bin()을 사용하면 이진수가 문자형 0b1010111으로 리턴된다. 반면 int()을 사용하면, 문자형인 이진수가 십진수 숫자 정수형 87로 리턴된다. 이진수임을 의미하는 접두사(Prefix) 0b는 다음과 같이 생략도 가능하다. >>> int('1010111', 2) 87 bin()을 사용해 변수에 값을 할당하면 다음과 같이 문자형이 된다. >>> a = bin(87) ..
any()와 all() 함수 >>> any([True, False, False]) True any()는 포함된 값 중 어느 하나가 참이라면 항상 참으로 출력한다. 논리 연산의 OR과 비슷하다. 반면 all()이라는 함수는 모든 값이 참이어야 True를 출력한다. >>> all([True, False, False]) False >>> all([True, True, True]) True 이처럼 all()은 논리 연산의 AND와 유사하다. 출처 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]
파이썬 콤마(,) 연산자 a += b, 연산자와 변수 뒤에 콤마(,)가 붙어 있다. 이렇게 하면 어떻게 동작할까? 먼저 콤마(,)가 없는 기본적인 추가 연산을 해보자. >>> a = [1] >>> b = [2, 3] >>> a += b >>> a [1, 2, 3] 단순히 +-를 했을 때는 요소를 이어붙인다. 행렬의 연결 연산과 동일하다. 이번에는 콤마를 넣어보자. >>> a = [1] >>> b = [2, 3] >>> a += b, >>> a [1, [2, 3]] 이렇게 중첩 리스트가 된다. 콤마는 중첩 리스트로 만들어주는 역할을 하며, 대괄호 []를 부여한 것과 동일한 역할을 한다. >>> a += [b] >>> a [1, [2, 3]] 출처 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [..
@staticmethod 데코레이터 @staticmethod는 자바의 메소드 static 선언과도 비슷한데, 이렇게 정의한 메소드는 클래스와 독립적인 함수로서의 의미를 강하게 갖는다. 파라미터에도 항상 따라붙는 self가 빠져 있고, 함수 자체가 별도의 자료형으로 선언되어 있다. class CLASS: def a(self): pass @staticmethod def b(): pass 이 같은 클래스가 선언되어 있을 때, 함수 a()와 b()의 타입을 출력해보자. >>> type(CLASS.a), type(CLASS.b) (, ) 클래스를 생성하지 않고 바깥에서 직접 호출했을 때 타입은 이처럼 둘 다 함수가 된다. >>> cls = CLASS() >>> type(cls.a), type(cls.b) (, )..
객체 복사 파이썬의 중요한 특징 중 하나는 모든 것이 객체라는 점이다. 심지어 숫자, 문자까지도 모두 객체다. 숫자, 문자가 리스트, 딕셔너리 같은 객체와의 차이점이라면 불변 객체라는 차이뿐이다. 그러다 보니 별도로 값을 복사하지 않는 한, 변수에 값을 할당하는 모든 행위는 값 객체에 대한 참조가 된다. 이 말은 참조가 가리키는 원래의 값을 변경하면 모든 참조, 즉 모든 변수의 값 또한 함께 변경된다는 말이기도 하다. 그렇다면 참조가 되지 않도록 값 자체를 복사하려면 어떻게 해야 할까? 가장 간단한 방법은 [:]로 처리하는 방법이다. >>> a = [1,2,3] >>> b = a >>> c = a[:] >>> id(a), id(b), id(c) (4362781552, 4362781552, 43615800..
중첩함수 중첩 함수(Nested Function)란 함수 내에 위치한 또 다른 함수로, 바깥에 위치한 함수들과 달리 부모 함수의 변수를 자유롭게 읽을 수 있다는 장점이 있다. 중첩 함수가 부모 함수의 변수를 공유하는 예제는 다음과 같다. def outer_function(t: str): test: str = t def inner_function(): print(text) inner_function( outer_function("Hello!') ----- Hello! 여기서 outer_function()은 inner_functuion()을 호출했고, 아무런 파라미터도 남기지 않았지만 부모 함수의 text 변수를 자유롭게 읽어들여 그 값인 Hello!를 출력했다. 이처럼 매번 파라미터를 전달하지 않아..
파이썬에서 언팩킹과 팩킹 zip()의 파라미터는 1개가 될 수도 있고, 2개가 될 수도, 10개가 될 수도 있다. 밑의 실험을 보면 알 수 있다. >>> a = ['a1', 'a2'] >>> b = ['b1', 'b2'] >>> c = ['c1', 'c2'] >>> d = ['d1', 'd2'] >>> list(zip(a)) [('a1',), ('a2',)] >>>list(zip(a, b)) [('a1', 'b1'), ('a2', 'b2')] >>> list(zip(a, b, c)) [('a1', 'b1', 'c1'), ('a2', 'b2', 'c2')] 여기에는 아스테리스크(Asterisk) 혹은 흔히 별표라고 부르는 *를 활용한다. 파이썬에서 *는 언팩(Unpack)이다. 시퀀스 언패킹 연산자(Seq..
해시란? 해시 함수란 임의 크기 데이터를 고정 크기 값으로 매핑하는 데 사용할 수 있는 함수를 말한다. 충돌 아무리 좋은 해시 함수라도 밑의 그림과 같이 충돌은 발생하게 된다. 이 그림에서 윤아와 서현은 해시 값이 2로 같은 값이 되어 충돌이 발생했다. 이처럼 충돌이 발생할 경우 어떤 식으로 처리하게 되는지 살펴보자. 개별 체이닝 입력 값을 밑의 표와 같이 정해보자. 해시는 키를 해싱한 결과며, '윤아'와 '서현'을 해싱한 결과는 충돌한다고 가정한다. 이 표를 개별 체이닝(Separate Chaining) 방식으로 구현하면 밑의 그림과 같다. 해시 테이블의 기본 방식이기도 한 개별 체이닝은 충돌 발생 시 이 그림과 같이 연결 리스트로 연결하는 방식이다. 충돌이 발생한 '..
내부 함수 명명 규칙 내부에서 사용한다는 의미로 PEP8 명명 규칙 기준에 따라 밑줄(_) 하나로 시작하도록 메소드 명을 정한다. class MycircularDeque: """ skip.... """ def _add(self, node: ListNode, new: ListNode): n = node.right node.right = new new.left, new.right = node, n n.left = new def insertFront(self, value: int) -> bool: if self.len == self.k: return False self.len += 1 self._add(self.head, ListNode(value)) return True 출처 파이썬 알고리즘 인터뷰 (글 :..
연결 리스트를 이용한 스택 ADT 구현 코드 class Node: def __init__(self, item, next): self.item = item self.next = next class Stack: def __init__(self): self.last = None def push(self, item): self.last = Node(item, self.last) def pop(self): item = self.last.item self.last = self.last.next return item stack = Stack() stack.push(1) stack.push(2) stack.push(3) stack.push(4) stack.push(5) 헷갈린 부분 처음에 Stack 클래스가 만들어지면..
숫자형 리스트를 단일 값으로 병합하기 a = [1, 2, 3, 4, 5]처럼 숫자형으로 이루어진 리스트가 있을 때 이를 하나로 합치는 좀 더 우아한 코드를 만들어 보자. >>> ''.join(str(e) for e in a) '12345' 이 방식의 코드는 아무래도 가독성이 떨어지고 영 보기가 좋지 않다. 좀 더 깔끔한 방법은 없을까? >>> ''.join(map(str, a)) '12345' 이 경우 임시 변수 e를 사용하지 않아 깔끔하며, map(str,로 이어지는 부분이 문자열로 변환을 암시하는 듯하여 가독성도 좋다. 코드 크기가 줄어듦은 물론이다. >>> functools.reduce(lambda x, y: 10 * x + y, a, 0) 12345 이런 식으로 처리할 수 있을 것 같다. func..
다중 할당 파이썬에서 다중 할당은 2개 이상의 값을 2개 이상의 변수에 동시에 할당하는 것을 말한다. 이 문제를 보면 다음과 같이 3개의 변수에 3개의 값을 할당한 바 있다. rev, rev.next, slow = slow, rev, slow.next 다음과 같이 두 줄로 분기하면 훨씬 더 가독성이 높은데, 굳이 한 줄로 처리한데에는 이유가 있다. rev, rev.next = slow, rev slow = slow.next 이렇게 두 줄로 늘어트릴 경우 rev, rev.next = slow, rev라는 구문에서 slow와 rev가 동일한 참조가 된다. 구문 중간에 rev = slow가 있으니 서로 같은 값을 참조하게 되는 것이다. 파이썬에는 원시 타입(Primiltive Types)이 존재하지 않는다. ..
유니코드와 UTF-8 초기에 문자를 표현하던 대표적인 방식은 ASCⅡ 인코딩 방식으로, 1바이트에 모든 문자를 표현했다. 게다가 1비트는 체크섬으로 제외하여 7비트, 즉 128글자로 문자를 표현했다. 그러다 보니 한글이나 한자 같은 문자는 2개 이상의 특수 문자를 합쳐서 표현하곤 했는데, 당연히 이런 방식은 비정상적이며, 경우에 따라서는 깨지거나 제대로 표현되지 않는 경우가 잦았다. 이런 문제를 해결하기 위해 2~4 바이트의 공간에 여유 있게 문자를 할당하고자 등장한 방식이 바로 유니코드다. 그러나 유니코드 자체는 1바이트로 표현이 가능한 영문자도 2바이트 이상의 공간을 사용하기 때문에 이를 그대로 사용하면 메모리 낭비가 심하고 따라서 이를 가변 길이 문자 인코딩 방식으로 효율적으로 인코딩하는 대표적인 ..
re 모듈 sub 함수 정규식과 매치되는 부분을 다른 문자로 바꾸어준다. sub 메서드의 첫 번째 매개변수는 바꿀 문자열이 되고, 두 번째 매개 변수는 대상 문자열이 된다. 그런데 딱 한 번만 바꾸고 싶은 경우도 있다. 이렇게 바꾸기 횟수를 제어하려면 다음과 같이 세 번째 매개변수로 count값을 넘기면 된다. import re s = "A man, a plan, a canal: Panama" s = re.sub('[^0-9a-z]', '', s) # 영어 소문자, 숫자 빼고 나머지 다 없앰. print(s) # s = "manaplanacanalanama" s = "A man, a plan, a canal: Panama" s = re.sub('[^0-9a-z]', '', s, count=1) print..
isalnum 함수 isalnum()는 영문자, 숫자 여부를 판별하는 함수 lower 함수 모두 소문자로 변환한다. class Solution: def isPalindrome(self, s: str) -> bool: strs: Deque = collections.deque() for char in s: if char.isalnum(): #영문자, 숫자 여부를 판별 strs.append(char.lower()) # 모두 소문자 변환 while len(strs) > 1: if strs.popleft() != strs.pop(): return False return True 출처 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]
typing 모듈 타입 어노테이션을 사용하다 보면 리스트, 사전, 터플, 세트와 같은 파이썬 내장 자료 구조에 대한 타입을 명시해야 할 때가 있습니다. 이럴 때는 typing 모듈에서 제공하는 List, Dict, Tuple, Set를 사용하여 타입 어노테이션을 추가한다. from typing import Deque class Solution: def isPalindrome(self, s: str) -> bool: strs: Deque = collections.deque() for char in s: if char.isalnum(): strs.append(char.lower()) while len(strs) > 1: if strs.popleft() != strs.pop(): return False ret..
제너레이터 제너레이터는 루프의 반복 동작을 제어할 수 있는 루틴 형태를 말한다. 예를 들어 임의의 조건으로 숫자 1억 개를 만들어내 계산하는 프로그램을 작성한다고 가정해보자. 이 경우 제너레이터가 없다면 메모리 어딘가에 만들어낸 숫자 1억 개를 보관하고 있어야 하낟. 그러나 제너레이터를 이용하면, 단순히 제너레이터만 생성해두고 필요할 때 언제든 숫자를 만들어낼 수 있다. 이때 yield 구문을 사용하면 제너레이터를 리턴할 수 있다. 기조느이 함수는 return 구문을 맞닥뜨리면 값을 리턴하고 모든 함수의 동작을 종료한다. 그러나 yield는 제너레이터가 여기까지 실행 중이던 값을 내보낸다는 의미로, 중간 값을 리턴한 다음 함수는 종료되지 않고 계속해서 맨 끝에 도달할 때까지 실행된다. yield의 값을 ..
locals locals()는 로컬 심볼 테이블 딕셔너리를 가져오는 메소드로 업데이트 또한 가능하다. 여기서는 딕셔너리를 가져오는 부분에 집중해 살펴보자면, 로컬에 선언된 모든 변수를 조회할 수 있는 강력한 명령이므로 디버깅에 도움이 된다. 변수명을 일일이 찾아낼 필요 없이 로컬 스코프에 정의된 모든 변수를 출력하기 떄문에 편리하다. import pprint pprint.pprint(locals()) """ {'__annotations__': {}, '__builtins__': , '__cached__': None, '__doc__': None, '__file__': '3.py', '__loader__': , '__name__': '__main__', '__package__': None, '__spec_..
sort + ramda 람다 표현식이란 식별자 없이 실행 가능한 함수를 말하며, 함수 선언 없이도 하나의 식으로 함수를 단순하게 표현할 수 있다. letters = ['let1 art can', 'let2 own kit dig', 'let3 art zero'] letters.sort(key=lambda x : (x.split()[1:], x.split()[0])) # 출력 : ['let1 art can', 'let3 art zero', 'let2 own kit dig'] 식별자를 제외한 문자열 [1:]을 키로 하여 정렬하며, 동일한 경우 후순위로 식별자 [0]를 지정해 정렬되도록, 람다 표현식을 이용해 정렬할 수 있다. 출처 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]
print 리스트를 출력할 떄는 join()으로 묶어서 처리한다. a = ['A', 'B'] print(' '.join(a)) # A B 다음과 같이 idx와 fruit이 정의되 있을 때 가장 선호되는 print() 방법은 f-string이다. 변수를 뒤에 별도로 부여할 필요 없이 마치 템플릿을 사용하듯 인라인으로 삽입할 수 있어 편리하게 사용할 수 있다. idx = 1 fruit = "Apple" print(f'{idx +1}: {fruit}') # 2: Apple 출처 : 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호)
타입 힌트 오류 확인 mypy를 사용하면 타입 힌트에 오류가 없는지 자동으로 확인 할 수 있으므로 이를 통해 수정 할 수 있다. 타입 힌트가 잘못 지정된 코드는 다음과 같이 InCompatible return value type 오류가 발생하므로 확인 후 직접 코드를 수정할 수 있다. $ mypy solution.py 출처 : 파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호)
카멜 케이스와 스네이크 케이스 카멜 케이스 단어를 대소문자로 구분하여 섞어서 작명하는 방식으로, 자바의 대표적인 표기 방식이기도 하다. 스네이크 케이스 각 단어를 언더스코어로 구분한다. 일반적으로 모두 소문자로 표기하지만 경우에 따라 시작 문자는 대문자로 표기하기도 한다. 연구 결과에 따르면 스네이크 케이스가 카멜 케이스보다 훨씬 더 인지하기 쉽다고 한다. 파이썬은 PEP8을 통해 스네이크 케이스 방식의 네이밍 컨벤션을 권장한다. camelCase: int = 1 snake_case: int = 1 네이밍 컨벤션 파이썬의 변수명 네이밍 컨벤션은 자바와 달리 각 단어를 밑줄(_)로 구분하여 표기하는 스네이크 케이스를 따른다. 이는 함수명도 마찬가지다. 특히 파이썬은 파이썬다운 방식에 굉장한 자부심이 있어서..
구조체 파이썬에는 구조체가 없을 뿐더러 클래스 또한 데이터 타입을 지정할 수 없어, 구조체와 같은 형태를 정의하려면 네임드 튜플을 사용해야 했다. from collections import namedtuple MyStruct = namedtuple("MyStruct", "field1 field2 field3") m = MyStruct("foo", "bar", "baz") 위처럼 정의해 사용하는 방법밖에 없었는데, 파이썬 3.7부터 dataclass를 지원하며, @dataclass 데코레이션으로 타입 힌트와 함께 활용함으로써 다음과 같이 class를 이용해 구조체 형태로 정의할 수 있다. from dataclasses import dataclass @dataclass class Product: weight..
제네릭 프로그래밍 제네릭이란 파라미터의 타입이 나중에 지어되게 해서 재활용성을 높일 수 있는 프로그래밍 스타일이다. 파이썬은 동적 타이핑 언어이기 때문에 제네릭이 필요 없다. 하지만 동적 타이핑의 장점이자 단점은 얼핏 사용하기엔 매우 편하지만 코드의 복잡도가 높아질수록 혼란을 가중시킨다는 점이다. 타입을 아예 명시하지 않으면 가독성을 낮추고 버그 발생 확률이 높아진다. 따라서 다음과 같이 타입을 명시할 수 있다. from typing import TypeVar T = TypeVar('T') U = TypeVar('U') def are_equal(a: T, b: U) -> bool: return a == b are_equal(10, 10.0) 파이썬은 동적 타이핑 언어지만 이처럼 타입을 명시하게 되면 가독..