5 분 소요

Pythonic Code

Overview

  • 파이썬 스타일의 코딩 기법
  • 파이썬 특유의 문법을 활용하여 효율적으로 코드를 표현함
  • 고급 코드를 작성 할 수록 더 많이 필요해짐

Example code


colors = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
    result += s
print(result)
# 'redbluegreenyellow'

result = ''.()
print(result)
# 'redbluegreenyellow'
    

Contents

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

and

split

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


items = 'zero one two three'. # 스페이스를 기준으로 문자열 나누기
# ['zero', 'one', 'two', 'three']

example = "teamlab.technology.io"
subdomain, domain, tld = example.
    

join


colors = ["red", "blue", "green", "yellow"]
<input type="text" data-answer=""_".join" />(colors)
# 'red-blue-green-yellow'
    

기존 List를 사용하여 간단히 다른 List를 만드는 방법

일반적으로 for + append보다 속도가 빠름


# General Style
result = []
for i in range(10):
    result.append(i)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# List comprehension
result = [i for i in range(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
result = [] # Filter
# [0, 2, 4, 6, 8]
    

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']
result = [i+j for i in word_1 for j in word_2 if not(i==j)]
result = [i+j if not(i==j) else i for i in word_1 for j in word_2]
    

import pprint
words = 'The quick brown fox jumps over the lazy dog'.split()

stuff = [[w.(), w.(), (w)] for w in words]
pprint.pprint(stuff)
"""
[['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]]
 """
    

Two dimensional vs One dimensional


case_1 = ["A", "B", "C"]
case_2 = ["D", "E", "F"]

result = [[i+j for i in case_1] for j in case_2]
# [['AD', 'BD', 'CD'], ['AE', 'BE', 'CE'], ['AA', 'BA', 'CA']]
    

&

enumerate

enumerate : 와 함께 list의 를 추출


# dict 타입으로 만들 때 자주 사용
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
{v.lower() : i for i, v in }
"""
{'adipiscing': 6,
 'aliqua.': 18,
 'amet,': 4,
 'consectetur': 5,
 'do': 9,
 'dolor': 2,
 'dolore': 16,
 'eiusmod': 10,
 'elit,': 7,
 'et': 15,
 'incididunt': 12,
 'ipsum': 1,
 'labore': 14,
 'lorem': 0,
 'magna': 17,
 'sed': 8,
 'sit': 3,
 'tempor': 11,
 'ut': 13}
 """
    

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']]
    

& &

함수 이름 없이 쓸 수 있는 익명함수

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


# general function
def f(x, y):
    return x + y

# lambda function
f = 

(lambda x, y: x+y)(10, 50)
    

권장: def f(x): return 2*x

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

  • 어려운 문법
  • 테스트의 어려움
  • 문서화 docstring 지원 미비

주어진 함수를 시퀀스의 각 요소에 적용하여 새로운 시퀀스를 반환하는 함수

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

list comprehension을 사용하는 걸 권장하는 분위기


ex = [1, 2, 3, 4, 5]
f = lambda x,y: x+y
list(map(f, ex, ex))
[f(value, value) for value in ex]
    

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

대용량의 데이터를 다룰 때 사용


 import reduce
print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]))
# 15
    

object

Sequence형 자료형에서 데이터를 순서대로 추출하는 object

내부적으로 iternext가 사용됨

iter()와 next() 함수로 iterable 객체를 iterator object로 사용


cities = ["Seoul", "Busan", "Jeju"]

iter_obj = (cities)

print(next(iter_obj))
print(next(iter_obj))
print(next(iter_obj))
    

iterable object를 특수한 형태로 사용해주는 함수

element가 사용되는 시점에 값을 메모리에 반환

yield를 사용해 한번에 하나의 element만 반환함

장점

  • 메모리 효율성: 한 번에 하나의 요소만 메모리에 올리므로 큰 데이터를 처리할 때 유리합니다.
  • 느긋한 계산: 필요할 때마다 값을 생성하여 불필요한 계산을 피할 수 있습니다.
  • 성능 최적화: 함수의 상태를 유지하며 효율적인 반복 작업을 수행할 수 있습니다.
  • 코드의 간결함: 복잡한 이터레이션 로직을 간단하게 작성할 수 있습니다.

Why & When

  • 일반적인 iterator는 generator에 반해 훨씬 큰 메모리 용량 사용
  • list 타입의 데이터를 반환해주는 함수는 generator로 만들어라
  • 큰 데이터를 처리할 때는 generator expression을 고려하라
  • 파일 데이터를 처리할 때도 generator를 쓰자

def simple_generator():
    for i in range(1, 11):
         i

# 제너레이터 객체 생성
gen = simple_generator()

# 제너레이터에서 값을 하나씩 꺼내기
for value in gen:
    print(value)
    

generator comprehension

list comprehension과 유사한 형태로 generator형태의 list 생성

generator expression이라는 이름으로도 부름

[] 대신 를 사용하여 표현


gen_ex = (n*n for n in range(500))
    

function passing arguments

함수에 입력되는 arguments의 다양한 형태

  1. Keyword arguments
  2. Default arguments
  3. Variable-length asterisk

1. Keyword arguments

함수에 입력되는 parameter의 을 사용, arguments를 넘김


def print_something(my_name, your_name):
    print(f"{my_name} {your_name}")

print_something(your_name = "aa", my_name = "bb") # your_name, my_name과 같이 parameter의 변수명을 사용하는 것을 Keyword arguments
    

2. arguments

parameter의 을 사용, 입력하지 않을 경우 출력


def print_something(my_name, your_name = "aa"):
    print(f"{my_name} {your_name}")
    

3. Variable-length(가변 인자) asterisk

만약 함수의 parameter가 정해지지 않았다면?

가 정해지지 않은 변수를 함수의 parameter로 사용하는 법

Keyword argument와 함께, argument 사용 가능

Asterisk(*) 기호를 사용하여 함수의 parameter를 표시함

입력된 값은 tuple type으로 사용할 수 있음

가변 인자는 오직 한 개만 맨 마지막 parameter 위치에 사용가능


def asterisk_test(a, b, ):
    return a+b+sum() # tuple type으로 입력됨
print(asterisk_test(1, 2, 3, 4, 5))
    

4. Keyword variable-length

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

asterisk(**) 두 개를 사용하여 함수의 parameter를 표시함

입력된 값은 type으로 사용할 수 있음

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


def kwargs_test_1():
    print() # dict type으로 값을 입력
kwargs_test_1(first = 1, second = 2, third = 3)
# {'first' : 1, 'second' : 2, 'third' : 3}

def kwargs_test_2(one, two, , ):
    print(one + two + sum())
    print()
kwargs_test_2(3, 4, 5, 6, 7, 8, 9, first = 3, secon = 2, third = 5)
    

asterisk

  • 단순 곱셈
  • 제곱 연산
  • 가변 인자
  • tuple, dict 등 자료형에 들어가 있는 값을 ( a container)
  • 함수의 입력값, zip 등에 유용하게 사용가능

def asterisk_test(a, *args):
    print(a, *args)
    print(a, args)
    print(type(args))
test = (2, 3, 4, 5, 6)
asterisk_test(1, *test)
# 1 
# 1 
# <class 'tuple'>
asterisk_test(1, test)
# 1 
# 1  # *args는 튜플로 받기 때문에  형태의 튜플이 된다
# <class 'tuple'>
    

댓글남기기