Why Pythonic code?

남 코드에 대한 이해도 : 많은 개발자들이 python 스타일로 코딩한다.

효율 : 단순 for loop append 보다 list가 조금 더 빠르다. 익숙해지면 코드가 짧아진다.

 

Split

type의 값을 "기준값"으로 나눠서 List 형태로 변환

a = "   EXTRA   SPACE   "

b = a.split().lower()
c = a.split(' ')

print(b)    # ['EXTRA', 'SPACE']
print(c)    # ['', '', '', 'EXTRA', '', '', 'SPACE', '', '', '']

 

list comprehension

  • 기존 List 사용하여 간단히 다른 List를 만드는 기법
  • 다른 List를 포함해서 새로운 List를 만드는 것.
  • 파이썬에서 가장 많이 사용되는 기법 중 하나
  • 일반적으로 for + append 보다 속도가 빠름
result = []
for i in range(10):
	result.append(i)
	# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

result = [i for i in range(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
result = [i for i in range(10) if i % 2 == 0]
# [0, 2, 4, 6, 8]
result = [i if i % 2 == 0 else -1 for i in range(10)]
# [0, -1, 2, -1, 4, -1, 6, -1, 8, -1]

word_1 = "Hello"
word_2 = "World"
result = [i + j for i in word_1 for j in word_2]
# ['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']

case_1 = ["a","b","c"]
case_2 = ["d","e","a"]
result = [i+j for i in case_1 for j in case_2] # case_1부터
# ['ad', 'ae', 'aa', 'bd', 'be', 'ba', 'cd', 'ce', 'ca']
result = [[i+j for i in case_1] for j in case_2] # case_2부터
# [['ad', 'bd', 'cd'], ['ae', 'be', 'ce'], ['aa', 'ba', 'ca']]
result = []
for i in range(10):
	result.append(i)
	# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

result = [i for i in range(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
result = [i for i in range(10) if i % 2 == 0]
# [0, 2, 4, 6, 8]
result = [i if i % 2 == 0 else -1 for i in range(10)]
# [0, -1, 2, -1, 4, -1, 6, -1, 8, -1]

word_1 = "Hello"
word_2 = "World"
result = [i + j for i in word_1 for j in word_2]
# ['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']

case_1 = ["a","b","c"]
case_2 = ["d","e","a"]
result = [i+j for i in case_1 for j in case_2] # case_1부터
# ['ad', 'ae', 'aa', 'bd', 'be', 'ba', 'cd', 'ce', 'ca']
result = [[i+j for i in case_1] for j in case_2] # case_2부터
# [['ad', 'bd', 'cd'], ['ae', 'be', 'ce'], ['aa', 'ba', 'ca']]

여담으로 pprint.pprint를 쓰면 이쁘게 나온다!

 

enumerate & zip

enumerate : list의 element를 추출할 때 번호를 붙여서 추출

  • 나오는 형태는 Tuple
for i, v in enumerate('abc'):
	print("{0}  {1}".format(i,v))
	# 0  a
	# 1  b
	# 2  c

for i, v in enumerate(['a','b','c']):
	print("{0}  {1}".format(i,v))
	# 0  a
	# 1  b
	# 2  c

zip : 두 개의 list의 값을 병렬적으로 추출함

alist = ['a1','a2','a3']
blist = ['b1','b2','b3']

[[a,b] for a, b in zip(alist, blist)]
# [['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']]
[c for c in zip(alist, blist)]
# [c for c in zip(alist, blist)]

list(enumerate(zip(alist, blist)))
# [(0, ('a1', 'b1')), (1, ('a2', 'b2')), (2, ('a3', 'b3'))]

 

lambda & map & reduce

lambda

함수 이름 없이, 함수처럼 쓸 수 있는 익명함수

수학의 람다 대수에서 유래함

def f(x, y):
	return x + y

f = lambda x, y : x + y

PEP 8에서는 lambda의 사용을 권장하지 않음

  • 어려운 문법
  • 테스트의 어려움
  • 문서화 docstring 지원 미비
  • 코드 해석의 어려움
  • 이름이 존재하지 않는 함수의 출현
  • 그래도 쓰는..

Map

두 개 이상의 list에도 적용 가능함, if filter도 사용가능

굳이 map을 사용하기 보다는 list comprehension을 사용하도록

ex = [1,2,3,4,5]
f = lambda x: x ** 2

list(map(f, ex))
# [1, 4, 9, 16, 25]
[f(value) for value in ex]

 

reduce

map function과 달리 list에 똑같은 함수를 적용해서 통합

대용량 데이터를 핸들링할 때, 주로 사용.

from functools import reduce

ex = [1,2,3,4,5]
f = lambda x, y: x + y

print(reduce(f,ex))
# 15

 

generator

Iterable data

  • Sequence형 자료형에서 데이터를 순서대로 추출하는 object
  • 내용이 아닌 위치정보(주소값)에 대한 정보가 저장됨.
  • next를 하면 다음 메모리 주소에 있는 값을 불러옴.
  • cities_주소 → seoul_주소 → busan_주소 → jeju_주소 → 없으므로 에러
cities = ["seoul", "busan", "jeju"]

memory_address = iter(cities)
# <list_iterator at 0x1ec8cbc6788>
next(memory_address) # seoul
next(memory_address) # busan
next(memory_address) # jeju

generator

  • iterable object를 특수한 형태로 사용해주는 함수
  • element가 사용되는 시점에 값을 메모리에 반환
  • yield를 사용해 한번에 하나의 element만 반환함.
  • 용량을 줄일 수 있기 때문에 대용량인 경우 사용하는 것이 효율적임.
import sys

def general_list(value):
	result = []
	for i in range(value):
		result.append(i)
	return result

result = general_list(50)
sys.getsizeof(result)
# 528
import sys

def generator_list(value):
	result = []
	for i in range(value):
		yield i

result = generator_list(50)
sys.getsizeof(result)
# 120
sys.getsizeof(list(generator_list(50)
# 472

When generator

  • list 타입의 데이터를 반환해주는 함수는 generator로!

→ 특히 사용하면 읽기 쉽고, 중간 과정에서 loop가 중단될 수 있을때

  • 큰 데이터를 처리할 때는 generator expression을 고려

→ 데이터가 커도 처리의 어려움이 없음.

  • 파일 데이터를 처리할 때도 generator를 사용하자

 

asterisk

함수에 입력되는 parameter의 변수명을 사용하여 argument를 넘김.

# Keyword arguments
def print_name_keyword(name, you_name):
	print("Hello {}, my name is {}".format(you_name, name))

print_name_keyword(name="aaa",you_name="bbb")

# default arguments
def print_name_default(name, you_name="NAVER"):
	print("Hello {}, my name is {}".format(you_name, name))

print_name_default("hwan")
# Hello NAVER, my name is hwan
print_name_default("hwan", "AA")
# Hello AA, my name is hwan

가변인자(variable-length)

  • 개수가 정해지지 않은 변수를 함수의 parameter로 사용하는 법
  • Keyword arguments와 함계, argument 추가가 가능
  • Asterisk(*) 기호를 사용하여 함수의 parameter를 표시함
  • 입력된 값은 tuple type으로 사용할 수 있음
  • 가변인자는 오직 한 개만 맨 마지막 parameter 위치에 사용가능
def asterisk_test(a, b, *args):
	print(a)
	print(b)
	print(args)
	print(type(args))

asterisk_test(1,2,3,4,5)
# 1
# 2
# (3, 4, 5)
# <class 'tuple'>

키워드 가변인자(Keyword variable-length)

  • Parameter 이름을 따로 지정하지 않고 입력하는 방법
  • asterisk(*) 두개를 사용하여 함수의 parameter를 표시함
  • 입력된 값은 dict type으로 사용할 수 있음
  • 가변인자는 오직 한 개만 기존 가변인자 다음에 사용
def kwargs_test(**kwargs):
	print(kwargs)
	print(type(kwargs))

kwargs_test(first=3, second=4, third=5)
# {'first': 3, 'second': 4, 'third': 5}
# <class 'dict'>

결론으로는 argument는 그냥 파라미터, 키워드 파라미터, 가변인자, 키워드 가변인자 순으로 작성해야함.

def test_3(one, two=3, *args, **kwargs):
	print(one,two, args, kwargs)

test_3(1,2,3,4,5,6,6,a=100,b=200)
# 1 2 (3, 4, 5, 6, 6) {'a': 100, 'b': 200}

 

asterisk(*)

  • 흔히 알고 있는 *를 의미함.
  • tuple, dict 등 자료형에 들어가 있는 값을 unpacking
  • 함수의 입력값, zip 등에 유용하게 사용가능
def asterisk_test(a, *args):
	print(a, args)
	print(type(args))

def asterisk_test2(a, args):
	print(a, *args)
	print(type(args))

asterisk_test(1,*(2,3,4,5,6)) # (1,2,3,4,5,6)과 같음
# 1 (2, 3, 4, 5, 6)
# <class 'tuple'>
asterisk_test(1,(2,3,4,5,6))
# 1 2 3 4 5 6
# <class 'tuple'>

data = ([1,2,],[3,4,],[5,6,])
print(*data)
# [1, 2] [3, 4] [5, 6]
for i in zip(*data):
    print(i)
# (1, 3, 5)
# (2, 4, 6)

def asterisk_test(a,b,c,d):
    print(a,b,c,d)
    
data = {"b":1,"c":2,"d":3}
asterisk_test(10, **data)
# 10 1 2 3

+ Recent posts