python 함수 - scope, lambda, closure, decorator, generator

|

패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
이 포스팅에서는 python 함수에 대해 설명합니다.


스코프 (영역)

파이썬에서는 코드 작성 시, 각 함수마다 독립적인 스코프(영역)을 가진다.

메인 프로그램(현재 동작하는 프로그램의 최상위 위치)의 영역은 전역영역(global scope)라고 하며, 전역 스코프 내부에서 독립적인 영역을 갖고 있는 경우에는 지역영역(local scope)라고 부른다.

champion = 'Lux'

def show_global_champion():
  print('show_global_champion : {}'.format(champion))

show_global_champion()
>>> show_global_champion : Lux

print('print champion : {}'.format(champion))
>>> print champion: Lux
champion = 'Lux'

def show_global_champion():
  print('show_global_champion : {}'.format(champion))

def change_global_champion():
  print('before change_global_champion : {}'.format(champion))
  champion = 'Ahri'
  print('after change_global_champion : {}'.format(champion))

show_global_champion()
>>> show_global_champion: Lux

change_global_champion()
>>> UnboundLocalError: local variable 'champion' referenced before assignment

change_global_champion 함수에서 오류를 볼 수 있다.

첫번째 코드에서는 champion변수가 함수의 로컬 스코프에 존재하지 않기 때문에 글로블스코프에서 해당 변수를 찾아 출력했으나, 다음 코드에서는 내부에 또다른 champion변수가 존재하기 때문에 할당하기 전인 변수를사용한 것으로 판단하여 프로그램에서 오류를 발생시킨다.

id(show_global_champion)
>>> 4378671712

id(change_global_champion)
>>> 4375901320

뿐만 아니라, 각 영역에 해당하는 데이터들은 locals()함수를 사용해 확인할 수 있으며, 전역 영역의 데이터들은 globals()함수를 사용한다.

champion = 'Lux'

def show_global_champion():
  print('show_global_champion : {}'.format(champion))

def change_global_champion():
  print(locals())
  champion = 'Ahri'
  print('after change_global_champion : {}'.format(champion))

show_global_champion()
>>> show_global_champion : Lux

change_global_champion()
>>> {}
    after change_global_champion : Ahri

즉, 함수는 독립적인 영역으로 위에서 정의한 것을 아래에서도 똑같이 정의 받지 못한다. 그래서 정의 받지 못하는 함수는 로컬의 값을 정의받는데, 그때 그것을 확인하는 방법은 locals()을 사용한다. 이를 사용해서 보면 두번째에 사용한 lux의 값은 {}으로 아무것도 받지 못했음을 알 수 있다.

스코핑 롤

스코프는 지역(local), 전역(global)외에도 내장(bulit-in)영역이 존재하며, 내장영역이 가장 바깥, 그 내부에 전역, 그 내부의 지역순으로 정의된다.

분리된 영역에서, 외부 영역에서는 내부 영역의 데이터를 사용할 수 없지만, 내부 영역에서는 자신의 외부 영역에 있는 데이터를 참조할 수 있다. (반대의 경우에는 함수의 인자로 데이터를 전달한다.)

즉 위의 예를 보면 show_global_championchange_glabal_champion함수의 데이터를 사용할 수 없지만, change_global_champion에서는 champion = 'Lux'데이터를 참조할 수 있다.

내장함수와 내장영역

print, dict 등 지정하지 않고 사용했던 내장 함수들은 위 스코핑 룰의 내장 스코프에 존재하는 함수들이다. 전역스코프의 __builtin__ 변수에 할당되어 있으며, 전역 스코프에서는 해당 변수의 내부를 참조할 수 있도록 파이썬이 시작될 때 자동으로 처리된다.

확인시 dir함수를 사용하며, dir함수는 해당 객체가 사용 가능한 속성 및 함수들을 리스트 형태로 나타내준다.

로컬 스코프에서 글로벌 스코프의 변수를 사용

champion = 'Lux'

def change_global_champion():
  champion = 'Ahri'
  print('after change_global_champion : {}'.format(champion))

change_global_champion()
>>> after change_glabal_champion : Ahri

print('print global champion : {}'.format(champion))
>>> print global champion : Lux

이 경우에는 show_global_champion함수와는 다르게 change_glabal_champion함수는 champion변수에 새로운 값(Ahri)을 대입한다. 만약 로컬 스코프에서 글로벌 스코프의 변수를 변경해야 한다면, 해당 변수가 로컬 스코프에서 생성되는 것이 아닌 글로벌 영역에 이미 존재하는 값을 가용함을 명시해주어야 한다.

champion = 'Lux'

def change_glabal_champion():
  global champion
  champion = 'Ahri'
  print('after change_glabal_champion : {}'.format(champion))


change_glabal_champion
>>> after change_global_champin : Ahri

print('print global champion : {}'.format(champion))
>>> print global champion : Ahri

파이썬에서는 한 스코프에서 동일한 이름을 가진 두 스코프의 변수를 사용할 수 없음을 기억해야 한다.

내부 함수에서의 로컬 스코프 (nonlocal)

champion = 'Lux'

def local1():
  global champion
  champion = 'Ahri'
  print('local1 locals() : {}'.format(champion))

  def local2():
    champion = 'Exreal'
    print('local2 locals() : {}'.format(locals()))

  local2()

print('global champion : {}'.format(champion))
>>> global champion : Lux

local1()
>>> local1 locals() : Ahri
    local2 locals() : {'champion': 'Ezreal'}

이렇듯 로컬 스코프 내부에 또 다른 로컬 스코프가 존재할 수 있다.

전역 스코프가 아닌, 자신의 바로 바깥 영역의 로컬 스코프(자신보다 한 단계 위의 로컬 스코프)의 데이터를 참조하고자 한다면, nonlocal키워드를 사용한다.

champion = 'Lux'

def local1():
  champion = 'Ahri'
  print('local1 locals() : {}'.format(champion))

  def local2():
    nonlocal champion
    champion = 'Ezreal'
    print('local2 locals() : {}'.format(champion))

  local2()
  print('local1 locala() : {}'.format(locals()))

print('global champion : {}'.format(champion
>>> global champion : Lux
local1()
>>> local1 locals() : Ahri
    local2 locals() : {'champion': 'Ezreal'}
    local1 locals() : {'local2': <function local1.<locals>.local2 at 0x10ea617b8>, 'champion': 'Ezreal'}

글로벌 키워드와 인자 전달의 차이

인자로 전달한 경우

global_level = 100

def level_add(value):
  value += 30
  print(value)

level_add(global_level)
>>> 130

print(global_level)
>>> 100

# 글로벌 레벨이라는 변수는 100이라는 변수를 참조하고 있다.
# 레벨 애드라는 함수에 벨류라는 파라미터를 가지고 여기서 글로벌 레벨을 전달했는데,
# 이 벨류가 같은 곳을 가리키게 된다. (100)
# 그 다음 밸류에 +30이 되어 메모리에는 130이 생기고 레벨에드는 100과의 연결이 끊기고 130에게 가게 되는 것이다.

# 그러면서 id값도 바뀌게 된다.
# 함수가 130을 가리키게 되면 그 130이라는 메모리는 이미 함수가 종료했으니 사라지고
# 여전히 100만 남기 때문에 프린트 글로벌 레벨은 100이 그대로 실행된다.

글로벌 키워드를 사용한 경우

global_level = 100

def level_add():
  global global_level
  global_level += 30
  print(global_level)

print(global_level)
>>> 100

level_add()
>>> 130

print(global_level)
>>> 130

즉, 인자로 전달한 경우, 같은 객체를 가리키는 글로벌 변수 global_level과 매개변수 value가 존재한다. 이때, 매개변수인 value의 값을 변경하는 것은 global_level에는 영향을 주지 않는다.

global키워드의 경우 둘은 같은 변수이다.

람다함수

한 줄 짜리 표현식으로 이루어지며, 반복문이나 조건문 등의 제어문은 포함될 수 없다. 또한 함수이지만 정의/호출이 나누어져 있지 않으며 표현식 자체가 바로 호출된다.

lambda <매개변수> : <표현식>
# 함수의 정의
>>> def multi(x):
...   return x*x
...

# 함수의 호출
>>> multi(5)
25

# 람다함수의 사용
>>> (lambda x : x*x)(5)
25

# 람다함수를 사용해 함수 정의
>>> f = lambda x : x*x
>>> f(5)
25
def multi(x):
  return x*x


def get_one_value_and_execute_function(value, f):
  return f(value)

get_one_value_and_execute_function(5, multi)
>>> 25

# 위의 함수는
get_one_value_and_execute_function(5, lambda x: x*x)
# 같은 역할을 한다.

클로져 (closure)

함수가 정의된 환경을 말하며, 파이썬 파일이 여러개일 경우 각 파일은 하나의 모듈 역할을 하고, 각 모듈은 독립적인 환경을 가진다. 독립된 환경은 각자의 영역을 전역 영역으로 사용한다.

level = 0

def outer():
  level = 50

  def inner():
    nonlocal level
    level += 30
    print(level)

  return inner
  # inner 함수 자체를 return

f = outer()

f() = 53
f() = 56
f() = 59
...
...
f2 = outer()

f2() = 53
f2() = 56
f2() = 59
...
...

type(f)
>>> function

print(f)
>>> <function outer.<locals>.inner at 0x110da9730>

데코레이터 (decorator)

함수를 받아 다른 함수를 반환하는 함수, 예로들면 기존에 존재하던 함수를 바꾸지 않고 전달된 인자를 보기위한 디버깅 print 함수를 추가한다던가 하는 기능을 할 수 있다.

  1. 기능을 추가할 함수를 인자로 받음
  2. 데코레이터 자체에 추가할 기능을 함수로 정의
  3. 인자로 받은 함수를 데코레이터 내부에서 적절히 호출
  4. 위 2가지를 행하는 내부 함수를 반환
def print_arguments(original_function):

  def decorated_function(*args, **kwargs):
    print(f'args: {args}')
    print(f'kwargs: {kwargs}')
    return original_function(*args, **kwargs)

  return decorated_function

def square(x):
  return x**2

square(5)
>>> 25

@print_arguments
def double(x):
  return x*2

double(2)
>>> args:(2,)
    kwargs:{}
    4

def half(x):
  print('input : {}'.format(x))
  return x//2

half(8)
>>> input : 8
    4

제너레이터 (generator)

제터레이터는 함수는 파이썬의 시퀀스 데이터를 생성하는 데 사용된다. 실제 시퀀스 데이터와 다른점은, 시퀀스 전체를 가지고 있는 것이 아니라 시퀀스 데이터를 생성하기 위한 어떠한 루틴만을 가지고 있는 것이다.

이 방식을 택했을 때의 장점은, 전체 크기만큼의 메모리를 가지고 있는 시퀀스 데이터와는 달리 메모리를 적게 사용할 수 있다.

제너레이터는 마지막으로 호출한 위치(항목)을 기억하고 있으며, 한 번 순회할 때 마다 그 다음 값을 반환한다.

제너테이터는 함수를 통해 만들어지고, 함수 내부의 반복문에서 yield키워드를 사용하면 제너레이터가 된다.

def range_gen(num):
  i = 0
  while i < num:
    yield i
    i +=1

type(range_gen)
>>> function

g = range_gen(10)
type(g)
>>> generator

next(g)
>>> StopIteration: # 오류발생
for item in g:
  print(item)

0
1
...
9

저기서의 g는 0~9까지의 숫자를 가지고 있는게 아니라, 0~9까지 도는 루틴만을 가지고 있는 것이다.

한번 사용하면 다시는 돌지 않아서 generator를 다시 돌려주고 실행해야 한다.

실습

1.매개변수로 문자열을 받고, 해당 문자열이 red면 apple을, yellow면 banana를, green이면 melon을, 어떤 경우도 아닐 경우 I don’t know를 리턴하는 함수를 정의하고, 사용하여 result변수에 결과를 할당하고 print해본다.

def print_fruitname(a):
  if a == 'red':
    return 'apple'
  elif a == 'yellow':
    return 'banana'
  elif a == 'green':
    return 'melon'
  else:
    return 'I don't know'

fruit_dict = {
    'red':'apple',
    'yellow':'banana',
    'green':'melon',
}

def what_fruit(color):
    return fruit_dict.get(color,'I don\'t konw')

2.1번에서 작성한 함수에 docstring을 작성하여 함수에 대한 설명을 달아보고, help(함수명)으로 해당 설명을 출력해본다.

def print_fruitname(a):
  '이 함수는 과일의 색을 넣으면 해당 과일의 정보를 알려줍니다.'
  if a == 'red':
    return 'apple'
  elif a == 'yellow':
    return 'banana'
  elif a == 'green':
    return 'melon'
  else:
    return 'I don't know'

help(print_fruitname)

3.한 개 또는 두 개의 숫자 인자를 전달받아, 하나가 오면 제곱, 두개를 받으면 두 수의 곱을 반환해주는 함수를 정의하고 사용해본다.

def print_number(a,b=None):
  if b is None:
    return a ** 2
  else:
    return a*b

# 더 간단한 방법
def square_or_multi_default_parameter(a, b=None):
  if b:
    return a ** 2
  return (a*b)

# 더더 간단한 방법
def square_or_multi_default_parameter(a, b=None):
    return a*b if b else a**2

# 혹은 위치인자 묶음을 통해서 구하는 방법
def squeare_of_multi_positional_args(*args): #위치 인자 묶음 사용
    if len(args) == 2:
        return args[0] * args[1]
    return args[0] **2

# 더 사람이 이해하기 쉽게 표현해보자면
def squeare_of_multi_positional_args(*args): #위치 인자 묶음 사용
    args_length = len(args)
    # if args_length > 2 or args_length <1:
    if not (args_length == 1 or args_length ==2):
        raise ValueError('숫자는 1개 또는 2개로 입력해주세요')
    if len(args) == 2:
        return args[0] * args[1]
    return args[0] **2


# 튜플, 언패킹으로 푸는 방법
def squeare_of_multi_positional_args(*args):
    if len(args) == 1:
        # 튜플 언패킹 시, 좌-우변 모두 'tuple'형태로 만들어야 한다. (',' 반드시 있어야 한다.)
        args1, = args
        return args1 ** 2
    elif len(args2) == 2:
        arg1, arg2 == args
        return args1 * args2

print_number(4)
>>> 16

print_number(4,6)
>>> 24

4.두 개의 숫자를 인자로 받아 합과 차를 튜플을 이용해 동시에 반환하는 함수를 정의하고 사용해본다.

def print_number(a,b):
  return (a+b, absa-b)


print_number(9,5)
>>> (14,4)

5.위치인자 묶음을 매개변수로 가지며, 위치인자가 몇 개 전달되었는지를 print하고 개수를 리턴해주는 함수를 정의하고 사용해본다.

def print_number(*args):
  print('args의 갯수 : {}'.format(args))
  return len(args)


print_number(3,4,5,6,7)
>>> 'args의 갯수 : 5'
    5

6.람다함수와 리스트 컴프리헨션을 사용해 한 줄로 구구단의 결과를 갖는 리스트를 생성해본다.

[(lambda x,y : '{} x {} = {}'.format(x,y,x*y)) (x,y) for x in range(2,10) for y in range(1,10)]

python 함수 - args, kwargs, docstring

|

패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
이 포스팅에서는 python 함수에 대해 설명합니다.


함수

매번 같은 코드를 계속 써야한다면 번거로우니, 반복적인 작업을 하는 코드를 재사용이 가능하게 정의해 놓은 함수를 만든다.

def 함수명(매개변수[parameters]):
	동작

함수의 정의, 실행

# 실행 시 'call func'를 print하는 함수 정의
>>> def func():
...   print('call func')
...

# 함수 자체는 function객체를 참조하는 변수
>>> func
<function func at 0x10dabf378>

# 함수를 실행시키기 위해 () 사용
>>> func()
call func

리턴값이 있는 함수 정의

>>> def return_true():
...   return True
...
>>> return_true()
True
def add(a,b):
    return a+b

add(5,7)

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

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

>>> def print_arguments(something):
...   print(something)
...
>>> print_arguments('ABC')
ABC

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

매개변수는 함수 내부에서 함수에게 전달되어 온 변수 즉, 함수를 정의할 때 들어오는 변수를 의미하고, 인자는 함수를 호출할 때 전달하는 변수 즉, 함수를 정의하고 나서 함수를 사용하는 변수를 의미한다.

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

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

함수가 리턴값을 가지지 않는 경우는 none객체를 얻는다.

위치 인자와 키워드 인자

위치인자(positional arguments)

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

>>> def student(name, age, gender):
...   return {'name': name, 'age': age, 'gender': gender}
...
>>> student('hanyeong.lee', 31, 'male')
{'name': 'hanyeong.lee', 'age': 31, 'gender': 'male'}

키워드 인자(keyword arguments)

매개변수의 이름을 지정하여 인자로 전달하여 사용하는 경우

>>> student(age=31, name='hanyeong.lee', gender='male')
{'name': 'hanyeong.lee', 'age': 31, 'gender': 'male'}

위치인자와 키워드 인자를 동시에 쓴다면, 위치인자가 먼저 와야 한다.

def students(name, age, gender):
    return{
        'name':name,
        'age':age,
        'gender': gender
    }

students('jihye',gender='female',age=25)

기본 매개변수값 지정

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

>>> def student(name, age, gender, cls='WPS'):
...   return {'name': name, 'age': age, 'gender': gender, 'class': cls}
...
>>> student('hanyeong.lee', 31, 'male')
{'name': 'hanyeong.lee', 'age': 31, 'gender': 'male', 'class': 'WPS'}

기본 매개변수값의 정의 시정

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

def return_list(value, result=[]):
  result.append(value)
  return result

# value라는 매개변수에 전달된 값을 새로운 리스트를 생성하는 result에 해당 값을 추가한 후 return해주는 함수

# 기존 리스트에 추가하는 형태로 사용

return_list('apple')

>>> ['apple']

return_list('banana')
>>> ['apple', 'banana']
# 값이 추가된 상태에서 다시 정의가 된다.
# 그렇기 때문에 위 ['apple']과 같은 메모리 상에 있다.
id(return_list(123123))
id(return_list(456456))

>>>4572752008

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

def return_list(value, result=None):
  if result is None:
    result = []
  result.append(value)
  return result

return_list('apple')
>>> ['apple']

return_list('banana')
>>> ['banana']

잠깐 =와 ==에 대해 이야기해보자면,

list1 = []
list1=list2

list1 == list2
>>> True

////////////////

var1 = 123123123123
var2 = 123123123123

var1 == var2
>>> True

# 이때

id(var1)
>>> 4572156880

id(var2)
>>> 4572159120

var1 is var2
>>> False

a = 100
b = 100

a == b
>>> True

a is b
>>> True
# 이미 작은 숫자들은 파이썬 내부적으로 같게 나오도록 적용되어 있다.

a = 123123123123
b = 123123123123

a is b
>>> False

a = '123123123123'
b = '123123123123'

a is b
>>> True

어느정도의 최적화하느냐에 따라 성능상 이득이냐를 따져보았을 때, 같은 값을 가진 객체라고 해서 같은 메모리를 가질 것이라는 법칙은 없다.

더 나아가 True, False, None 이들 또한 객체라고 부르기에

id(True)
>>> 4535273808

id(False)
>>> 4535273840

id(None)
>>> 4535374312

각자에 해당하는 id 값이 존재한다.

def return_value(abc):
  print(abc)

return_value(3)
>>> 3

이때

3 is return_value(3)
>>> 3 False
id(return_value(3))
>>> 4341563880

id(3)
>>> 4341846608

위치인자 묶음

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

우리가 따로 위치인자의 수를 정해주지 않았을 때 사용

def print_args(*args):
  print(args)

print_args(3,5,124,'hello')
>>> (3,5,124,'hello')
# 튜플 형식으로 출력된다.

키워드 인자 묶음

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

def print_kwargs(**kwargs):
  print(kwargs)

print_kwargs(a='apple', b='banana', hi='123123123123')
>>> {'a':'apple', 'b':'banana', 'hi':'123123123123'}

docstring

함수를 정의한 문서 역할을 한다.

함수 정의 후, 몸체의 시작부분에 문자열로 작성하며, 여러줄로도 작성가능하다.

def print_args(*args):
  'args로 전달된 위치인자들을 출력해준다.'
  print(args)

help(print_args)
>>> Help on function print_args in module __main__:

    print_args(*args)
      args로 전달된 위치인자들을 출력해준다.

함수를 인자로 전달

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

  • ‘call func’를 출력하는 함수를 정의하고, 함수를 인자로 받아 실행하는 함수를 정의하여 첫 번째에 정의한 함수를 인자로 전달해 실행해보자.
def print_call():
  print(call func)

def print_execute(f):
  f()

print_execute(print_call)

내부 함수

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

  • 문자열 인자를 하나 전달받는 함수를 만들고, 해당 함수 내부에 전달받은 문자열을 대문자화해서 리턴해주는 내부 함수를 구현한다. 문자열을 전달받는 함수는 내부함수를 실행한 결과를 리턴하도록 한다.
def execute(a):
  def upper(b):
    return b.upper()
  return upper(a)

execute('asdasd')
>>> 'ASDASD'

python 제어문(if), list-comprehension

|

패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
이 포스팅에서는 python 제어문에 대해 설명합니다.


제어문 (if, else, elif)

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

# 기본적으로 if와 else는 이런 방식으로 쓰이고
if 조건:
	조건이 참일 경우
else:
	조건이 거짓일 경우

# 아래와 같이 if-else구문내 또 if-else구문이 중첩되어 사용되는 경우
if 조건1:
	조건1이 참일 경우
else:
	조건1이 거짓일 경우

	if 조건2:
		조건1은 거짓이나, 조건2는 참일 경우
	else:
		조건1,2가 모두 거짓일 경우

# 아래와 같이 elif를 사용하여 쓸 수 있다.
if 조건1:
	조건1이 참일 경우
elif 조건2:
	조건1은 거짓이나, 조건2가 참일 경우
else:
	조건1,2가 모두 거짓일 경우

조건 표현식

참일경우 if 조건식 else 거짓일 경우
  • is_holidayTrue또는 False값을 할당한 후, if문과 조건표현식을 사용해서 각각 ‘Good’과 ‘Bad’를 출력하는 코드를 짜본다.
is_holiday = False

# if문을 사용한 것
if is_holiday:
  print('good')
else:
  print('bad')

# 조건표현식을 사용한 것
'good' if is_holiday else 'bad'

중첩 조건표현식

# 조건이 2개일 경우
조건1이 참일경우 if 조건1 else 조건1은 거짓이나 조건2가 참일경우 if 조건2 else 조건1,2가 모두 거짓일 경우
  • vacation에 1에서 10중 아무 값이나 할당 후, if, elif, else문과 중첩 조건표현식을 사용해서 각각 vacation이 7이상이면 ‘Good’, 5이상이면 ‘Normal’, 그 이하면 ‘Bad’를 출력하는 코드를 짜본다.
vacition = 8

# if, elif, else를 사용한 것
if vacation >= 7 :
  pring('good')
elif vacation >= 5 :
  print('nomarl')
else:
  print('bad')

# 중첩 조건표현식을 사용한 것
'good' if vacation >=7 else 'normal' if vacation >=5 else 'bad'

for문 (조건에 따른 순회)

기본 형태

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

중첩

for문 안에 for문을 사용할 수 있다.

for 항목1 in iterable객체1:
  iterable객체1을 순회하며 실행할 코드
  for 항목2 in iterable객체2:
    iterable객체1 내부에서 새로운 iterable객체2를 순회하며 실행할 코드

중단하기 (break)

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

for 항목 in iterable객체:
  (반복문을 중단하고 싶을때)break

위와 같이 중간(break)를 확인하고 싶을 때 else를 사용한다.

for 항목 in iterable객체:
  pass
else:
  break가 한 번도 호출되지 않았을 경우의 코드

만약 for문이 break됐다면 else문이 실행됐을 것이다.

건너뛰기 (continue)

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

for 항목 in iterable객체:
  (현재의 반복을 중간에 그만두고 다음 반복으로 건너뛰고 싶을 때)continue

숫자 시퀀스 생성 (range)

range()함수는 특정 범위의 숫자 스트림 데이터를 반환한다.

range(start, stop, step)

>>> for x in range(0, 10):
# 0 부터 10까지 순회하라
...   print(x)
...
0
1
2
3
4
5
6
7
8
9

while문 (반복문)

if문과 유사하나, while문 뒤의 조건이 참일 경우 계속해서 반복한다.

while 조건:
  조건이 참일경우 실행
  조건이 거짓이 될 경우까지 계속해서 반복

예로 들어

>>> count = 0
>>> while count < 10:
...   print(count)
...   count += 1
...
0
1
2
3
4
5
6
7
8
9

컴프리헨션 (comprehension)

함축 또는 내포

일반적인 for문을 사용하는 때보다 훨씬 간편하다.

그러나 조건이 2개 이상이 되는 경우에는 일반적인 for문을 사용하는게 옳다.

리스트 컴프리헨션

[표현식 for 항목 in iterable객체]
  • [1,2,3,4,5]를 만드는 방법
# 리스트 컴프리헨션을 사용한 경우
[i for i in range(1, 6)]

# range와 for문을 사용한 경우
for i in range(1, 6):
  print(i)
  • 만약 각 i에 2배의 값을 할당하고 싶다면?
[i*2 for i in range(1,6)]
  • 만약 1~5중 짝수만 해당하는 리스트를 만들고 싶다면?
[i for i in range(1,6) if i % 2==0]

리스트 컴프리헨션의 중첩

for color in colors:
  for fruit in fruits:

[(color, fruit) for color in colors for fruit in fruits]

셋 컴프리헨션

{표현식 for 표현식 in iterable객체}

실습

1.for문을 2개 중첩하여 (0,0), (0,1), (0,2), (0,3), (1,0), (1,1)….. (6,3)까지 출력되는 반복문을 구현한다.

for i in range(0,8):
  for j in range(0,4):
    print((i,j))

2.리스트 컴프리헨션을 중첩하여 위 결과를 갖는 리스트를 생성한다

[(i,j) for i in range(0,7) for j in range(0,4)]

3.1, 2번의 반복문에서 1번은 튜플의 첫 번째 항목이 짝수일때만 출력하도록, 2번은 첫 번째 항목이 짝수일때만 리스트의 원소로 추가한다.

for i in range(0,8):
  for j in range(0,4):
    if i % 2 == 0:
      print((i,j))

[(i,j) for i in range(0,7) for j in range(0,4) if i % 2 ==0]

4.1000에서 2000까지의 숫자 중, 홀수의 합을 구해본다.

result = 0
for i in range(1001, 2001, 2):
    result += i

print(result)

5.리스트 컴프리헨션을 사용하여 구구단 결과를 갖는 리스트를 만들고, 해당 리스트를 for문을 사용해 구구단 형태로 나오도록 출력해본다. 각 단마다 한 번 더 줄바꿈을 넣어준다.

[(i*j) for i in range(1, 10) for j in range(1, 10)]

for i in range(1, 10):
  for j in range(1, 10):
    print(i*j)

6.1에서 99까지의 정수 중, 7의 배수이거나 9의 배수인 정수인 리스트를 생성한다. 단, 7의 배수이며 9의 배수인 수는 한 번만 추가되어야 한다.

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

python dictionary, set

|

패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
이 포스팅에서는 python 딕셔너리와 셋에 대해 설명합니다.


딕셔너리 (dictionary)

key-value 형태로 항목을 가지는 자료구조

딕셔너리 생성

>>> empty_dict1 = {}
>>> empty_dict2 = dict()
>>> champion_dict = {
... 'Lux': 'the Lady of Luminosity',
... 'Ahri': 'the Nine-Tailed Fox',
... 'Ezreal': 'the Prodigal Explorer',
... 'Teemo': 'the Swift Scout',
... }

형변환

>>> sample = [[1,2], [3,4], [5,6]]
>>> dict(sample)
{1: 2, 3: 4, 5: 6}

항목 찾기/추가/변경

>>> champion_dict['Lux']
'the Lady of Luminosity'
>>> champion_dict['Sona'] = 'Maven of the Strings'
>>> champion_dict['Lux'] = 'Demacia'

결합 (update)

>>> com_dict = {}
>>> com_dict.update(champion_dict)
>>> com_dict.update(item_dict)
>>> com_dict

삭제 (del)

>>> del com_dict['Doran\'s Blade']

이외에도 전체삭제 clear, in으로 True, False값을 반환하는 키 값을 검색해볼 수 있다.

keys()는 모든 키를 얻고, values()는 모든 값을 얻고, items()는 모든 키와 값을 튜플로 반환하여 얻을 수 있다.

셋 (set)

셋은 키만 있는 딕셔너리와 같으며, 중복된 값이 존재할 수 없다.

셋 생성

>>> empty_set = set()
>>> champions = {'lux', 'ahri', 'ezreal'}

형변환

>>> set('ezreal')
{'e', 'z', 'a', 'l', 'r'}
# 중복된 값은 하나로 나타난다.

>>> set(champion_dict)
{'Ahri', 'Lux', 'Ezreal', 'Sona', 'Teemo'}
# 딕셔너리는 키만 남는다.

집합연산

연산자 설명
파이프라인 합집합(union)
& 교집합(intersection)
- 차집합(difference)
^ 대칭차집합(exclusive)

실습

1.apple사과, banana바나나, cherry체리의 key-value를 갖는 fruits라는 이름의 사전을 만든다.

fruits = { 'apple': '사과', 'banana': '바나나', 'cherry':'체리'}

2.fruitsSet으로 만들어 fruits_set변수에 할당한다.

fruits_set = set(fruits)

3.fruits_setdurian이 존재하는지 확인한다.

'durian' in fruits_set
>>> False

4.fruits사전에서 apple키에 해당하는 값을 출력한다.

fruits['apple']
>>> '사과'

5.girlgroups라는 이름의 2차원 사전을 만들고 출력해본다.

  • 최상위 키는 girlsdayredvelvet이 있으며, 각각 자식으로 사전을 갖는다.

  • girlsday키의 자식사전에는 koreanmembers키가 있으며, 각각 '걸스데이'라는 문자열과 ['민아', '혜리', '소진', '유라']라는 리스트를 갖는다.

  • redvelvet키의 자식사전에도 koreanmembers키가 있으며, 각각 '레드벨벳'이라는 문자열과 ['아이린', '슬기', '웬디', '조이', '예리']라는 리스트를 갖는다.

girlgroups = {
  'girlsday': {
    'korean': '걸스데이',
    'members': '민아, 혜리, 소진, 유라'.split(',')
  },
  'redvelvet': {
    'korean': '레드벨벳',
    'members': '아이린, 슬기, 웬디, 조이, 예리'.split(',')
  }
}

6.girlgroups사전의 최상위 키 목록을 출력해본다.

girlgroups.keys()
>>> dict_keys(['girlsday', 'redvelvet'])

7.girlgroups['girlsday']의 모든 키를 출력해본다.

girlgroups['girlsday'].keys()
>>> dict_keys(['korean', 'members'])

8.girlgroups['redvelvet']의 모든 값을 출력해본다.

girlgroups['redvelvet'].values()
>>> dict_values(['레드벨벳', ['아이린', ' 슬기', ' 웬디', ' 조이', ' 예리']])

9.x = {1,2,3,4,5,6,8}, y={4,5,6,9,10,11}, z={4,6,8,9,7,10,12}일 때,

  • x,y,z의 교집합에 해당하는 숫자는?
x&y&z
>>> {4, 6}
  • y,z의 교집합이며 x에는 속하지 않는 숫자는?
(y&z)-x
>>> {9, 10}
  • x에만 속하고 y,z에는 속하지 않는 숫자는?
x-(y|z)
>>> {1, 2, 3}

python 시퀀스(list, tuple)

|

패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
이 포스팅에서는 python 시퀀스에 대해 설명합니다.

주요 용어 : index slice append extend insert del remove pop count


시퀀스타입

파이썬에 내장된 시퀀스 타입에는 문자열, 리스트, 튜플이 있다.

문자열은 인용부호(‘’,”“)를 사용하며, 리스트는 대괄호[], 튜플은 괄호()를 사용하여 나타낸다.

리스트

>>> empty_list1 = []
>>> empty_list2 = list()
>>> sample_list = ['a', 'b', 'c', 'd']
>>> sample_list2 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

인덱스 연산

  • sample_list2를 이용해서 실습. 5월, 7월을 인덱스연산을 통해 추출해보자.
sample_list2[4]
sample_list2[6]

내부항목 변경

  • sample_list를 이용, 3번째 요소인 ‘c’를 대문자 ‘C’로 바꿔본다.
sample_list[2] = C

슬라이스 연산

  • sample_list2를 이용, 1월부터 3월씩 건너뛴 결과를 quarters에 할당
qurters = sample_list2[::3]
  • sample_list2를 이용, 끝에서부터 3번째 요소까지를 last_three에 할당
last_three = sample_list2[:-4:-1]
  • sample_list2를 이용, 끝에서부터 처음까지(거꾸로) 2월씩 건너뛴 결과를 reverse_two_steps에 할당
reverse_two_steps = sample_list2[::-2]

리스트 항목 추가 (append)

>>> sample_list.append('e')
>>> sample_list
['a', 'b', 'c', 'd', 'e']

리스트 병합 (extend, +=)

>>> fruits = ['apple', 'banana', 'melon']
>>> colors = ['red', 'green', 'blue']
>>> fruits.extend(colors)
>>> fruits
['apple', 'banana', 'melon', 'red', 'green', 'blue']
>>> fruits = ['apple', 'banana', 'melon']
>>> colors = ['red', 'green', 'blue']
>>> fruits += colors
>>> fruits
['apple', 'banana', 'melon', 'red', 'green', 'blue']

extend대신 append를 사용하면?

fruits.append(color) 리스트 안에 리스트를 추가하는 모습이 나온다.

['apple', 'banana', 'melon', ['red', 'green', 'blue']]

특정 위치에 리스트 항목 추가 (insert)

  • fruits리스트의 1번째 위치에 ‘mango’를 추가해보자
fruits.insert(1, 'mango')
  • fruits리스트의 100번째 위치에 ‘pineapple’을 추가해보자
fruits.insert(100, 'pineapple')

특정 위치 리스트 항목 삭제 (del)

del fruits[0]

값으로 리스트 항목 삭제 (remove)

fruits.remove('mango')

리스트 항목 추출 후 삭제 (pop)

fruits.pop()
fruits.pop(-3)

값으로 리스트 항목 찾기 (index)

>>> fruits.index('apple')
0

존재여부 확인 (in)

'apple' in fruits

값은 True, False로 나온다.

값 세기 (count)

>>> fruits.append('red')
>>> fruits.append('red')
>>> fruits.count('red')
3

정렬하기 (sort, sorted)

  • sort는 리스트 자체를 정렬한다.
  • sorted는 리스트의 정렬 복사본을 반환
def number(n):
  # number라는 함수는 매개변수 n의 1번째 요소를 리턴해준다.
  return n[1]

random = [(1,2,3), (2,3,4), (1,4,2), (2,1,3),(2,5,6)]
# random이라는 변수를 함수 number에 따라 정렬한다.
random.sort(key=number)
print(random)
>>> [(2, 1, 3), (1, 2, 3), (2, 3, 4), (1, 4, 2), (2, 5, 6)]

튜플 (tuple)

리스트와 비슷하나, 정의 후 내부 항목의 삭제나 수정이 불가능하다.

개발을 하다보면 변하지 않아야 하는 값들이 있는데, 그런 값들은 튜플에 넣어주면 유용하게 쓸 수 있다.

실습

1.문자열 ‘Fastcampus’를 리스트, 튜플 타입으로 형변환하여 새 변수에 할당한다.

li = ['Fastcampus,']
tu = ('Fastcampus,')