[멋사 AI 웹 서비스 스쿨 TIL] 26일차 회고

1. 함수

반복적으로 사용되는 코드 묶음이에요. 다른 언어의 함수와 동일한 역할을 수행해요. 당연히 사용자 정의 함수가 있고 python이 기본으로 제공하는 내장함수가 있어요. 함수의 이름은 가독성을 높이기 위해서 snake case를 사용해서 표현해요. 쉽게 말하면 “_”를 이용해서 소문자로 함수이름을 작성해요.

2. 사용자 정의 함수

# 함수를 정의해 보아요!
# 함수를 정의하기 위해서 사용하는 keyword는 def.
# 함수이름은 소문자로 만들고 두 단어 이상인 경우 _ 를 이용해서 연결(snake case)
# 인자는 당연히 변수명만 명시하면 되요!
# 함수 선언이 끝나는 부분에 반드시 : 을 명시해야 해요!
# 당연하 함수의 body부분은 들여쓰기(indent)를 통해서 block을 표현해야 해요!

def my_sum(a, b, c):
    return a + b + c

result = my_sum(1, 2, 3)
# result = my_sum(1, 2)  # Error 인자의 개수를 맞춰야 해요!

print(f'숫자의 합은 : {result}')

#########################################

# 여러 개의 인자가 함수로 전달될 경우 
# 함수에서는 변수 1개로 전달된 모든 인자를 받을 수 있어요!

def my_sum(a, b, c, d, e, f, g, h, i):
    return a + b + c + d + e + f + g + h + i

result = my_sum(1, 2, 3, 4, 5, 6, 7, 8, 9)

print(f'1부터 9까지의 합은 : {result}')

# *를 이용해서 다수의 인자를 받을 수 있는 가변인자를 지정
# 이런 경우 전달된 데이터가 tuple로 만들어져서 전달되요!
def my_sum(*args):    
    print(args)  # (1, 2, 3, 4, 5, 6, 7, 8, 9)
    mySum = 0
    for i in args:
        mySum += i

    return mySum

result = my_sum(1, 2, 3, 4, 5, 6, 7, 8, 9)

print(f'1부터 9까지의 합은 : {result}')

# 간혹 python의 함수는 리턴값을 여러 개 사용할 수 있어요!
# 실제로는 아니예요! => tuple을 리턴하는 경우 ()를 생략해서 그렇게 보이는 거예요!

def multi_return(a, b):
    result1 = a + b
    result2 = a * b

    return result1, result2   # 마치 값 2개를 리턴하는 것처럼 보여요!
                              # tuple로 리턴하는 거예요!

x1, x2 = multi_return(10, 20)
print(x1, x2)  # 30 200

# 함수의 또 다른 특징
# default parameter라고 불리는 parameter가 있을 수 있어요!
# 당연히 default parameter는 항상 parameter의 맨 마지막에만 등장할 수 있어요!
def default_param(a, b, c=True):
    data = a + b
    if data > 10:
        return True
    else:
        return False

result1 = default_param(5, 10)
print(result1)
result2 = default_param(5, 10, False)

2.1 call-by-value vs. call-by-reference

함수를 호출할 때 인자의 값을 복사해서 함수에게 전달하는 개념을 call-by-value라고 하고, 함수를 호출할 때 인자의 주소값을 넘겨줘서 함수에게 전달하는 개념을 call-by-reference라고 해요.

def modify_value(x):
    x = x + 10
    print(f'함수 내부의 x값 : {x}')  # 15

num = 5
modify_value(num)  # 5라는 값을 함수에 복사해줘요!
print(f'함수 외부의 num값 : {num}')  # 5

#############################################

# 아래처럼 동작하는 방식을 우리는 call-by-reference라고 해요!
# 대표적으로 list, dict, set 이놈들은 call-by-reference로 동작하고
# 나머지 데이터들은 모두 call-by-value로 동작해요!

def modify_list(lst):
    lst.append(4)  # [1, 2, 3, 4]
    print(f'함수 내부에서 list의 값은 {lst}')  # [1, 2, 3, 4]

my_list = [1, 2, 3]
modify_list(my_list)  # list의 메모리 주소값을 넘겨줘요!
print(f'함수 외부에서 list의 값은 {my_list}')  # [1, 2, 3] > [1, 2, 3, 4]

2.2 global scope와 local scope

# python은 global scope와 local scope가 자동으로
# 연결되지 않아요!

# 그러면 함수내부(local scope)에서는 
# 함수 외부(global scope)에서 선언한
# 변수를 사용할 수 없나요? => global 이라는 keyword를 이용해야 해요!

# global scope
tmp = 100

def my_func(x):
    global tmp     # global scope에 있는 변수를 참조하겠다고 알려줘야 해요! 
    # local scope
    tmp = tmp + x  # tmp라는 변수를 사용할 수 없어요!

    return tmp

print(my_func(200))

파이썬의 함수에 대해서 알아야 할 사항을 몇 가지 정리해보면:

  • 함수 정의하는 방법
    def 라는 keyword를 이용해요.
    함수의 선언 뒤에 반드시 : 기호를 이용해야 해요!
    함수의 body는 indent(들여쓰기)를 이용해서 표현해야 해요! {} 를 사용하지 않아요!
    만약 함수의 body에 어떠한 작업도 할 게 없으면 비워두는 게 아니라 pass라는 keyword를
    사용해야 오류가 발생하지 않아요!
  • 함수 호출 시 인자의 개수를 맞춰서 호출해야 호출이 가능해요!
  • 함수 호출 시 전달하는 인자를 tuple로 함수 내부에서 받아서 사용할 수 있어요! ⇒ *
  • 함수의 결과값 return 시 tuple을 이용하면 마치 여러 개의 값을 리턴하는 듯한 효과를 줄 수 있어요!
  • 함수를 사용할 때 default parameter를 이용해서 전달되지 않은 parameter를 사용할 수 있어요!
  • call-by-value vs call-by-reference
  • global scope와 local scope가 자동으로 연결되지 않아요! ⇒ global keyword를 이용하면 상위 scope를 이용할 수 있어요!

3. 내장 함수

python이 제공하는 내장함수는 아주아주 많아요! 그 많은 걸 다 외울 수는 없어요! 하지만 그 중 많이 사용되는 함수는 알아두는 게 좋아요!


a = 100                 # int()
b = 3.141592            # float()
c = [1, 2, 3, 4, 5, 6]  # list()
d = (1, 2, 3, 4, 5)     # tuple()
e = range(10)           # range()
f = '이것은 소리없는 아우성'   # str()
g = { "name": "홍길동", "age" : 20 }   # dict()
h = { 100, 200, 300 }   # set()
i = True                # bool() 

# 1. 기본 함수
print(len(h))  # 길이, 개수를 알려주는 대표적인 python 함수
print(type(f)) # <class 'str'>  type()은 객체에 대한 class를 알려줘요!
print(int(b)) # 3  클래스 이름으로 되어 있는 함수가 있어요. 각 함수는
              # 데이터를 해당 타입으로 변형하기 위해서 사용.
print(tuple(c)) # (1, 2, 3, 4, 5, 6)

# 2. enumerate() 함수 : 순서가 있는 자료형과 같이 사용되요!
#    index와 요소를 결합해서 enumerate 객체를 생성해요!
#    사용하려면 이 객체를 list나 tuple로 변경해서 사용하면 되요!

result = enumerate(['이것은', '소리없는', '아우성!'])
print(result) # <enumerate object at 0x7ec0b0382480> ??
print(list(result)) # [(0, '이것은'), (1, '소리없는'), (2, '아우성!')]

for idx, item in enumerate(['이것은', '소리없는', '아우성!']):
    print(idx, item)

# 3. map()
# map() 반복 가능한 객체(list, tuple)의 각 요소에 특정 함수를 적용한 결과를 담는
# map 객체를 반환하는 내장 함수.

# map(function, iterable)

def square(x):
    return x * x

numbers = [1, 2, 3, 4, 5]

square_map = map(square, numbers)
print(square_map) # <map object at 0x7ec0b1f2fa00>
print(list(square_map)) # [1, 4, 9, 16, 25]

letters = ['a', 'b', 'c']
upper_letters = map(str.upper, letters)
print(list(upper_letters)) # ['A', 'B', 'C']

# max() , min() : 최대 최소값을 구하는 함수
print(max([1, 100, 20, 30, 5])) # 100
print(min([1, 100, 20, 30, 5])) # 1

# 정렬하는 함수 => sorted (오름차순으로 정렬하는 함수)
a = [4, 7, 9, 2, 3, 6]
result = sorted(a)
result1 = sorted(a, reverse=True)
print(result) # [2, 3, 4, 6, 7, 9]
print(result1) # [9, 7, 6, 4, 3, 2]

a = [4, 7, 9, 2, 3, 6]
list_sort = a.sort()
print(list_sort) # None => list의 sort method는 list 자체를 변환해요. 결과를 리턴하지 않아요!
print(a) # [2, 3, 4, 6, 7, 9]

# zip() : 동일한 개수로 이루어진 자료형을 묶어주는 역할. tuple로 묶여요!
a = [1, 2, 3, 4]
b = ['a', 'b', 'c']

c = list(zip(a, b))
print(c) # [(1, 'a'), (2, 'b'), (3, 'c')]

4. lambda

lambda(람다)는 한 줄로 함수를 정의하는 방법이에요. 람다는 함수의 이름을 명시하지 않아요! anonymous function이라고 하기도 해요. 이름이 없기 때문에 일반적으로 변수에 할당해서 사용해요. 람다는 일반 함수와는 살짝 달라요. 왜냐하면 함수는 아니기 때문에 그래요. 람다 표현식이라고 하는데 함수가 아니라 표현식이에요!

# 람다함수 활용

# 1. 두 수의 합을 구하는 람다함수를 작성한 후 사용해 보세요!

sum = lambda x, y: x + y

print(sum(5, 9)) # 14

# 2. list의 모든 요소를 제곱해서 출력하려고 해요. 어떻게 구현하면 좋을까요?
#    람다를 이용해서 구현해 보세요!
numbers = [1, 2, 3, 4, 5]

print(list(map(lambda x: x*x, numbers))) # [1, 4, 9, 16, 25]

# 3. filter라는 함수도 있는데 이 함수는 데이터를 말 그대로 걸러내는 역할을 하는 함수.
#    리스트에서 짝수만 출력할 거예요!

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(list(filter(lambda x: x % 2 == 0, numbers)))

1. list 연습문제

# 문제 1: 리스트의 합 구하기
# 주어진 리스트의 모든 요소의 합을 구하는 함수를 작성하세요.

def sum_of_list(lst):
    pass

print(sum_of_list([1, 2, 3, 4]))  # 출력: 10

##############################################################

# 문제 2: 리스트에서 최댓값과 최솟값 구하기
# 리스트에서 최댓값과 최솟값을 구하는 함수를 작성하세요.

def max_and_min(lst):
    pass

print(max_and_min([10, 20, 4, 45, 99]))  # 출력: (99, 4)

##############################################################

# 문제 3: 리스트 뒤집기
# 주어진 리스트를 역순으로 뒤집는 함수를 작성하세요. 
# (직접 구현해 보세요, list.reverse() 사용하지 말 것)

def reverse_list(lst):
    pass

print(reverse_list([1, 2, 3, 4]))  # 출력: [4, 3, 2, 1]

##############################################################

# 문제 4: 리스트 중복 제거
# 리스트에서 중복된 요소를 제거하고, 중복이 제거된 리스트를 반환하는 함수를 작성하세요.

def remove_duplicates(lst):
    pass

print(remove_duplicates([1, 2, 2, 3, 4, 4, 5]))  # 출력: [1, 2, 3, 4, 5]

##############################################################

# 문제 5: 리스트 요소들의 곱 구하기
# 리스트의 모든 요소의 곱을 구하는 함수를 작성하세요.

def multiply_list(lst):
    pass

print(multiply_list([1, 2, 3, 4]))  # 출력: 24

##############################################################

# 문제 6: 리스트에서 짝수와 홀수 구분하기
# 주어진 리스트에서 짝수와 홀수를 구분하여 별도의 리스트에 저장한 뒤 반환하는 함수를 작성하세요.

def separate_even_odd(lst):
    pass

print(separate_even_odd([1, 2, 3, 4, 5, 6, 7, 8, 9]))  
# 출력: ([2, 4, 6, 8], [1, 3, 5, 7, 9])

##############################################################

# 문제 7: 리스트 요소들의 위치 교환
# 리스트의 첫 번째 요소와 마지막 요소의 위치를 바꾸는 함수를 작성하세요.

def swap_first_last(lst):
    pass

print(swap_first_last([1, 2, 3, 4, 5]))  # 출력: [5, 2, 3, 4, 1]

##############################################################

# 문제 8: 리스트에서 특정 요소의 모든 인덱스 찾기
# 리스트에서 특정 요소가 나타나는 모든 인덱스를 리스트로 반환하는 함수를 작성하세요.

def find_all_indices(lst, value):
    pass

print(find_all_indices([1, 2, 3, 2, 4, 2, 5], 2))  # 출력: [1, 3, 5]

##############################################################

# 문제 9: 리스트의 중간 요소 찾기
# 리스트의 중간에 있는 요소를 반환하는 함수를 작성하세요. 
# 리스트의 길이가 짝수일 경우 두 개의 중간 요소를 반환하세요.

def find_middle(lst):
    pass

print(find_middle([1, 2, 3, 4, 5]))  # 출력: 3
print(find_middle([1, 2, 3, 4]))     # 출력: (2, 3)

##############################################################

# 문제 10: 중첩 리스트 펼치기 (Flattening)
# 중첩된 리스트를 평평하게 만들어 단일 리스트로 반환하는 함수를 작성하세요.

def flatten(lst):
    pass

print(flatten([1, [2, 3], [4, [5, 6]], 7]))  # 출력: [1, 2, 3, 4, 5, 6, 7]

2. dict 연습문제

# 문제 1: 딕셔너리에서 값의 합 구하기
# 주어진 딕셔너리에서 모든 값의 합을 구하는 함수를 작성하세요. 
# (딕셔너리의 값은 모두 숫자라고 가정합니다.)

def sum_of_dict_values(d):
    pass

print(sum_of_dict_values({'a': 100, 'b': 200, 'c': 300}))  # 출력: 600

##############################################################

# 문제 2: 딕셔너리에서 특정 값 찾기
# 딕셔너리에서 특정 값을 가지는 첫 번째 키를 반환하는 함수를 작성하세요. 
# 값이 없는 경우 None을 반환합니다.

def find_key_by_value(d, value):
    pass

print(find_key_by_value({'a': 100, 'b': 200, 'c': 300}, 200))  # 출력: 'b'
print(find_key_by_value({'a': 100, 'b': 200, 'c': 300}, 400))  # 출력: None

##############################################################

# 문제 3: 키 값 뒤집기
# 주어진 딕셔너리에서 키와 값을 뒤집어 새로운 딕셔너리를 반환하는 
# 함수를 작성하세요. (값은 고유하다고 가정합니다.)

def invert_dict(d):
    pass

print(invert_dict({'a': 1, 'b': 2, 'c': 3}))  
# 출력: {1: 'a', 2: 'b', 3: 'c'}

##############################################################

# 문제 4: 두 딕셔너리 합치기
# 두 개의 딕셔너리를 합쳐서 새로운 딕셔너리를 반환하는 함수를 작성하세요. 
# 만약 동일한 키가 존재하면 두 값의 합을 사용하세요.

def merge_dicts(d1, d2):
    pass

print(merge_dicts({'a': 100, 'b': 200}, {'b': 300, 'c': 400}))  
# 출력: {'a': 100, 'b': 500, 'c': 400}

##############################################################

# 문제 5: 딕셔너리 정렬하기
# 주어진 딕셔너리를 값에 따라 오름차순으로 정렬된 딕셔너리를 반환하는 함수를 작성하세요.

def sort_dict_by_value(d):
    pass

print(sort_dict_by_value({'a': 3, 'b': 1, 'c': 2}))  
# 출력: {'b': 1, 'c': 2, 'a': 3}

##############################################################

# 문제 6: 중첩 딕셔너리에서 값 가져오기
# 중첩된 딕셔너리에서 특정 키의 값을 가져오는 함수를 작성하세요. 
# 키가 없으면 None을 반환합니다.

def get_nested_value(d, keys):
    pass

nested_dict = {'a': {'b': {'c': 100}}}
print(get_nested_value(nested_dict, ['a', 'b', 'c']))  # 출력: 100
print(get_nested_value(nested_dict, ['a', 'b', 'x']))  # 출력: None

##############################################################

# 문제 7: 키와 값 스왑하기
# 딕셔너리에서 키와 값을 스왑하고, 동일한 값을 가진 키들이 있을 경우 
# 리스트로 묶는 함수를 작성하세요.

def swap_keys_values(d):
    pass

print(swap_keys_values({'a': 1, 'b': 2, 'c': 1}))  # 출력: {1: ['a', 'c'], 2: 'b'}

##############################################################

# 문제 8: 딕셔너리 필터링
# 주어진 딕셔너리에서 특정 값을 가지는 키-값 쌍만 남겨 새로운 딕셔너리를 
# 반환하는 함수를 작성하세요.

def filter_dict_by_value(d, value):
    pass

print(filter_dict_by_value({'a': 100, 'b': 200, 'c': 100}, 100))  
# 출력: {'a': 100, 'c': 100}

##############################################################

# 문제 9: 두 딕셔너리의 공통 키 찾기
# 두 딕셔너리에서 공통된 key와 value를 가진 모든 키-값 쌍을 반환하는 함수를 작성하세요.

def common_keys(d1, d2):
    pass

print(common_keys({'a': 100, 'b': 200, 'c': 300}, {'b': 200, 'c': 400, 'd': 500}))  
# 출력: {'b': 200}

##############################################################

# 문제 10: 리스트의 딕셔너리로 변환
# 두 개의 리스트를 받아서 하나는 키, 다른 하나는 값으로 사용하여 딕셔너리를 
# 생성하는 함수를 작성하세요. 
# 리스트의 길이가 다르면 더 짧은 길이에 맞춰서 딕셔너리를 만드세요.

def lists_to_dict(keys, values):
    pass

keys = ['a', 'b', 'c']
values = [1, 2, 3]
print(lists_to_dict(keys, values))  # 출력: {'a': 1, 'b': 2, 'c': 3}

3. data type 연습문제

# 문제 1: 숫자 뒤집기
# 주어진 정수의 자리수를 반대로 뒤집는 함수를 작성하세요. 
# (음수도 처리해야 합니다)

def reverse_integer(n):
    pass

print(reverse_integer(12345))  # 출력: 54321
print(reverse_integer(-12345))  # 출력: -54321

##############################################################

# 문제 2: 문자열 문자 수 세기
# 주어진 문자열에서 각 문자의 발생 횟수를 세고, 이를 딕셔너리 형태로 반환하는 
# 함수를 작성하세요.

def count_characters(s):
    pass

print(count_characters("hello"))  # 출력: {'h': 1, 'e': 1, 'l': 2, 'o': 1}

##############################################################

# 문제 3: 튜플과 리스트 변환
# 튜플을 리스트로, 리스트를 튜플로 변환하는 함수를 작성하세요.

def convert_tuple_list(data):
    pass

print(convert_tuple_list((1, 2, 3)))  # 출력: [1, 2, 3]
print(convert_tuple_list([1, 2, 3]))  # 출력: (1, 2, 3)

##############################################################

# 문제 4: 집합 교집합, 합집합, 차집합
# 두 개의 리스트를 받아서 각각 교집합, 합집합, 차집합을 구하는 함수를 작성하세요.

def set_operations(list1, list2):
    pass

print(set_operations([1, 2, 3], [3, 4, 5]))  
# 출력: {'intersection': {3}, 'union': {1, 2, 3, 4, 5}, 'difference': {1, 2}}

##############################################################

# 문제 5: 리스트 중간 요소 찾기
# 주어진 리스트의 중간 요소를 반환하는 함수를 작성하세요. 
# 만약 리스트의 길이가 짝수이면, 두 개의 중간 요소를 반환하세요.

def find_middle_element(lst):
    pass

print(find_middle_element([1, 2, 3, 4, 5]))  # 출력: 3
print(find_middle_element([1, 2, 3, 4]))     # 출력: (2, 3)

##############################################################

# 문제 6: 키-값 쌍 리스트 변환
# 딕셔너리에서 키와 값을 각각 리스트로 변환하는 함수를 작성하세요.

def dict_to_lists(d):
    pass

print(dict_to_lists({'a': 1, 'b': 2, 'c': 3}))  
# 출력: (['a', 'b', 'c'], [1, 2, 3])

##############################################################

# 문제 7: 문자열에서 단어의 역순 출력
# 주어진 문자열에서 단어의 순서를 뒤집어 출력하는 함수를 작성하세요.

def reverse_words(s):
    pass

print(reverse_words("Hello World"))  # 출력: "World Hello"

##############################################################

# 문제 8: 중복 요소 제거
# 주어진 리스트에서 중복된 요소를 제거한 리스트를 반환하는 함수를 작성하세요.

def remove_duplicates(lst):
    pass

print(remove_duplicates([1, 2, 2, 3, 4, 4, 5]))  # 출력: [1, 2, 3, 4, 5]

##############################################################

# 문제 9: 모든 요소 곱하기
# 리스트 안의 모든 요소를 곱한 값을 반환하는 함수를 작성하세요.

def multiply_elements(lst):
    pass

print(multiply_elements([1, 2, 3, 4]))  # 출력: 24

##############################################################

# 문제 10: 짝수 인덱스 요소 추출
# 주어진 리스트에서 짝수 인덱스에 위치한 요소들만 추출하여 
# 새로운 리스트를 반환하는 함수를 작성하세요.

def even_index_elements(lst):
    pass

print(even_index_elements([10, 20, 30, 40, 50]))  # 출력: [10, 30, 50]

##############################################################

# 문제 11: 문자열을 정수로 변환
# 문자열로 표현된 숫자를 정수로 변환하는 함수를 작성하세요. 
# 단, 숫자 이외의 문자가 포함된 경우에는 None을 반환하세요.

def str_to_int(s):
    pass

print(str_to_int("12345"))  # 출력: 12345
print(str_to_int("12a45"))  # 출력: None

##############################################################

# 문제 12: 숫자를 문자열로 변환
# 주어진 정수를 문자열로 변환하는 함수를 작성하세요. 
# 음수와 0도 처리해야 합니다.

def int_to_str(n):
    pass

print(int_to_str(12345))  # 출력: "12345"
print(int_to_str(-12345))  # 출력: "-12345"

##############################################################

# 문제 13: 리스트 합치기
# 두 개의 리스트를 하나로 합치는 함수를 작성하세요.

def concatenate_lists(lst1, lst2):
    pass

print(concatenate_lists([1, 2, 3], [4, 5, 6]))  # 출력: [1, 2, 3, 4, 5, 6]

##############################################################

# 문제 14: 문자열에서 모음 개수 세기
# 주어진 문자열에서 모음(a, e, i, o, u)의 개수를 세는 함수를 작성하세요.

def count_vowels(s):
    pass

print(count_vowels("hello world"))  # 출력: 3

##############################################################

# 문제 15: 중첩 리스트 평탄화
# 중첩된 리스트를 평탄화하여 단일 리스트로 만드는 함수를 작성하세요.

def flatten_list(lst):
    pass

print(flatten_list([1, [2, 3], [4, [5, 6]], 7]))  
# 출력: [1, 2, 3, 4, 5, 6, 7]