수학 연산

  • 숫자 데이터에 ** 연산자를 사용할 경우 지수 승을 구할 수 있다. x ** y == x^y

  • 숫자 데이터에 // 연산자를 사용할 경우 floor division 연산을 수행할 수 있는데, 이 연산은 나눗셈 후 소수점 밑으로 버리고 정수부분만 남기는 것이다.

>>> 2**4
16
>>> 1.2 // 0.2
5.0
>>> 1.2 / 0.2 # 실제 소수점 연산은 결과가 정수 연산과 다를 수 있으므로 유의해야 한다.
5.999999999999999

 

Comprehension

  • 짧은 문법만으로 반복 가능한 객체를 생성하게 해주는 기능으로, 시퀀스 형(List, Dictionary, Set)에 대해서만 사용가능하다.

>>> [x**2 for x in range(10)]		# List
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> {x:x+4 for x in range(1,10,2)}	# Dictionary
{1: 5, 3: 7, 5: 9, 7: 11, 9: 13}
>>> {x for x in range(10)}		# Set
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  • 또한, 중첩 반복문과 조건문까지 사용가능하다.

>>> [x**2 for x in range(10) if x**2 & 1 == 0]
[0, 4, 16, 36, 64]
>>> [x*y for x in range(4) for y in range(4)]
[0, 0, 0, 0, 0, 1, 2, 3, 0, 2, 4, 6, 0, 3, 6, 9]
  • 괄호를 이용하면 제너레이터(Generator) 객체를 생성할 수 있는데, 제너레이터란 시퀀스 값을 만들어내는 객체로 메모리 공간을 절약하게 해주는 매우 유용한 기능이다.

    • 메모리 절약의 의미는 시퀀스 형의 모든 원소를 만들어서 메모리에 올리는게 아니라, 각 원소를 한 번씩 순회하기 때문에 메모리에 모든 원소가 올라갈 필요가 없다는 뜻이다.

    • next() 함수를 써서 다음 값을 계속 꺼내올 수 있는데 끝에 도달하면 StopIteration 예외를 던진다.

    • 제너레이터 객체는 함수 형태로 yield 라는 키워드를 return 대신 사용하는 방식으로 많이 작성되며, 더 자세한 정보는 여기(파이썬 코딩 도장)를 참고하면 좋다.

>>> y = (x**2 for x in range(4))
>>> y
<generator object <genexpr> at 0x10c26d580>
>>> next(y)
0
>>> next(y)
1
>>> next(y)
4
>>> next(y)
9
>>> next(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> def gen():
...    for x in range(4):
...        yield x**2
...
>>> y = gen()
>>> y
<generator object gen at 0x10c18f660>
>>> next(y)
0
>>> next(y)
1
>>> next(y)
4
>>> next(y)
9
>>> next(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> z = gen()
>>> list(z)	# == [i for i in gen()]
[0, 1, 4, 9]
>>> for i in gen():
...     print(i, end=' ')
...
0 1 4 9

 

Pack vs Unpack

  • * 연산자를 이용해서 시퀀스형 데이터들을 쉽고 간편하게 묶거나(packing) 풀거나(unpacking) 할 수 있다.

  • 주로 함수의 매개변수에 사용되는 경우가 있다. 매개변수에 *args**kwargs 를 사용할 경우 인자를 보다 유연하게 선별할 수 있다.

    • args 는 리스트로 받은 것을 함수에서 튜플로 관리한다. args[0] 은 첫번째 인자이다.

    • kwargs 는 딕셔너리로 받아서 함수에서 키워드 기반으로 인자를 관리한다. kwargs[키워드] 는 해당 인자를 값으로 갖는다.

>>> def fn(word, count):
...     print(word * count)
...

>>> args = ['monkey', 4]
>>> fn(*args)
monkeymonkeymonkeymonkey

>>> kwargs = {'count': 3, 'word': 'best'}
>>> fn(**kwargs)
bestbestbest

>>> a, *b, c = [i for i in range(1,7)]
>>> print(a, b, c)
1 [2, 3, 4, 5] 6
>>> v = [1,2,3,4]
>>> print(*v)
1 2 3 4
>>> x = '123'
>>> print(*x)
1 2 3
>>> a, *b = x
>>> a
'1'
>>> b
['2', '3']

 

자주 쓰이는 내장형 함수

  • 내장형 함수(Built-in Functions)는 별도의 import 없이 인터프리터에서도 사용가능한 함수들이다.

  • int(), float(), str() 등의 타입 변환 함수도 자주 쓰지만, 아래의 함수들도 타입 변환 함수만큼이나 매우 유용하다.

  • map(function, iterable, ...): 첫번째 인자로 함수를 받고 두번째 인자로 iterable 객체(값을 차례대로 꺼낼 수 있는 객체)를 받는다. 단, 넘기는 함수의 인자는 객체의 각 원소를 받을 수 있는 형태여야 하며, 원소의 함수 실행결과를 iterator 객체로 반환한다.

>>> x = map(int, ['1','2','3'])
>>> x
<map object at 0x10c1907c0>
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

>>> x = map(int, ['1','2','3'])
>>> list(x)
[1, 2, 3]
>>> a, b, c = map(int, ['1','2','3'])
>>> print(a, b, c)
1 2 3
  • filter(function, iterable): 첫번째 인자로 함수를 받고 두번째 인자로 iterable 객체(값을 차례대로 꺼낼 수 있는 객체)를 받는다. 각 원소를 함수의 인자로 넘겼을 때 나온 결과가 참(True)인 것들만 걸러내서 iterator 객체로 반환한다.

>>> x = filter(lambda x: x % 2 == 0, [1,2,3,4,5])
>>> x
<filter object at 0x10c26bd60>
>>> next(x)
2
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> x = {'absdf': 23, 'jiower': 4342, 'dog': 994, 'cat': 9212, 'duck': 1}
>>> sorted(x) # 키를 기준으로 오름차순 정렬
['absdf', 'cat', 'dog', 'duck', 'jiower']
>>> sorted(x, key=lambda k: x[k]) # 값을 기준으로 오름차순 정렬
['duck', 'absdf', 'dog', 'jiower', 'cat']
>>> sorted(x, key=lambda k: x[k], reverse=True) # 값을 기준으로 내림차순 정렬
['cat', 'jiower', 'dog', 'absdf', 'duck']

>>> x = [('absdf', 23), ('jiower', 4342), ('dog', 994), ('cat', 9212), ('duck', 1)]
>>> sorted(x, key=(lambda x: x[1]), reverse=True) # 원소의 두번째 값을 기준으로 내림차순 정렬
[('cat', 9212), ('jiower', 4342), ('dog', 994), ('absdf', 23), ('duck', 1)]
  • zip(*iterables): 여러 개의 iterable 객체를 받으면, 인덱스 단위로 묶어서(aggregates) 제너레이터 객체로 반환한다.

    • 여러 개의 iterable 중 가장 짧은 길이의 것에 맞춰져서 나오기 때문에 길이가 맞지 않으면 중간에 데이터가 짤릴 수 있다.

    • 반복문에서 둘 이상의 시퀀스 형의 원소를 나란히 처리할 때 자주 쓰인다.

>>> x = zip([2*i+1 for i in range(5)], [i**2 for i in range(8)])
>>> x
<zip object at 0x10c2bde80>
>>> list(x)
[(1, 0), (3, 1), (5, 4), (7, 9), (9, 16)]
>>> x = zip([2*i+1 for i in range(5)], [i**2 for i in range(8)], [1,2,3,4])
>>> list(x)
[(1, 0, 1), (3, 1, 2), (5, 4, 3), (7, 9, 4)]
  • enumerate(iterable, start=0): iterable 객체를 start 번째 부터 순환하는데 인덱스도 함께 반환한다. 반복문 내에서 원소의 인덱스가 필요할 때 유용하게 쓰인다.

>>> for idx, el in enumerate(['a','b','c']):
...     print('idx =', idx, ', element =', el)
...
idx = 0 , element = a
idx = 1 , element = b
idx = 2 , element = c
  • range(start, stop[, step]): stop 만 인자로 받기도 하지만, 그 함수는 이미 유명하므로 생략. 세번째 인자로 step 값을 주면 step 단위로 start와 stop 사이의 값을 리스트 형태로 갖는다. 반환형은 range 클래스이기 때문에 반복문 밖에서 쓸 때는 list(range(10)) 이런식으로 한 번 형변환을 해줄 필요가 있다.

  • next(iterator[, default]): iterator 객체의 다음 원소를 반환하는 함수로, 내부적으로 iterator 객체의 __next__() 를 호출한다. iterable 객체(시퀀스형 데이터들, list, str 등)의 경우 iter() 함수를 사용해서 iterator 객체로 바꿀 수 있다.

>>> x = 'best'
>>> y = iter(x)
>>> next(y)
'b'
>>> next(y)
'e'
>>> next(y)
's'
>>> next(y)
't'
>>> next(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
  • input([prompt]): 표준 입력받을 때 사용되는 함수로, 알고리즘 문제 풀 때 다음과 같이 많이 이용된다.

>>> a, b, c = map(int, input().rstrip().split()) # 1줄에 개별 원소 입력 받기
3 6 9
>>> print(a, b, c)
3 6 9
>>> x = [int(input()) for _ in range(3)] # 여러 줄로 개별 원소 입력 받기
99
102
33
>>> x
[99, 102, 33]

 

+ Recent posts