Pythonic Code 익히기

무조건 지켜야하는 rule은 아니지만,
잘 익히면 다른 사람의 코드를 쉽게 읽을수 있고,
다양한 프레임워크, 라이브러리를 사용할 때 쉽게 이해할 수 있다.
(시간적 효율도 좋아짐)

1. split & join

1.1 split 함수

string type의 값을 특정 구분자로 나누어 list 형태로 반환하는 함수.

# 공백을 기준으로
>>> greeting = "Hello my name is Lee"
>>> sp_greeting = greeting.split()
>>> print(sp_greeting)
['Hello', 'my', 'name', 'is', 'Lee']

# ","을 기준으로
>>> fruits = "apple,banana,tomato"
>>> sp_fruits = fruits.split(",")
>>> print(sp_fruits)
['apple', 'banana', 'tomato']

# unpacking
>>> fruit1, fruit2, fruit3 = sp_fruits
>>> print(fruit1)
apple
>>> print(fruit2)
banana
>>> print(fruit3)
tomato

1.2 join 함수

split과 반대로 list를 구분자로 연결해 하나의 문자열로 합쳐서 반환하는 함수.

>>> fruits = ['apple', 'banana', 'tomato']
>>> all_fruits = " & ".join(fruits)
>>> print(all_fruits)
apple & banana & tomato

(for문 돌면서 +로 연결해주는 방법보다 빠르다.)

2. list comprehension

기존의 list를 사용하여 다른 list를 만드는 기법.
일반적으로 for + append 보다 속도가 빠르다.

2.1 기본

# for + append
>>> list_a = []
>>> for i in range(10):
        list_a.append(i)
>>> print(list_a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# list comprehension
>>> list_b = [i for i in range(10)]
>>> print(list_b)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# list comprehension
>>> list_b = [i for i in range(10) if i % 2 != 0]
>>> print(list_b)
[1, 3, 5, 7, 9]

2.2 Nested for loop

>>> word1 = "Hello"
>>> word2 = "World"

# for + append
>>> result1 = []
>>> for i in word1:
        for j in word2:
             result1.append(i + j) 
>>> print(result1)
['HW', 'Ho', 'Hr', 'Hl', 'Hd', 'eW', 'eo', 'er', 'el', 'ed', 'lW', 'lo', 'lr', 'll', 'ld', 'lW', 'lo', 'lr', 'll', 'ld', 'oW', 'oo', 'or', 'ol', 'od']

# list comprehension
>>> result2 = [i+j for i in word1 for j in word2]
>>> print(result2)
['HW', 'Ho', 'Hr', 'Hl', 'Hd', 'eW', 'eo', 'er', 'el', 'ed', 'lW', 'lo', 'lr', 'll', 'ld', 'lW', 'lo', 'lr', 'll', 'ld', 'oW', 'oo', 'or', 'ol', 'od']

2.3 Filter

>>> alpha_1 = ["A", "B", "C"]
>>> alpha_2 = ["B", "C", "D"]

# filter if
>>> result = [i + j for i in alpha_1 for j in alpha_2 if not(i == j)]
>>> print(result)
['AB', 'AC', 'AD', 'BC', 'BD', 'CB', 'CD']

# filter if,else
>>> result = [i + j if not(i == j) else "Same alpha!" for i in alpha_1 for j in alpha_2]
>>> print(result)
['AB', 'AC', 'AD', 'Same alpha!', 'BC', 'BD', 'CB', 'Same alpha!', 'CD'] 

2.4 Two dimensional list

>>> words = "The quick brown fox jumps over the lazy dog".split()
>>> print(words)
['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']
>>> stuff = [[w.upper(), w.lower(), len(w)] for w in words]
>>> for i in stuff:
       print(i)
['THE', 'the', 3]
['QUICK', 'quick', 5]
['BROWN', 'brown', 5]
['FOX', 'fox', 3]
['JUMPS', 'jumps', 5]
['OVER', 'over', 4]
['THE', 'the', 3]
['LAZY', 'lazy', 4]
['DOG', 'dog', 3]

3. enumerate & zip

3.1 enumerate

listelement를 추출할 때 번호를 붙여서 추출하는 방법.
즉, indexelement를 동시에 접근하면서 반복문을 돌릴 수 있다.

  • enumerate()indexelement로 이루어진 tuple을 돌려주기 때문에, 각각 다른 변수에 할당하고 싶으면 unpacking을 해야함.
>>> list_a = ['first', 'second', 'third']
>>> for i, e in enumerate(list_a):
        print(i, e) 
0 first
1 second
2 third

{index: element} 또는 {element: index} 로 이루어진 dict를 만들때 유용하다.

3.2 zip

두개의 list를 병렬적으로 추출하는 방법.
옷의 지퍼(zipper)를 올리듯, 두 list의 데이터를 엮어준다.
(tuple type으로 만들어줌.)

>>> list_a = ['a', 'b', 'c']
>>> list_b = ['A', 'B', 'C']

>>> for a, b in zip(list_a, list_b):
        print(a, b) 
a A
b B
c C

4. lambda & map & reduce

4.1 lambda

runtime에 생성해서 사용할 수 있는 이름없는 익명 함수.
return할 값을 한 줄 정도의 statement로 작성해준다.

  • python3 부터는 권장하지 않음(테스트가 어려움).
    하지만 여전히 많이 쓰인다고는 함.
# 일반적인 함수
>>> def my_sum(x, y):
        return (x + y)
>>> print(my_sum(40,  2))
42

# lambda 함수
>>> my_lam_sum = lambda x, y : x + y
>>> print(my_lam_sum(40, 2))
42
>>> (lambda x, y: x + y)(40, 2)
42

4.2 map

listelement들을 지정된 함수로 처리해준다.
두 개 이상의 list에도 적용 가능하고, if filter도 사용 가능하다.
(list comprehension형태로 표현하는게 더 보기좋다!)

>>> list_a = [1, 2, 3]

# 한 개의 리스트
>>> my_square = lambda x : x ** 2
>>> print(list(map(my_square, list_a)))
[1, 4, 9]

# 두 개 이상의 리스트
>>> my_sum = lambda x, y : x + y
>>> print(list(map(my_sum, list_a, list_a)))
[2, 4, 6]

4.3 reduce

list에 지정된 함수를 처리하여 통합(누적)한다.
주로 여러 데이터의 누적 집계를 내기 위해 사용.

  • python3 부터는 권장하지 않음.
>>> from functools import reduce

>>> list_a = [1, 2, 3, 4, 5]
>>> my_sum = lambda x, y : x + y
# x1 = 1, y1 = 2 -> x1 + y1 = 3 = x2
# x2 = 3, y2 = 3 -> x2 + y2 = 6 = x3
# x3 = 6, y3 = 4 -> x3 + y3 = 10 = x4
# x4 = 10, y4 = 5 -> x4 + y4 = 15
>>> print(reduce(my_sum, list_a))
15

5. generator (iterable object)

5.1 iterable object

suquence형 자료형에서 데이터를 순서대로 추출하는 object.
내부적으로, iternext가 사용된다.

>>> num = ['one', 'two', 'three', 'four', 'five']
>>> num_list_address = iter(num)
>>> print(num_list_address)
<list_iterator object at 0x10146aa90>
>>> print(next(num_list_address))
one
>>> print(next(num_list_address))
two
>>> print(next(num_list_address))
three
>>> print(next(num_list_address))
four
>>> print(next(num_list_address))
five

5.2 generator

iterable object를 특수한 형태로 사용해주는 함수.
yield 키워드를 사용해 element의 주소만 가지고 있다가 element가 실제 사용되는 시점에 값을 메모리에 올려준다.
(많은 데이터를 쓸때 메모리 절약을 할 수 있다. - 권장!)

# general list
>>> def general_list(num):
...     result = []
...     for i in range(num):
...             result.append(i)
...     return (result)
... 
>>> list_a = general_list(50)
>>> type(list_a)
<class 'list'>
>>> print(list_a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
>>> import sys
# sys.getsizeof(object) -> object의 크기를 Byte단위로 반환.
>>> sys.getsizeof(list_a)
520		# 520 Byte

# generator list
>>> def generator_list(num):
...     result = []
...     for i in range(num):
...             yield i
... 
>>> list_b = generator_list(50)
>>> type(list_b)
<class 'generator'>
>>> sys.getsizeof(list_b)
112		# 112 Byte

5.2.1 generator comprehension

위의 list comprehension과 유사하게 사용 가능.
양 끝이 '[ ]' 가 아닌 '( )' 로 닫혀있다.

>>> list_gen = (n for n in range(50))
>>> type(list_gen)
<class 'generator'>
>>> sys.getsizeof(list_gen)
112
>>> print(list(list_gen))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

6. asterisk - (*)

6.1 가변인자 : variable-length argument

  • 개수가 정해지지 않은 변수를 함수의 parameter로 사용.
  • asterisk를 사용하여 함수의 parameter를 표시.
  • 입력된 값은 함수 내에서tuple type으로 사용.
  • 오직 한 개만 함수의 맨 마지막 parameter 위치에 사용.
>>> def sum_all(a, b, *args):
...     print(list(args))
...     print(type(args))
...     return (a + b + sum(args))
... 
>>> result = sum_all(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
[3, 4, 5, 6, 7, 8, 9, 10]	# 함수 내에서 가변인자
<class 'tuple'>			# 함수 내에서 가변인자 type
>>> print(result)
55

6.2 키워드 가변인자 : Keyword variable-length argument

  • parameter 이름을 따로 지정하지 않고 입력.
  • asterisk를 두개 사용하여 함수의 parameter를 표시.
  • 입력된 값은 함수 내에서 dict type으로 사용.
  • 오직 한 개만 기존 가변인자 다음에 사용.(순서 지키지 않으면 에러 발생함)
# 키워드 가변인자만 사용
>>> def kword_test(**kwargs):
...     print(kwargs)
...     print(type(kwargs))
... 
>>> kword_test(one = 24, two = 42, three = 7)
{'one': 24, 'two': 42, 'three': 7}
<class 'dict'>

# 가변인자 뒤에 키워드 가변인자 사용
>>> def sum_all(a, b = 1, *args, **kwargs):
...     print(f"args: {args}")
...     print(f"kwargs: {kwargs}")
... 
>>> sum_all(1, 2, 3, 4, 5, 6, 7, eight=8, nine=9, ten=10)
args: (3, 4, 5, 6, 7)
kwargs: {'eight': 8, 'nine': 9, 'ten': 10}

6.3 unpacking container

container에 들어있는 값들을 unpacking하여 함수에 전달할 때 사용할 수 있다.
**를 이용하여 dict 자료형을 unpacking 할 수도 있다.

>>> def unpacking_test(a, *args):
...     print(a, args)
...     print(type(args))
... 
# unpacking_test(1, 2, 3, 4, 5) 와 동일함. *로 unpacking 되었기 때문.
>>> unpacking_test(1, *(2, 3, 4, 5))
# 가변인자는 tuple type으로 받음.
1 (2, 3, 4, 5)
<class 'tuple'>

>>> def unpacking_test2(a, args):
...     print(a, *args)
...     print(type(args))
... 
>>> unpacking_test2(1, (2, 3, 4, 5))
# tuple type을 받아서 unpacking 하여 출력.
1 2 3 4 5
<class 'tuple'>

이 글은 네이버 부스트코스 강의 중 최성철교수님의 강의를 바탕으로 학습하며 작성했습니다.


추가로 파이썬 코딩 컨벤션(PEP 8)에 대한 정보는 밑의 링크에 자세하게 나와있다.
https://codechacha.com/ko/pythonic-and-pep8/
https://www.python.org/dev/peps/pep-0008/
https://google.github.io/styleguide/pyguide.html

참고.
https://www.daleseo.com/python-zip/
https://wikidocs.net/16069
https://brownbears.tistory.com/342

profile
머신러닝을 공부하고 있습니다. 특히 비전 분야에 관심이 많습니다.

0개의 댓글