제어문

if, elif, else (조건문)

if와 else는 조건이 참인지 거짓인지 판단하는 파이썬 선언문(Statement)이며, elif는 else내의 if를 중첩해야 할 때 사용한다.

조건 표현식

In [3]: if is_holiday:
   ...:     print('Good')
   ...: else:
   ...:     print('Bad')
   ...:
Bad

중첩 조건표현식

In [4]: vacation = 7

In [6]: if vacation >= 7:
   ...:     print('Good')
   ...: elif vacation >= 5:
   ...:     print('Normal')
   ...: else:
   ...:     print('Bad')
   ...:
Good

In [8]: print('Good') if vacation >= 7 else print('Normal') if vacation >= 5 else print('Bad')
Good

for문 (조건에 따른 순회)

기본형태

시퀀스형 데이터를 순회하고자 할 때 사용한다.

# for 항목 in 순회가능(iterable)객체:
#   <항목을 사용한 코드>

# 숫자 시퀀스 생성 (range)
# iterable 객체를 반환
In [9]: for i in range(5):
   ...:     print(i)
   ...:
0
1
2
3
4

In [10]: for x in range(1, 10, 3):
    ...:     print(x)
    ...:
1
4
7

# iterable 객체로 문자열, 튜플, 딕셔너리, 셋 등이 있다.
# 리스트
In [11]: champion_list = ['lux', 'ahri', 'ezreal', 'zed']

In [12]: for champion in champion_list:
    ...:     print(champion)
    ...:
lux
ahri
ezreal
zed

# 딕셔너리
In [13]: champion_dict = {
    ...: 'lux': 'abc',
    ...: 'ahri': 'def',
    ...: 'ezreal': 'ghi',
    ...: 'zed': 'jkl',
    ...: }

# 딕셔너리 키를 순회할 때
In [14]: for champion in champion_dict:
    ...:     print(champion)
    ...:
ahri
lux
ezreal
zed

In [15]: for champion in champion_dict.keys():
    ...:     print(champion)
    ...:
ahri
lux
ezreal
zed

# 딕셔너리 값을 순회할 때
In [16]: for champion in champion_dict.values():
    ...:     print(champion)
    ...:
def
abc
ghi
jkl

# 딕셔너리 키/값 모두 순회할 때
In [17]: for champion in champion_dict.items():
    ...:     print(champion)
    ...:
('ahri', 'def')
('lux', 'abc')
('ezreal', 'ghi')
('zed', 'jkl')

중첩

# 구구단 2단부터 9단까지 출력
In [17]: for i in range(2, 10):
    ...:     for j in range(2, 10):
    ...:         print('{} x {} = {}'.format(i, j, i*j))

In [18]: for i in range(2, 10):
    ...:     print('= {} 단 ='.format(i))
    ...:     for j in range(2, 10):
    ...:         print('{} x {} = {}'.format(i, j, i*j))
    ...:     print('\n')
    ...:

중단하기 (break)

데이터를 순회하던 중, 특정 조건에서 순회를 멈추고 반복문을 빠져나갈 때 사용한다.

# 구구단 2단부터 3단까지 출력
In [21]: for i in range(2, 10):
    ...:     print('= {} 단 ='.format(i))
    ...:     for j in range(2, 10):
    ...:         print('{} x {} = {}'.format(i, j, i*j))
    ...:     if i == 3:
    ...:         break

건너뛰기 (break)

데이터를 순회하던 중, 반복문을 중단하지 않고 다음 반복으로 건너뛸 때 사용한다.

# 구구단 4단을 제외한 2단부터 9단까지 출력
In [22]: for i in range(2, 10):
    ...:     if i == 4:
    ...:         continue
    ...:     print('= {} 단 ='.format(i))
    ...:     for j in range(2, 10):
    ...:         print('{} x {} = {}'.format(i, j, i*j))

여러 시퀀스 동시순회 (zip)

# zip으로 묶은 시퀀스 중,
# 가장 짧은 시퀀스가 완료되면 순회종료
In [23]: fruits = ['apple', 'banana', 'melon']
In [24]: colors = ['red', 'yellow', 'green', 'purple']

In [26]: for fruit, color in zip(fruits, colors):
    ...:     print('fruit:', fruit, ' color:', color)
    ...:
fruit: apple  color: red
fruit: banana  color: yellow
fruit: melon  color: green

# 튜플로 반환
In [28]: for item in zip(fruits, colors):
    ...:     print(item)
    ...:     print(type(item))
    ...:     print(item[0])
    ...:     print(item[1])
    ...:
('apple', 'red')
<class 'tuple'>
apple
red
('banana', 'yellow')
<class 'tuple'>
banana
yellow
('melon', 'green')
<class 'tuple'>
melon
green

# zip클래스 형태의 iterable 객체
In [34]: result = zip(colors, fruits)

In [35]: result
Out[35]: <zip at 0x10ab048c8>

In [36]: print(type(result))
<class 'zip'>

# 리스트 형태로 사용하려면 list()함수를 사용
In [37]: result_list = list(result)

In [38]: result_list
Out[38]: [('red', 'apple'), ('yellow', 'banana'), ('green', 'melon')]

In [39]: print(type(result_list))
<class 'list'>

While문 (반복문)

In [45]: count = 0

In [46]: while count < 4:
    ...:     print(count)
    ...:     count += 1
    ...:
0
1
2
3

컴프리헨션 (Comprehension)

iterable한 객체로부터 파이썬의 자료구조를 만드는 방법. 가독성과 사용성에서 이득을 얻을 수 있을 경우 항상 사용해준다.

한줄로 보기좋게 표현된다면, 가능한 사용하는 것이 좋다. (속도나 효율면에서 유리)

리스트 컴프리헨션

# [표현식 for 항목 in iterable객체]
In [47]: [i for i in range(1, 6)]
Out[47]: [1, 2, 3, 4, 5]

In [48]: [i*2 for i in range(1, 6)]
Out[48]: [2, 4, 6, 8, 10]

In [49]: [i for i in range(1, 15) if i % 2 == 0]
Out[49]: [2, 4, 6, 8, 10, 12, 14]

# 리스트 컴프리헨션의 중첩
# 3중 중첩까지 가면 알아보기 힘들기 때문에,
# 2중 중첩까지만 사용하는게 좋음
In [50]: [(color, fruit) for color in colors for fruit in fruits]
Out[50]:
[('red', 'apple'),
 ('red', 'banana'),
 ('red', 'melon'),
 ('yellow', 'apple'),
 ('yellow', 'banana'),
 ('yellow', 'melon'),
 ('green', 'apple'),
 ('green', 'banana'),
 ('green', 'melon'),
 ('purple', 'apple'),
 ('purple', 'banana'),
 ('purple', 'melon')]

셋 컴프리헨션

In [51]: {i for i in range(1,4)}
Out[51]: {1, 2, 3}

제네레이터 컴프리헨션

괄호로 되어있지만 튜플을 생성하지 않는다. 튜플은 컴프리헨션이 없다.

# 제너레이터 객체는 순회 가능하다.
In [51]: {i for i in range(1,4)}
Out[51]: {1, 2, 3}

In [52]: g = (item for item in range(10))

In [53]: g
Out[53]: <generator object <genexpr> at 0x10ac366c0>

In [54]: print(type(g))
<class 'generator'>

# 리스트 형태로 만들 수 있다.
In [55]: g_list = list(g)

In [56]: g_list
Out[56]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [57]: print(type(g_list))
<class 'list'>

실습

  1. for문을 2개 중첩하여 (0,0), (0,1), (0,2), (0,3), (1,0), (1,1)….. (6,3)까지 출력되는 반복문을 구현한다.
  2. 리스트 컴프리헨션을 중첩하여 위 결과를 똑같이 출력한다.
  3. 1, 2번의 반복문에서 튜플의 첫 번째 항목이 짝수일때만 출력하도록 조건을 변경한다.
  4. 1000에서 2000까지의 숫자 중, 홀수의 합을 구해본다.
  5. 리스트 컴프리헨션을 사용하여 구구단 결과를 갖는 리스트를 만들고, 해당 리스트를 for문을 사용해 구구단 형태로 나오도록 출력해본다. (각 단마다 한 번 더 줄바꿈을 넣어준다.)
  6. 1에서 99까지의 정수 중, 7의 배수이거나 9의 배수인 정수인 리스트를 생성한다. 단, 7의 배수이며 9의 배수인 수는 한 번만 추가되어야 한다.
In [1]: for i in range(7):
   ...:     for j in range(4):
   ...:         print('({}, {})'.format(i, j))
   ...:

In [2]: xy = [(x, y) for x in range(7) for y in range(4)]

In [4]: for i in xy:
   ...:     print(i)


In [5]: for i in range(7):
   ...:     if i % 2 != 0:
   ...:         continue
   ...:     for j in range(4):
   ...:         print((i, j))
   ...:
# 이렇게 작성해도 되지만, 위의 코드가 더 효율적이다.
In [7]: for i in range(7):
   ...:     for j in range(4):
   ...:         if i % 2 == 0:
   ...:             print((i, j))
   ...:
# 효율코드의 리스트 컴프리헨션
In [13]: [(i, j) for i in range(7) if i % 2 == 0 for j in range(4)]


In [16]: result = 0

In [17]: for i in range(1000, 2001):
    ...:     if i % 2 != 0:
    ...:         result += i
    ...:

In [18]: print(result)
750000


In [24]: result = [ x*y for x in range(2, 10) for y in range(2, 10)]

In [25]: index = 0

In [26]: for i in range(2, 10):
    ...:     for j in range(2, 10):
    ...:         print('{} x {} = {}'.format(i, j, result[index]))
    ...:         index += 1
    ...:     print('\n')

# enumerate : iterable 객체를 count
# 이용해 위에서 인덱스 역할을 편리하게 구현할 수 있다.
In [35]: for index, x in enumerate(range(1002, 1010)):
    ...:     print('index: {}, value: {}'.format(index, x))
    ...:
index: 0, value: 1002
index: 1, value: 1003
index: 2, value: 1004
index: 3, value: 1005
index: 4, value: 1006
index: 5, value: 1007
index: 6, value: 1008
index: 7, value: 1009

# 다른 방법
In [32]: result = ['{} x {} = {}'.format(i, j, i*j) for i in range(2, 10
    ...: ) for j in range(1, 10)]

In [33]: for i in result:
    ...:     print(i)


In [34]: for i in range(1, 100):
    ...:     if i % 7 == 0 or i % 9 == 0:
    ...:         print(i)
    ...:

In [35]: [i for i in range(1, 100) if i % 7 == 0 or i % 9 == 0]

함수

반복적인 작업을 하는 코드를 재사용이 가능하게 정의해 놓은 것

함수의 정의, 실행

# 함수 정의
In [1]: def func():
   ...:     print('call func')

# 함수 자체는 function 객체를 참조하는 변수
In [2]: func
Out[2]: <function __main__.func>

In [4]: print(type(func))
<class 'function'>

# 함수 실행
In [5]: func()
call func

리턴 값이 있는 함수 정의

함수의 결과로 Bool값을 갖는 데이터를 리턴하여 if문이나 while문의 조건으로 사용가능하다.

In [6]: def return_true():
   ...:     return True
   ...:

In [7]: return_true()
Out[7]: True

In [8]: result = return_true()

In [9]: print(result)
True

In [10]: print(type(result))
<class 'bool'>

In [11]: if return_true():
    ...:     print('return_true')
    ...: else:
    ...:     print('false')
    ...:
return_true

매개변수를 사용하는 함수 정의

In [12]: def print_arguments(something):
    ...:     print(something)
    ...:

In [13]: print_arguments('ABC')
ABC

매개변수(parameter)와 인자(argument)의 차이

함수 내부에서 함수에게 전달되어 온 변수는 매개변수라 부르며, 함수를 호출할 때 전달하는 변수는 인자로 부른다.

# 함수 정의시, 매개변수
def func(매개변수1, 매개변수2):

# 함수 호출시, 인자
func(인자1, 인자2)

리턴값이 없을 경우

함수에서 리턴해 주는 값이 없을 경우, 아무것도 없다는 뜻을 가진 None 객체를 얻는다.

# 아무겂도 없다는 것을 알려주기위한 객체
In [16]: a = None

In [17]: print(type(a))
<class 'NoneType'>

# 파이썬이 미리 생성해논 객체이므로 똑같은 주소 참조
In [18]: id(a)
Out[18]: 4356116024

In [19]: b = None

In [20]: id(b)
Out[20]: 4356116024

위치 인자 (Positional arguments)

매개변수의 순서대로 인자를 전달하여 사용하는 경우

In [21]: def student(name, age, gender):
    ...:     return {'name': name, 'age': age, 'gender': gender}
    ...:

In [24]: student('hmlim', 30, 'female')
Out[24]: {'age': 30, 'gender': 'female', 'name': 'hmlim'}

In [25]: student(30, 'hylee', 'male')
Out[25]: {'age': 'hylee', 'gender': 'male', 'name': 30}

In [26]: h_name = 'kdhong'
In [27]: h_age = 20
In [28]: h_gender = 'male'

In [29]: student(h_name, h_age, h_gender)
Out[29]: {'age': 20, 'gender': 'male', 'name': 'kdhong'}

키워드 인자 (Keyword arguments)

매개변수의 이름을 지정하여 인자로 전달하여 사용하는 경우이다. 순서 상관없이 인자를 전달한다. (예: 회원가입 받을 때)

In [31]: student(age=30, name='yhlee', gender='female')
Out[31]: {'age': 30, 'gender': 'female', 'name': 'yhlee'}

# 괄호안에서는 자유롭게 타이핑 가능
In [34]: student(
    ...:     name = 'mike',
    ...:     gender = 'male',
    ...:     age = 35
    ...: )
Out[34]: {'age': 35, 'gender': 'male', 'name': 'mike'}

# 위치 인자와 키워드 인자를 혼합해 사용할 경우
In [35]: student('sam', 25, gender='male')
Out[35]: {'age': 25, 'gender': 'male', 'name': 'sam'}
# 키워드 인자는 맨 뒤에 전달
In [36]: student(name='kate', 40, 'female')
  File "<ipython-input-36-0648f45f1b0d>", line 1
    student(name='kate', 40, 'female')
                        ^
SyntaxError: non-keyword arg after keyword arg

기본 매개변수값 지정

인자가 제공되지 않을 경우, 기본 매개변수로 사용할 값을 지정할 수 있다.

In [41]: def get_student(name, age, gender, school_class='WPS'):
    ...:     return {'name': name, 'age': age, 'gender': gender, 'class': school_class}
    ...:

In [42]: get_student('hmlim', 30, 'female')
Out[42]: {'age': 30, 'class': 'WPS', 'gender': 'female', 'name': 'hmlim'}

In [43]: get_student('lhy', 30, 'male', 'WDS')
Out[43]: {'age': 30, 'class': 'WDS', 'gender': 'male', 'name': 'lhy'}

기본 매개변수값 정의 시점

기본 매개변수값은 함수가 실행될 때 마다 계산되지 않고, 함수가 정의 되는 시점에 계속해서 사용된다.

In [52]: def return_list1(value, result=[]):
    ...:     result.append(value)
    ...:     return result

# 인자가 제공되지 않을 경우,
# 기본 매개변수값으로 지정한 result=[] 사용
In [54]: return_list1('apple')
Out[54]: ['apple']

# 계속 사용
In [55]: return_list1('banana')
Out[55]: ['apple', 'banana']

# 인자가 제공된 경우,
# fruits_list 리스트 객체에 value 추가
In [56]: fruits_list = ['melon', 'orange']

In [57]: return_list1('lemon', fruits_list)
Out[57]: ['melon', 'orange', 'lemon']

In [60]: return_list1('mango')
Out[60]: ['apple', 'banana', 'mango']

In [61]: return_list1('apple', fruits_list)
Out[61]: ['melon', 'orange', 'lemon', 'apple']


In [58]: return_list1('peer', 'mango')
-------------------------------------------------------
AttributeError: 'str' object has no attribute 'append'

In [59]: return_list1('peer', f_list = ['mango'])
-------------------------------------------------------
TypeError: return_list1() got an unexpected keyword argument 'f_list'

함수가 실행되는 시점에 기본 매개변수 값을 계산하려면, 아래와 같이 바꿔준다.

# 기본 변수값을 None 객체로 지정
In [67]: def return_list2(value, result=None):
    ...:     if result is None:
    ...:         result = []
    ...:     result.append(value)
    ...:     return result
    ...:
# 이렇게 작성할 수 있지만,
# 사용하다 오류가 발생할 확률이 있으므로
# None을 사용하는게 좋다.
In [67]: def return_list2(value, result=3):
    ...:     if result is 3:
    ...:         result = []
    ...:     result.append(value)
    ...:     return result
    ...:

# 인자가 제공되지 않을 경우
In [68]: return_list2('apple')
Out[68]: ['apple']

In [69]: return_list2('banana')
Out[69]: ['banana']

# 인자가 제공된 경우,
# None 대신 주어진 인자값으로 대체
In [70]: return_list2('banana', fruits_list)
Out[70]: ['melon', 'orange', 'lemon', 'apple', 'banana']


In [72]: return_list1_step1 = return_list('red')
In [73]: return_list1_step2 = return_list('blue')

In [74]: id(return_list1_step1)
Out[74]: 4390107848

In [75]: id(return_list1_step2)
Out[75]: 4390107848


In [78]: return_list2_step1 = return_list2('red')
In [79]: return_list2_step2 = return_list2('blue')

In [80]: id(return_list2_step1)
Out[80]: 4389394760

In [81]: id(return_list2_step2)
Out[81]: 4390238024

# 사용예
In [20]: def add_value_for_list_or_return_new_list_contain_value(add_value, ori_list=None):
    ...:     if ori_list is None:
    ...:         ori_list = []
    ...:     ori_list.append(add_value)
    ...:     return ori_list

위치인자 묶음

함수에 위치인자로 주어진 변수들의 묶음은 *매개변수명으로 사용할 수 있다. 관용적으로 *args를 사용한다. 인자 개수가 정해지지 않았을 때 사용한다.

In [82]: def print_args(*args):
    ...:     print(args)
    ...:

# 튜플로 반환
In [83]: print_args(1)
(1,)

In [84]: print_args(1, 2)
(1, 2)

In [85]: print_args(1, 2, 'abc', [])
(1, 2, 'abc', [])

In [86]: result = return_args(1, 2, 'abc', [])

# 키워드 인자는 사용할 수 없음
In [89]: result = return_args(1, 2, 'abc', [], k1='abc')
-------------------------------------------------------
TypeError: return_args() got an unexpected keyword argument 'k1'

키워드 인자 묶음

함수에 키워드인자로 주어진 변수들의 묶음은 **매개변수명으로 사용할 수 있다. 관용적으로 **kwargs를 사용한다.

In [11]: def print_kwargs(**kwargs):
    ...:     print(kwargs)
    ...:

# 딕셔너리로 반환
In [12]: print_kwargs(name='hmlim', gender='female', age=30)
{'name': 'hmlim', 'age': 30, 'gender': 'female'}


In [15]: def all_args(*args, **kwargs):
    ...:     print('position args: ', args)
    ...:     print('keyword args: ', kwargs)
    ...:

# 키워드 인자는 맨 뒤에 전달
In [17]: all_args(123, 'abc', color='red')
position args:  (123, 'abc')
keyword args:  {'color': 'red'}

In [18]: all_args(color='blue', 124)
  File "<ipython-input-18-fc7d069c059d>", line 1
    all_args(color='blue', 124)
                          ^
SyntaxError: non-keyword arg after keyword arg

# 사용예
In [29]: def print_args_len(*args):
    ...:     print('args count: {}'.format(len(args)))
    ...:

In [30]: print_args_len(1, 2, 3, 4, 7)
args count: 5


In [31]: def print_kwargs_len(**kwargs):
    ...:     print('kwargus count: {}'.format(len(kwargs)))
    ...:

In [33]: print_kwargs_len(name='abc')
kwargus count: 1

In [34]: def print_kwargs_key_value(**kwargs):
    ...:     for item in kwargs.items():
    ...:         print('key {}, value {}'.format(item[0], item[1]))
    ...:

In [35]: print_kwargs_key_value(name='hmlim', gender='female')
key name, value hmlim
key gender, value female

docstring

함수를 정의한 문서 역할을 한다. 함수 정의 후, 몸체의 시작부분에 문자열로 작성한다.

In [36]: def print_args_len(*args):
    ...:     'Print positional arguments with length'
    ...:     print(args)
    ...:     return len(args)
    ...:
# help 함수를 이용해 docstring을 볼 수 있다.
In [37]: help(print_args_len)

# 여러줄로 작성 가능
In [38]: def print_kwargs(**kwargs):
    ...:     '''Print keyword arguments
    ...:     and return length'''
    ...:     print(kwargs)
    ...:     return len(kwargs)
    ...:

In [39]: help(print_kwargs)

함수를 인자로 전달

파이썬에서 함수 역시 다른 객체와 동등하게 취급되므로 함수에서 인자로 함수를 전달, 실행, 리턴하는 형태의 프로그래밍이 가능하다.

In [40]: def print_call_func():
    ...:     print('call func')
    ...:

In [42]: def excute_args_func(func):
    ...:     func()
    ...:

In [43]: excute_args_func(print_call_func)
call func

내부함수

함수 안에서 또 다른 함수를 정의해 사용할 수 있다.

In [50]: def outer(val):
    ...:     def inner():
    ...:         return val.upper()
    ...:     return inner()
    ...:

In [51]: outer('a')
Out[51]: 'A'