① 필요하다면 코드를 여러 줄에 걸쳐 작성한다
물리적으로 1줄보다 긴 문장을 작성할 때 여러 가지 방법을 이용해서 해결할 수 있다.
- literal 문자열 다음에 literal 문자열 입력
ex) my_str = 'I am Hen-er-y the Eighth,' ' I am!' 라고 입력
>>> my_str
'I am Hen-er-y the Eighth, I am!' 로 입력된다.
# 'I am Hen-er-y the Eighth, ' 라는 literal 문자열 다음에
# 한 칸 띄고
# ' I am!' literal 문자열을 입력함으로써 두 문자열을 연결했다.
\
를 이용하는 방법
my_str = 'I am Hen-er-y the Eighth,' \
' I am!'
# 이때, 역슬래시(\) 뒤에 아무런 공백없이 바로 줄 바꿈을 해줘야 한다.
>>> my_str
'I am ready! You are ready'
- 소괄호, 중괄호, 대괄호를 이용하는 방법
my_str = ('I am ready! '
' You are ready'
' Living in the sunlight')
>>> my_str
'I am ready! You are ready Living in the sunlight'
② for 루프 현명하게 사용하기
range 함수를 사용하는 건 C 언어 스타일의 for 루프이다.
- C 언어 스타일의 for 루프
beat_list = ['John', 'Paul', 'George', 'Ringo']
for i in range(len(beat_list)) :
print(beat_list[i])
위와 같이 for루프를 사용하지 말고 아래와 같이 for 루프를 사용하도록 하자.
Java에서 사용하는 enhanced-for문과 비슷해보인다.
beat_list = ['John', 'Paul', 'George', 'Ringo']
for guy in beat_list :
print(guy)
인덱스 번호도 함께 생성하고 싶다면 enumerate 함수를 사용하자.
beat_list = ['John', 'Paul', 'George', 'Ringo']
for guy in beat_list :
print(guy)
# 출력 결과
1. John
2. Paul
3. George
4. Ringo
cf) 인덱스를 사용하지 않고 변수 값을 변경한다면 객체의 값이 변경되지 않고 새로운 객체가 생성되어 해당 변수에 대입된다.
무슨 말이냐면 다음 코드를 보자.
beat_list = ['John', 'Paul', 'George', 'Ringo']
for guy in beat_list :
guy = 'Chris' # 인덱스를 사용하지 않고 변수 값을 변경 시도
print(beat_list)
# 출력 결과 - 객체의 값이 변경되지 않음
['John', 'Paul', 'George', 'Ringo']
for 문 안에서 beat_list의 각각의 값을 guy
라는 변수로 가리키도록 했다.
그런데, 가리키는 값을 Chris
라는 새롭게 생성된 객체로 바꾼 것이다.
그러면, guy 변수
가 가리키던 값이 변경될 뿐 beat_list
의 0번째 값에는 아무런 변화가 생기지 않는다.
③ 메모리-값-변경(in place)과 신규-객체-생성(non-in-place)
문자열(String)과 리스트가 이런 차이를 분명하게 보여준다.
- 문자열
s1 = s2 = 'A string'
s1 += '...with more stuff!'
>>> s1
'A string...with more stuff!'
>>> s2
'A string'
여기서 주목할 점은 s1이 참조하던 값을 메모리에서 변경한 것이 아니다.
새로운 문자열 'A string...with more stuff!'
을 생성해서 참조한 것이다.
그렇기 때문에 s1과 s2는 지금 서로 다른 값을 가리키고 있는 상태다.
- 리스트
a_list = b_list = [10, 20]
a_list += [30, 40]
>>> a_list
[10, 20, 30, 40]
>>> b_list
[10, 20, 30, 40]
분명 a_list를 변경했음에도 불구하고 b_list의 값도 변경된 걸 확인할 수 있다.
왜냐하면, a_list와 b_list는 서로 같은 리스트를 가리켰기 때문에 a_list에서 변경한 리스트는 b_list가 가리킨 리스트와 동일하기 때문이다.
값을 직접 변경하는 연산
이 신규 객체를 생성하는 연산
보다 훨씬 효율적이다.
그래서 문자열에서 +=
를 사용하는 것 보다는 join 메서드
를 사용하는 것이 더 좋다.
ex)
str_list = []
n = ord('a')
for i in range(n, n+26) :
str_list += chr(i);
alpha_str = ''.join(str_list)
>>> alpha_str
'abcdefghijklmnopqrstuvwxyz'
④ 다중 대입
a = b = c = d = 0 # a, b, c, d 서로 다른 4개의 변수에 값은 값(0)을 대입할 수 있다
⑤ 튜플 대입
다중 대입은 서로 다른 변수에 같은 값을 대입할 떄 유용하다.
하지만, 서로 다른 값을 대입하고 싶다면 어떻게 해야 할까?
가장 먼저 생각할 수 있는 방법은 아래와 같다.
a = 1
b = 0
하지만, 튜플 대입을 사용하면 1줄로 표현할 수 있다.
a, b = 1, 0
튜플 대입을 이용하면 swap 과정을 간편하게 구현할 수 있다
- 다른 언어의 swap
temp = x
x = y
y = temp
- python에서의 swap
x, y = y, x
⑥ 고급 튜플 대입
- 튜플 unpack
tup = 10, 20, 30 # 3개의 값을 저장한 튜플
a, b, c = tup # 튜플에 있는 3개의 값을 3개의 변수에 저장
# 물론, 좌측 변수의 개수와 우측에 있는 튜플의 값 개수가 동일해야 한다.
# 그렇지 않으면 에러가 발생
print(a, b, c)
- 1개의 값을 갖는 튜플 생성
my_tup = (1)
# my_tup의 타입 내용 - 그냥 정수 값으로 저장됨
>> type(my_tup)
<class 'int'>
이렇듯 소괄호 기호만을 가지고 1개의 항목
을 갖는 튜플을 생성할 수는 없다. 그래서 다음과 같이 입력해줘야 한다.
my_tup = (1, )
# my_tup의 타입 내용
>>> type(my_tup)
<class 'tuple'>
*
기호를 사용한 튜플 대입
*
기호를 사용하면 튜플 대입에 유연성을 더할 수 있다.
a, *b = 2, 4, 6, 8
>>> a
2
>>> b
[4, 6, 8]
위와 같이 변수 b가 첫 번째를 제외한 나머지 항목들의 리스트를 참조한다는 걸 알 수 있다.
*
기호는 좌항의 위치 상관없이 놓을 수 있다. 다만, 1개만 사용할 수 있다.
a, *b, c = 10, 20, 30, 40, 50, 6000
>>> a
10
>>> b
[20, 30, 40, 50]
>>> c
6000
⑦ 리스트와 문자열 곱하기
- 리스트 곱하기
C, Java 언어는 배열의 개수를 미리 정해서 선언한다. 하지만, python은 별도의 데이터 선언이 없다.
그래서 많은 개수의 리스트를 만드려면 일일이 초기값을 넣어줘야 한다.
list = [0, 0, 0, 0, .... ]
하지만, 초기값을 일일이 넣는다는 건 말이 안된다. 그래서 아래와 같은 방법을 사용하면 된다.
my_list = [0] * 10000 # 보이는 대로 0을 10000개 넣은 리스트가 생성됨
>>> len(my_list)
10000
- 문자열 곱하기
문자열에서도 동일한 기능을 위한 곱하기(*
)를 사용할 수 있다.
div_str = '-' * 40
>>> div_str
'----------------------------------------'
⑧ 여러 개의 값 return
ex) 2차 방정식을 수행하는 함수. 전달하는 매개변수는 계수값.
>>> def quad(a, b, c) :
... det = (b * b - 4 * a * c) ** .5
... x1 = (-b + det) / (2 * a)
... x2 = (-b - det) / (2 * a)
... return x1, x2
...
>>> quad(1, -2, 1)
(1.0, 1.0) # 함수의 return값이 이와 같이 2개 나오도록 할 수 있다.
⑨ 루프와 else 키워드
else는 대부분 if 와 함께 쓰인다.
파이썬에서는 루프에서 사용하는 try-except 문법으로 사용될 수 있다.
반복문에서 사용한 else
는 루프가 break문을 만나서 일찍 빠져나오지 않는다면 반복문 종료시 실행된다.
def find_divisor(n, max) :
for i in range(2, max + 1) :
if n % i == 0 :
print (i, 'divides evenly into', n)
break
else :
print("No!!!!")
>>> find_divisor(49, 6) # break 문을 만나지 않으면서 반복문이 끝났으니까 else 부분 실행
No!!!!
>>> find_divisor(49, 7) # break 문을 만나서 반복문이 끝났으니까 else 부분 실행 X
7 divides evenly into 49
⑩ 필요없는 문자 제거 - replace
s = s.replace(' ', '') # 문자열 s에서 빈칸을 없애주는 코드
만약에 모든 모음을 삭제하고 싶다면 다음과 같이 쓸 수 있다.
# 문자열 s의 각각의 문자를 c로 가리키고
# 그 c가 모음이 아닌 경우에만 저장되도록 함
a_list = [c for c in s if c not in 'aeiou']
s = ''.join(a_list)
⑪ 연결된 비교 연산자
if 0 < x and x < 100 :
print('x is in range')
# 짧게 변경 - 연결된 비교 연산자 사용
if 0 < x < 100 :
print('x is in range')
- 여러 종류 섞어 쓰는 경우
a, b, c = 5, 10, 15
# 0 < a <= c and c > b > 1 을 의미함
if 0 < a <= c > b > 1 :
~~~
# a, b, c, d, e가 모두 같은 값인 경우
if a == b == c == d == e :
~~
이처럼 파이썬에서는 여러개의 비교연산자를 한꺼번에 사용할 수 있다.
⑫ 함수 테이블로 switch문 모방하기
파이썬은 switch문을 제공하지 않는다. 그렇지만 if/elif를 여러 번 쓴다면 코드가 장황해보일 수 있다.
- if/elif를 사용한 경우
if n == 1:
do_plot(stockdf)
elif n == 2 :
do_highlow_plot(stockdf)
elif n == 3 :
do_volumn_subplot(stockdf)
elif n == 4 :
do_movingavg_plot(stockdf)
장황하다. 그래서 다음과 같은 idea를 통해 switch문을 모방할 수 있다.
- 리스트를 이용한 방식
fn = [sum, max, min]
>>> fn[0]([1, 2, 3]) # sum
6
>>> fn[1]([1, 2, 3]) # max
3
>>> fn[2]([1, 2, 3]) # min
1
함수를 저장하고 있는 리스트를 만들어서
원하는 함수에 해당하는 인덱싱을 해서 각각 다른 함수를 호출하는 방식을 생각할 수 있다.
파이썬 함수 역시 객체이기 때문에 리스트의 항목에 넣을 수 있기에 가능한 방식이다.
- 딕셔너리를 이용한 방식
fn = {'SUM' : sum, 'MAX': max, 'MIN' : min}
fn['SUM']([1, 2, 3])
fn['MAX']([1, 2, 3])
fn['MIN']([1, 2, 3])
⑬ 동등 연산자(==) vs is 연산자
아래와 같은 상황을 보자.
s1 = "I am what I am and that is all that I am"
s2 = "I am what I am" + " and that is all that I am"
# 동등 연산자로 본다면 s1, s2는 같은 값을 가지기 때문에 true
>>> s1 == s2
True
# s1, s2는 동일한 값을 갖더라도 서로 다른 객체이기 때문에 is 연산자에서는 false를 반환
>>> s1 is s2
False
그래서 is 연산자를 사용하는 경우는
1) None, True, False와 같은 객체와 비교하는 경우
2) 동일한 객체의 값을 비교하는 경우
⑭ 여러 문장을 1줄로 줄이기
코드의 문장들이 충분히 짧다면 여러 문장을 1줄로 작성할 수 있다.
a = 1; b = 2; c = a+b; print(c)
물론 1줄씩 작성할 때는 ;
을 사용하지 않아도 되지만 공간을 절약할 수 있다는 측면에서 충분히 활용할 수 있는 문법이다.
⑮ 단일 행 if/then/else문
형식부터 설명하면 다음과 같다.
(참 값) if 조건문 else (거짓 값)
# 조건문이 참일 때 (참 값)을 반환
# 조건문이 거짓일 때 (거짓 값)을 반환
ex)
cell = 'X' if turn % 2 else 'O'
⑯ range와 함께 enum 생성
각각의 변수를 숫자로 표현하는게 편한 경우가 있다.
red = 0; blue = 1; green = 2; black = 3; white = 4
위 코드는 잘 동작하지만 자동화 할 수 있는 방법이 있다. 아래의 방법을 보자.
red, blue, green, black, white = range(5) # 위 코드랑 동일한 내용이다.
# 1부터 시작하고 싶다면 range(1, 6)을 쓰면 된다.
⑰ IDLE 안에서 print 함수 사용 줄이기
ex) 별표 기호(*
) 40 * 20 블록으로 출력하기
- 가장 느린 방법 - print 함수를 40 * 20번 호출한다
for i in range(20) :
for j in range(40) :
print('*', end = ' ')
print()
- 한 번에 한 개 행의 별표 기호를 출력
row_of_aster = '*' * 40
for i in range(20) :
print(row_of_aster)
- 여러 줄의 큰 문자열을 미리 만들고 print는 1번만 호출 -
+=
이용
row_of_aster = '*' * 40
s = ''
for i in range(20) :
s += row_of_aster + '\n'
print(s)
성능을 좀 더 개선하기 위해 join 메소드를 사용한다.
- 여러 줄의 큰 문자열을 미리 만들고 print는 1번만 호출 -
join
이용
row_of_aster = '*' * 40
list_str = []
for i in range(20) :
list_str.append(row_of_aster)
print('\n'.join(list_str)) # 리스트를 합치는데
# 구분되는 곳 마다 '\n'을 넣어서 합친다.
위 코드를 1줄로 줄이면
print('\n'.join(['*' * 40] * 20))
⑱ 큰 숫자에 _ 삽입
보통 숫자를 구분할 때 콤마(,
)를 쓴다. ex) 1,400,000
그렇지만, 파이썬에서는 콤마를 이용해서 값을 넣지 못한다. ex) n = 1,400,000 => 안되는 코드
그래서 _
를 사용할 수 있다.
>>> n = 1_500_0000
>>> n
15000000
'Python' 카테고리의 다른 글
[파이썬 코드 업] 4-3장. 데코레이터 (0) | 2023.05.06 |
---|---|
[파이썬 코드 업] 4-2장. (0) | 2023.05.06 |
[파이썬 스킬 업] 3장. 리스트 기능 (0) | 2023.04.27 |
[파이썬 스킬 업] 2장. 문자열 기능 (0) | 2023.04.25 |
[파이썬 스킬 업] 1-4 세트(set) (0) | 2023.04.17 |