foo = long_function_name(var_one, var_two,
var_three, var_fout)
위 코드에서처럼 첫 번째 줄에 파라미터가 있다면, 파라미터가 시작되는 부분에 보기 좋게 맞춘다.
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
위 코드에서처럼 첫 번째 줄에 파라미터가 없다면, 공백 4칸 인덴트를 한 번 더 추가하여 다른 행과 구분하게 된다.
var_one = 1
var_two = 2
var_three = 3
var_four = 4
foo = long_function_name(
var_one, var_two,
var_three, var_four
)
1
위 코드에서 처럼 여러 줄로 나눠쓸 경우 다음 행과 구분되도록 인덴트를 추가한다.
자바와 달리 각 단어를 밑줄(_)로 구분하여 표기하는 스네이크 케이스를 따른다.
# 카멜 케이스 (자바 스타일)
camelCase: int = 1
# 스네이크 케이스 (파이썬 스타일)
snake_case: int = 1
a: str = "1"
b: int = 1
def fn(a: int) -> bool:
pass
가독성이 좋아진다.
파이썬은 map, filter와 같은 함수형 기능을 지원하며 다음과 같은 람다 표현식도 지원한다.
list(map(lambda x: x+ 10, [1, 2, 3]))
[11, 12, 13]
리스트 컴프리헨션을 사용하자!
[n * 2 for n in range(1, 10 + 1) if n % 2 == 1]
[2, 6, 10, 14, 18]
만약 리스트 컴프리헨션을 사용하지 않으면 다음과 같이 작성해야 한다.
a = []
for n in range(1, 10 + 1):
if n % 2 == 1:
a.append(n * 2)
a
[2, 6, 10, 14, 18]
리스트 외에도 딕셔너리 등이 가능하다.
original = {'test': 1, 'testt': 2}
a = {}
for key, value in original.items():
a[key] = value
a
{'test': 1, 'testt': 2}
제너레이터는 루프의 반복(Iteration) 동작을 제어할 수 있는 루틴 형태
제너레이터는 메모리에 보관해두지 않고, 단순히 제너레이터만 생성해두고 필요할 때 언제든 숫자를 만들 수 있음
yield 구문을 통해 제너레이터를 리턴할 수 있음.
기존의 함수는 리턴 구문을 맞닥뜨리면 값을 리턴하고 모든 함수의 동작을 종료함.
yield는 함수를 종료하지 않고 리턴만 하고 계속해서 함수를 진행한다.
def get_natural_number():
n = 0
while True:
n += 1
yield n
get_natural_number()
<generator object get_natural_number at 0x7f8686fdbcf0>
g = get_natural_number()
for _ in range(0, 5):
print(next(g))
1 2 3 4 5
제너레이터는 여러 타입의 값을 하나의 함수에서 생성하는 것도 가능
def generator():
yield 1
yield 'string'
yield True
g = generator()
g
<generator object generator at 0x7f868790feb0>
next(g)
1
next(g)
'string'
next(g)
True
next(g)
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-27-e734f8aca5ac> in <module> ----> 1 next(g) StopIteration:
제너레이터의 방식을 활용하는 대표적인 함수로 range()가 있다.
list(range(5))
[0, 1, 2, 3, 4]
range(5)
range(0, 5)
type(range(5))
range
for i in range(5):
print(i, end=' ')
0 1 2 3 4
이 코드에서 range()는 range 클래스를 리턴하며, for문에서 사용할 경우 내부적으로 제너레이터와 next()를 호출하듯 매번 다음 숫자를 생성해낸다.
a = [n for n in range(1000000)]
b = range(1000000)
len(a)
1000000
len(b)
1000000
그러나 a에는 이미 생성된 값이 담겨있고, b는 생성해야 한다는 조건만 존재한다.
b
range(0, 1000000)
type(b)
range
메모리 점유율을 비교하면 와닿는다.
import sys
sys.getsizeof(a)
8697456
sys.getsizeof(b)
48
b[10]
10
a[10]
10
a = [1, 2, 3, 2, 45, 2, 5]
a
[1, 2, 3, 2, 45, 2, 5]
enumerate(a)
<enumerate at 0x7f86870fdcc0>
list(enumerate(a))
[(0, 1), (1, 2), (2, 3), (3, 2), (4, 45), (5, 2), (6, 5)]
인덱스를 자동으로 부여해준다.
a = ['a1', 'b2', 'c3']
for i in range(len(a)):
print(i, a[i])
0 a1 1 b2 2 c3
i = 0
for v in a:
print(i, v)
i += 1
0 a1 1 b2 2 c3
for i, v in enumerate(a):
print(i, v)
0 a1 1 b2 2 c3
5 / 3
1.6666666666666667
5 // 3
1
int(5 / 3)
1
몫 (Quotient) = //
나머지 (Remainder) = %
5 % 3
2
몫과 나머지를 동시에 구하는 방법
divmod(5, 3)
(1, 2)
print('A', 'B')
A B
print('A', 'B', sep=',')
A,B
print('a', end=' ')
print('bb')
a bb
a = ['A', 'B']
print(' '.join(a))
A B
idx = 1
fruit = "Apple"
print('{0}: {1}'.format(idx + 1, fruit))
2: Apple
print(f'{idx + 1}: {fruit}')
2: Apple
def test():
pass
pass는 널 연산으로 아무것도 하지 않는 기능
locals는 로컬 심볼 테이블 딕셔너리를 가져오는 메소드로 업데이트 또한 가능하다.
로컬에 선언된 모든 변수를 조회할 수 있는 강력한 명령어.
import pprint
# pprint.pprint(locals())
파이썬의 PEP 8 과 구글의 파이썬 스타일 가이드를 참조하자.
변수명을 잘 지어주고, 주석을 영어로 달아주자
리스트 컴프리헨션은 대체로 표현식이 2개를 넘지 않도록 하고 복잡해질 경우 줄을 나누어 사용하자.
가독성이 떨어 질 수 있기 때문이다.
def foo(a, b=[]):
pass
def bar(a, b = {}):
pass
대신 다음과 같이 불변 객체를 사용한다.
def foo(a, b=None):
pass
def bar(a, b: Optional[Sequence] = None):
if b in None:
b = []
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-76-148b570899cd> in <module> 1 def foo(a, b=None): 2 pass ----> 3 def bar(a, b: Optional[Sequence] = None): 4 if b in None: 5 b = [] NameError: name 'Optional' is not defined
True, False를 판ㅂ녈할 때는 암시적인 방법을 사용하는 편이 간결하고 가독성이 좋다.
Good case
if not user:
...
if foo == 0:
..
if i % 10 == 0:
...
Bad case
if len(users) == 0:
...
if foo is not None and not foo:
...
if not i % 10:
...
파이썬 철학
import this
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!