[BoostCamp AI Tech / Day 2] Pythonic code

newbie·2021년 8월 3일
0

Index

  • Pythonic Code
  • Pythonic Code 장점
  • pythonic Code contents
    • Split & join
    • list comprehension
    • enumerate & zip
    • lambda & map & reduce
    • iterable object(generator)
    • asterisk

Pythonic Code

  • 파이썬 스타일의 코딩 기법
  • 파이썬 특유의 문법을 활용하여 효율적으로 코드 표현
  • 그러나 많은 언어들이 서로의 장점을 채용하여, 더이상 파이썬 특유는 아님
  • 고급 코드를 작성할수록 더 많이 필요

Pythonic Code 장점

  • 다른 사람의 코드에 대한 이해도
    • 많은 개발자들이 python 스타일로 코딩을 함
  • 효율
    • 단순 for loop append보다는 list가 더 빠르며
    • 익숙해질수록 코드도 간결해짐

pythonic Code contents

  • Split & join
  • list comprehension
  • enumerate & zip
  • lambda & map & reduce
  • generator
  • asterisk

split & join

  • split : string type의 값을 "기준값"으로 나눠서 List 형태로 변환
  • join : list 값을 "기준값"과 합쳐서 string type으로 변환
  • split과 join은 반대 역할
#### split ####
items = "one two three".split() #기준값이 없으면 스페이스바(" ") 기준
print(items)
>> ['one','two','three']

a,b,c = ""one two three".split() #언패킹

items = "one,two,three".split(",") #"," 기준
print(items)
>> ['one','two','three']

#### join #####
tmp = "-".join(items)
print(tmp)
>> 'one-two-three

list comprehension

  • 기존 list를 사용하여 다른 list를 만드는 기법
  • 포괄적인 list, 포함되는 리스트 등의 의미로 사용
  • 일반적인 for + append보다 속도가 빠름
#일반적인 for loop
result = []
for i in range(5):
    result.append(5)
result
>> [0,1,2,3,4]


# list comprehension
result = [i for i in range(5)]
result
>> [0,1,2,3,4]

## if 구문이 추가
result = [i for i in range(5) if i % 2 == 0]
result
>> [0,2,4]


## if else 구문 추가
result = [i  if i % 2 == 0 else "kkk" for i in range(5)]
result
>> [0,'kkk',2,'kkk',4]

## 이중 for문
result [(i,j) for i in range(3) for j in range(3)]
result
[(0,0),0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]
# for i in range(3)
#    for j in range(3)

enumerate & zip

  • enumerate : list의 element를 추출할 때 번호를 붙여서 추출
  • zip : 두 개의 list 값을 병렬적으로 추출
# enumerate
t = ['a','b','c']
tmp = []
for i,v in enumerate(tmp):
   tmp.append((i,v))
print(tmp)
>> [(0,'a'),(1,'b'),(2,'c')]

## 상기 코드를 list로도 구현할 수 있음
t = ['a','b','c']
tmp = list(enumerate(t))
print(tmp)
>> [(0,'a'),(1,'b'),(2,'c')]

# zip
a = ['x1','x2','x3']
b = ['y1','y2','y3']
tmp = []
for a,b in zip(a,b):
   tmp.append((a,b))
print(tmp)
>> [('x1','y1'),('x2','y2'),('x3','y3')]

# 상기 코드 list로 구현
tmp = list(zip(a,b))
print(tmp)
>> [('x1','y1'),('x2','y2'),('x3','y3')]

lambda & map & reduce

  • lambda

    • 함수 이름 없이, 함수처럼 쓸 수 있는 익명 함수
    • 단 python3부터 lambda 함수를 권장하지 않지만(PEP8) 여전히 많이 쓰임(lambda 대신 def 사용)
    def f(x): # general function
        return x + 5
    f = lambda x : x + 5  # lambda function
    • lambda 문제점
      • 어려운 문법
      • 테스트 어려움
      • 문서화(docstring) 지원 X
      • 코드 해석 어려움
      • 이름이 존재 하지 않는 함수 출현
  • map

    • 두 개 이상의 list에도 적용 가능, lf fiter도 사용 가능
    • python3 이후 iteration을 생성하므로, list를 붙여줘야 list로 사용 가능
    • 실행 시점에 값을 생성하여 메모리에 효율적
    • 단, map함수도 lambda 함수와 마찬가지의 이유로 권장 안함
      • 대신 list comprehension으로 사용하길 권장
    tmp = [1,2,3,4,5]
    f = lambda x : x + y
    tmp2 = list(map(f,tmp,tmp))
    tmp2
    >> [2,4,6,8,10]
    
    tmp2 = list(map(lambda x : x**2 if x%2 == 0 else x, tmp)
    >> [1,4,3,16,5]
    
  • reduce

    • map function과 달리 list에 똑같은 함수를 적용해서 통합
    • 대용량의 데이터를 다룰 때 많이 사용
    • reduce 역시도 사용을 권장하지는 않음
    from functools import reduce
    reduce(lambda x,y : x+y,[1,2,3,4,5])
    >> 15
    # 

    iterable object

    • sequence형 자료형에서 데이터를 순서대로 추출하는 object
      • for문
    • 내부적으로 iternext가 구현되어 있음
    • iter()와 next() 함수로 iterable 객체를 iterator object로 사용 가능
    • iterator 객체로 만들 경우, 객체는 모든 값에 대한 주소를 가지고 있지 않고, 현재 값과 다음 값의 메모리 주소 위치만을 갖고 있음
    tmp = [1,2,3]
    tmp_iter = iter(tmp)
    next(tmp_iter) => 1
    next(tmp_iter) => 2
    next(tmp_iter) => 3
    • generator
      • iterable object를 특수한 형태로 사용해주는 함수
      • element가 사용되는 시점에 값을 메모리에 반환
        : yield를 사용해 한번에 하나의 element만 반환
      • 하기와 같은 코드가 있을 때
        • generator_list는 실제 값을 반환하는게 아니라
        • 아래 for문에서 해당 값이 쓰일 때 메모리 주소로부터 값을 반환
      • 결과적으로 대용량의 데이터를 다룰 때 리소스를 최대한 아낄 수 있음
      def generator_list():
          for i in range(10):
              yield i
      for i in generator_list():
          print(i)
      • generator comprehension
        • list comprehension과 유사한 형태로 generator 형태의 list 생성
        • generator expression이라고도 부름
        • [] 대신 () 사용

          gen_ex = (n for n in range(50))
          type(gen_ex) => <class ' generator'>

      • why generator
        • 읽기 쉬운 장점, 중간 과정에서 loop 중단될 경우 고려
        • 데이터가 커도 처리에 어려움이 없음

asterisk

  • 곱셈(*), 제곱연산(**), 가변 인자, 언패킹

  • 가변인자(variable-length argument)

    • 개수가 정해지지 않은 변수를 함수의 parameter로 사용하는 법
    • keyword arguments와 함께 arguemnt 추가 가능
    • asterisk(*) 기호를 사용하여 함수의 parameter 표시
    • 입력된 값은 tuple 형태로 저장됨
    • 가변인자는 오직 한 개만 맨 마지막 parameter 위치에 사용 가능
    • 가변인자는 일반적으로 *arg를 변수명으로 사용
    • 가변인자로 받은 값을 언패킹도 가능
    • 단, 기존 agument에 keyword 형태로 값을 입력할 경우 가변인자 사용 불가
    def asterisk_test(a,b,*args):
        return a + b + sum(args)
    asterisk_test(1,2,3,4,5) => 15
    #a = 1, b = 2, *args에는 3,4,5가 입력됨
  • 키워드 가변인자 (keyword variable-length argument)

  • parameter 이름을따로 지정하지 않고 입력하는 방법

  • asterisk(*) 두 개를 사용

  • 입력된 값은 dict type으로 저장

  • 가변인자는 오직 한 개만 기존 가변 인자 다음에 사용

    def tmp(a,b,**kwargs):
        print(a,b,kwargs)
    tmp(1,2, first = 10) => 1 2 {'first' : 10}
  • unpacking a container

    • tuple, dict 등 자료형에 들어가 있는 값을 unpacking
    • 함수의 입력값, zip 등에 유용하게 사용
    li = [1,2,3,4,5]
    print(li, *li) => [1,2,3,4,5] 1 2 3 4 5
    
    list(zip(*[[1,2,3],[2,4,6]]) => [[1,2],[2,4],[3,6]]
profile
DL, NLP Engineer to be....

0개의 댓글