파이썬 스타일 코드
파이썬 스타일의 코딩 기법
파이썬 특유의 문법을 활용하여 효율적으로 코드를 표현할 수 있다. 그러나, 현재는 많은 언어에서 서로의 장점을 채용하여 유사한 부분이 많음. 고급 코드를 작성할 수록 더 많이 필요해짐.
split & join
split함수
string type의 값을 ‘기준값’으로 나눠서 list 형태로 변환
items = "zero one two three".split() # [zero, one, two, three]
example = 'python,java,javascript' example.split(",")
# [python, java, javascript]
a, b, c = example.split(",") # a, b, c 변수에 example의 단어를 언패킹
subdomain, domain, tld = "teamlab.technology.io".split(".") # "."을 기준으로 언패킹
join함수
string으로 구성된 list르 합쳐 하나의 string으로 반환
a = ["a","b","c"] "".join(a) # "abc" 반환
", ".join(a) # "a, b, c" 반환
"-".join(a) # "a-b-c" 반환
list comprehension
기존 list를 사용하여 간단히 다른 list를 만드는 기법
일반적으로 for + append보다 속도가 빠름
비교) 1️⃣ 일반적인 for + append, 2️⃣ list compregension
#1 일반
result = []
for i in range(10):
result.append[i] # [0,1,2,3,4,5,6,7,8,9]
#2 list comprehension
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]
# 조건문을 삽입하여 작성할 수도 있음.
추가 예시1)
word_1 = "Hello"
word_2 = "World"
result = [i+j for i in word_1 for j in word_2]
# Nested For loop
#['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']
첫 번째 for에서 word_1의 0번째 인덱스인 ‘H’를 i에 입력, 2번째 for에서 word_2의 각 알파벳을 j에 입력하여 i+j를 실행하고 word_1의 1번째 인덱스인 ‘e’를 가져와서 … 반복하여 주석과 같은 결과를 도출한다.
추가 예시2)
case_1 = ["A", "B", "C"]
case_2 = ["D", "E", "A"]
a = [i+j for i in case_1 for j in case_2]
# ["AD", "AE", "AA", "BD", "BE", "BA", "CD", "CE", "CA"]
a = [i+j for i in case_1 for j in case_2 if not(i==j)] # if를 활용하여 필터링을 할 수 있다.
# ["AD", "AE", "BD", "BE", "BA", "CD", "CE", "CA"]
추가 예시3) 기존 list를 활용하여 새로운 list를 만들기
words = "It's only when the tide goes out that you discover who's been swimming naked".split()
# ["It's", 'only', 'when', 'the', 'tide', 'goes', 'out', 'that', 'you', 'discover', "who's", 'been', 'swimming', 'naked']
stuff = [[w.upper(), w.lower(), len(w)] for w in words]
# [["IT'S", "it's", 4], ['ONLY', 'only', 4], ['WHEN', 'when', 4], \\
# ['THE', 'the', 3], ['TIDE', 'tide', 4], ['GOES', 'goes', 4], \\
# ['OUT', 'out', 3], ['THAT', 'that', 4], ['YOU', 'you', 3], \\
# ['DISCOVER', 'discover', 8], ["WHO'S", "who's", 5], ['BEEN', 'been', 4], \\
# ['SWIMMING', 'swimming', 8], ['NAKED', 'naked', 5]]
워렌버핏의 명언 - 물이 빠졌을 때, 누가 발가벗고 수영하고 있었는지 알 수 있다.
위의 글을 공백을 기준으로 나눠 list로 만들고(split) [대문자, 소문자, 길이]를 한 list로 하는 새로운 list를 출력하는 코드이다.
간단한 문장으로 기존 list에서 새로운 list를 만들어 낼 수 있다.
Two dimensional vs One dimensional
추가 예시4) 추가 예시2를 활용하여 2차원 list 작성해보자.
case_1 = ["A", "B", "C"]
case_2 = ["D", "E", "A"]
# j가 포함된 for가 먼저 실행되고 i가 포함된 for 실행
a = [[i+j for i in case_1] for j in case_2]
# [['AD', 'BD', 'CD'], ['AE', 'BE', 'CE'], ['AA', 'BA', 'CA']]
첫번째 list에서 ‘D’가 반복되는 것을 보고 j가 포함된 for가 먼저 실행된 것을 확인할 수 있다.
enumerate & zip
enumerate
list의 element를 추출할 때 번호를 붙여서 추출할 때 번호를 붙여서 추출
list의 값을 dict나 순번을 이용하여 특정 값을 추출하거나, 정렬하는 등 편리하게 사용할 수 있다.
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
{for i,j in enumerate(seasons)} # 언패킹을 이용하여 dict 타입으로 저장 할 수 있음.
# {0:'Spring', 1: 'Summer', 2: 'Fall', 3:'Winter'}
zip
두 개의 list의 값을 병렬적으로 추출함.
for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
print(item)
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')
[sum(x) for x in zip((1,2,3), (10,20,30), (100,200,300))]
# [111,222,333]
enumerate & zip 병용 사례
alist = ["a1", "a2", "a3"]
blist = ["b1", "b2", "b3"]
for i , (a, b) in enumerate(zip(alist, blist)):
print(i, a, b)
# 0 a1 b1
# 1 a2 b2
# 2 a3 b3
lambda & map & reduce
lanbda
함수 이름 없이 함수처럼 쓸수 있는 익명 함수 / python3부터는 권장하지 않으나 여전히 많이 사용됨.
# 일반적인 함수
def f(x,y):
return x+y
# lambda 함수
f = lambda x,y: x+y
lambda 함수를 권장하지 않는 이유
어려운 문법, 이름이 존재하지 않는 함수의 출현, 코드 해석의 어려움, 테스트의 어려움, 문서화 Docstring 지원 미비
map
function에 argument를 자동으로 입력하여 iterator를 생성 → 즉! function과 적합한 list만 있다면 자동으로 쫙!
두 개 이상의 list에도 적용 가능함, if filter도 사용 가능
python3는 iteration을 생성 → list를 붙여줘야 list 사용가능
ex = [1,2,3,4,5]
print(list(map(lambda x: x+x, ex))) # [2, 4, 6, 8, 10]
print((map(lambda x: x+x, ex))) # <map object at 0x7fbb5b019f70> ; list 해줘야한다.
f = lambda x: x ** 2
print(map(f, ex)) # <map object at 0x7fbb5b019fd0> # list 필요!
for i in map(f, ex): # list에 넣지는 않았으나 기본적으로 iterator이므로 for에 사용 가능
print(i) # 1 4 9 16 25
reduce
map과 달리 list에 똑같은 함수를 적용해서 통합 - 굉장히 직관적이지 못함;
from functools import reduce
print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # 결과는 15, 1+2=3+3=6+4=10+5=15
위 3개의 함수는 간단한 코드로 다양한 기능을 제공하나 직관성이 떨어져서 python3에서는 권장하지 않음.
하지만, Legacy library나 다양한 코드에서 여전히 사용중이다.
generator
iterable object
sequence형 자료형에서 데이터를 순서대로 추출하는 object - list, tuple, 문자열 등
내부적 구현으로 ‘iter’와 ‘next’가 사용된다.
cities = ['seoul', 'busan', 'incheon']
iter_cities = iter(cities)
print(iter_cities) # <list_iterator object at 0x7fc5a21538e0>
print(next(iter_cities)) # seoul
print(next(iter_cities)) # busan
print(next(iter_cities)) # incheon
next(iter_cities) # Error 발생, stopiteration
generator
iterable object를 특수한 형태로 사용해주는 함수
element가 사용되는 시점에 값을 메모리에 반환
yield를 사용해 한번에 하나의 element만 반환함. 단, yield는 함수 내에 있어야한다.(doc의 설명)
list comprehesion과 유사한 형태로 generator 생성. generator expression이라고도 부름
[ ]대신 ( )을 사용한다.
generator_ex = (n*n for n in range(500))
print(generator_ex) # <generator object <genexpr> at 0x7f975de337b0>
for i in generator_ex: # 0~499의 제곱 출력
print(i)
일반적인 iterator는 generator에 비해 훨씬 큰 메모리 용량을 사용한다.
list타입의 데이터를 반환해주는 함수는 generator로 만들자. 읽기가 쉽고, 중간 과정에서 loop이 중단될 수 있을 때 사용하자.
큰 데이터를 사용할 때는 상대적으로 메모리를 덜 차지하는 generator를 사용해보자
파일 데이터를 처리할 때도 generator를 사용해보자
함수의 arguments
- keywords arguments
- default arguments
- variable-lenth arguments
keywords arguments
함수에 입력되는 parameter의 변수명을 사용하여 argument를 넘김
ex) 아래 간단한 함수에서 사용된 ‘name’
def hint(name):
return print("힌트 :", name)
default arguments
parameter의 기본값을 사용한다. 입력하지 않을 경우 기본값을 출력
ex) 아래 함수에서 name의 기본값이 ‘바보’로 되어있다.
def hint(name = "바보"):
return print("이름은 "+name+"입니다.")
variable-lenth arguments
아래 asterisk와 같이 공부해보자.
asterisk
Asterisk는 ‘ * ’기호를 뜻한다.
함수에서 가변인자(variable-lenth) 즉 개수가 정해지지 않은 변수를 함수에 사용하는 방법이다.
keyword arguments와 함께 추가가 가능하다.
입력된 값은 tuple type으로 사용할 수 있다. 가변인가는 오직 한 개만 맨 마지막 parameter 위치에 사용한다.
일반적으로 가변인자(variable-lenth)는 ‘*args’ 로 표현한다.
def hap(a, b, *args):
return a+b+sum(args)
hap(1,2,3,4,5,6)
# 21, 1은 a에, 2는 b에 입력되고 나머지는 *args에 tuple로 저장된다.(몇개가 됐든)
키워드 가변인자(keyword variable-lenth)
parameter를 따로 지정하지 않고 입력하는 방법
*을 2개 사용하여 함수의 parameter를 표시한다.
입력된 값은 dict로 사용할 수 있다.
가변인자는 오직 한개만 기존 가변인자 다음에 사용한다.
ex) 키워드 가변인자 예제
def hint(one, two, *args, **kwargs):
print(one+two+sum(args))
print(kwargs)
hint(1,2,3,3,4,first=1, second=2, third=3)
# 13, {'first': 1, 'second': 2, 'third': 3}
*는 그 외에도 우리가 흔히 알고있는 곱하기, 제곱 등에도 사용되고 있다.
그리고, *는 unpacking에도 사용할 수 있다. 함수 입력값, zip 등에 유용하게 사용가능
'개발자 공부' 카테고리의 다른 글
모듈과 패키지 (0) | 2023.05.18 |
---|---|
Python Object Oriented Programming (1) | 2023.05.17 |
data 구조 및 종류 (2) | 2023.05.16 |
Function 2 (0) | 2023.05.11 |
String(문자열) (0) | 2023.05.10 |