스터디/파이썬 스터디 강의자료

[4팀/이제은] 5차시 파이썬 스터디 - 함수

알 수 없는 사용자 2023. 4. 6. 17:12

DSOB_5강_강의자료.pdf
0.58MB
DSOB_5강_과제.pdf
0.28MB

01 함수 기초

> 함수의 개념과 장점

>> 코딩의 꽃, 함수

이때까지 print( )나 range 등과 같은 함수를 사용해왔습니다.

이번 장에서는 이런 함수들을 직접 만들어봅시다!

함수를 조금 더 쉽게 이해하기 위해 믹서에 비유해보았습니다.

어떠한 과일을 갖고 주스라는 음식을 완성하기 위해선 믹서라는 도구가 필요하죠! 여기서의 믹서는 과일을 입력받아 주스를 출력하는 함수와 같은 역할을 하고 있는 것입니다.

😊 즉, 입력값을 가지고 어떤 일을 수행한 다음에 그 결과물을 내어놓는 것, 이것이 바로 함수가 하는 일입니다. (함수의 개념)

 

그렇다면 이 믹서를 왜 사용할까요? 각기 다른 과일을 여러번 주스로 만들어먹기 위해서 사용합니다. 함수도 이와 같습니다.

😊 즉, 똑같은 작업을 여기서도 하고, 저기서도 하고, 여러 번 하고 싶을 때 사용합니다. (함수의 장점)

또한, 프로그래밍의 경우 여러 사람이 하나의 작업을 같이 작업하는 경우가 대부분입니다. 이런 경우에 팀원들이 각자 해야 할 부분을 나눠서 하고 나중에 합치게 됩니다. 함수라는 개념은 바로 이 방법을 가능하도록 도와줍니다.

 

 

>> 개념과 장점

 

함수(funtion) : 어떤 일을 수행하는 코드의 덩어리, 코드의 묶음

 

- 필요할 때마다 호출 가능

반복적으로 수행해야 하는 업무를 한 번만 작성해 놓고 필요할 때마다 호출하여 사용할 수 있습니다. (같은 작업을 여러 번 반복하지 않아도 됨)

 

- 논리적인 단위로 분할 가능

함수는 코드를 논리적인 단위로 나눌 수 있습니다. (간단히 도형을 계산하 는 프로그램을 곱셈을 하는 코드, 덧셈을 하는 코드, 나눗셈을 하는 코드 등으로 분할)

 

- 코드의 캡슐화

함수는 코드의 캡슐화가 가능합니다.

 


💊캡슐화(Encapsulation) : 데이터, 그리고 데이터를 처리하는 함수를 하나로 묶은 것

- 캡슐화된 객체들은 재사용이 가능하며, 세부 내용이 은폐(정보 은닉)되어 오류가 적습니다. 덕분에 인터페이스가 단순해지고, 객체간의 결합도가 낮아집니다.

- 캡슐화는 인터페이스만 잘 정의하면 다른 사람이 자신의 코드를 쉽게 가져다 사용할 수 있는 특징이 있습니다.

+ 인터페이스를 정의한다는 것은 코드에 입력되는 입력 input값과 코드의 수행 결과인 출력 output 값을 명확히 한다는 것이다. 흔히 블랙박스라고도 하는데, 인터페이스가 잘 정의된 함수라면 코드의 내부 구조를 몰라도 함수를 사용하는 데에는 아무 문제가 없다.

 

> 함수의 선언

함수를 직접 만드려면 함수를 정의부터 해주어야 합니다. 이때 Definition의 약자인 def를 사용합니다!

 

<기본 형태>

def 함수 이름 (매개변수 #1 ...):
	명령문 1
	명령문 2
	return <반환값>
  1. def를 통해 함수 이름과 받아올 매개변수를 정해줍니다.
  2. 함수 이름 : 함수 이름은 개발자가 마음대로 지정할 수 있지만 일반적으로 파이썬에서는 다음과 같은 규칙을 사용합니다. 
    • 소문자로 입력한다.
    • 띄어쓰기를 할 경우에 _ 기호를 사용한다.
    • 작업을 나타내기 위해 동사와 명사를 함께 사용하는 경우가 많다. ex) save_model
    • 외부에 공개하는 함수일 경우 줄임말을 사용하지 않고 짧고 명료한 이름으로 정한다.
  3. 매개변수 (parameter, 파라미터) : 매개변수는 함수에서 입력값으로 사용하는 변수를 의미하며, 1개 이상의 값을 적을 수 있습니다. 이 매개변수를 이용해 우리가 원하는 작업을 수행한 뒤 원하는 결과값을 출력합니다.
  4. 명령문 : 함수 내부의 명령 코드들은 들여쓰기를 하는 것을 잊지 맙시다! 수행하는 코드는 지금까지 배운 일반적인 코드와 같습니다.

그렇다면 간단한 덧셈 함수를 만들면서 감을 잡아보겠습니다.

먼저 함수가 할 일을 정확히 정해야합니다. 이 함수의 할 일은 숫자 두 개를 매개변수로 받아 덧셈을 한 뒤 출력하는 것입니다.

 

<실습>

def add_two_num(a, b):
    print("덧셈중...")
    result = a + b
    return result


value = add_two_num(10, 13)
print(value)

→ 두 수를 입력받고, ‘덧셈중…’이라는 문장을 출력한 뒤에, 두 수를 더한 값을 리턴값으로 받아오는 함수

→ 함수를 위에서 정의해주어야 함 : 기본적으로 코드는 위에서 아래로 진행하기 때문에 위에서 정의하지 않으면 실행문에서 함수를 찾지 못함

→ a, b 는 매개변수, 10, 13은 인수

 

 

<return>

리턴값의 역할을 알아보기 위해 위의 코드에서 리턴값 정의를 빼고 실행하여 봅시다.

def add_two_num(a, b):
    print("덧셈중...")
    result = a + b


value = add_two_num(10, 13)
print(value)

이렇게 리턴값을 정의해주지 않으면, 기본값은 None이 반환됩니다. 리턴값은 함수라는 믹서가 만들어낸 주스라고 생각하면 편합니다.

즉, 결과물, 출력값을 의미합니다.

한가지 알고있어야 하는 점은 return이 발생했을 때, 함수가 종료된다는 점입니다. (함수를 끝내는 return의 힘)

 

 > 함수의 형태

함수는 매개변수와 리턴값(반환값)의 유무에 따라 네 가지 형태로 구분합니다.

각각의 함수를 코드로 작성해봅시다!

 

def add(a, b): 
    result = a + b 
    return result


a = add(3, 4)
print(a)

매개변수O, 반환값O

 

def add(a, b): 
    print("%d, %d의 합은 %d입니다." % (a, b, a+b))


add(3, 4)
a = add(3, 4)
print(a)

매개변수O, 반환값X

 

def say(): 
    return 'Hi'


a = say()
print(a)

매개변수X, 반환값O

 

def say(): 
    print('Hi')

say()

매개변수X, 반환값X

 

 

 02 함수의 인수

> 변수

이제 변수에 대해 조금 더 자세히 다뤄보도록 하겠습니다.

변수라면 전에 배웠지만, 저번에는 자료형을 중점으로 배웠고, 이번에는 변수의 종류들을 배워볼 것입니다.

 

- 전역변수와 지역변수

먼저 변수에는 전역변수와 지역변수가 있습니다.

전역변수 : 프로그램 체 영에서 사용하는 변수

지역변수 : 특정 코드블록에서만 지역적으로 사용되는 변수

 

def add_two_num(a, b):
    print("덧셈중...")
    result = a + b
    return result


result = 0
add_two_num(10,13)
print(result)

위 코드를 실행해보도록 하겠습니다. 분명 result 값에 10 + 13 계산을 해서 대입했는데 결과는 0이 나왔습니다.

이는 지역변수와 전역변수의 개념을 보여줍니다. result = 0과 result = a + b 에서의 result는 서로 다릅니다.

add_two_num 안의 result는 해당 함수 내에서만 사용하는 지역변수로써 사용되고 사라집니다.

→ 그렇다면 함수 안에서 전역변수를 사용하고 싶다면? : global 변수 지정

 

def add_two_num(a, b):
    global result
    print("덧셈중...")
    result = a + b
    return result

result = 0
add_two_num(10,13)
print(result)

함수 안에서 result를 global 변수로 지정해주었습니다. 결과가 우리가 생각하는대로 나왔음을 알 수 있습니다.

 

> 매개변수와 인수

🧐 매개변수(parameter)인수(argument)의 차이는 무엇일까요?

코드와 함께 살펴봅시다.

def add_two_num(a, b):    # 함수 정의
    print("덧셈중...")
    result = a + b
    return result


a = 10
b = 13
value = add_two_num(a, b) # 함수 호출

우리는 함수를 정의할 때, 그리고 함수를 호출할 때, 값을 넣습니다.

함수를 정의할 때 넣는 값(변수)를 매개변수라 하고,

함수를 호출할 때 넣는 값을 인수라 합니다.

 

> 인수의 종류

함수의 입력으로 들어가는 변수인 인수의 다양한 형태에 대해 알아봅시다!

 

>> 키워드 인수

→ 함수의 인터페이스에서 지정한 변수명을 사용하여 함수의 인수를 지정하는 방법

def print_sth(my_name, your_name):
    print("Hello {0}, My name is {1}".format(your_name, my_name))


print_sth("Minji", "Hanni")
print_sth(your_name = "Hanni", my_name = "Minji")

print_sth 함수는 (my_name, your_name)이라는 입력 인터페이스를 가집니다. 함수를 호출할 땐 인수가 순서대로 입력되도록 코드를 작성해야 합니다. (첫 번째 print)

그러나 함수의 입력 변수명만 정확히 기재된다면 순서에 상관없이 원하는 변수에 인수를 넣을 수 있습니다. (두 번째 print)

이처럼 함수의 인터페이스에서 지정한 변수명을 사용해서 인수를 지정하는 방법키워드 인수를 사용한 방법입니다.

 

 

 

>> 디폴트 인수

→ 매개변수에 기본값을 지정하여 사용하고 아무런 값도 인수로 넘어가지 않을 때 지정된 기본값(디폴트 값)을 사용하는 방법

def print_sth_2(my_name, your_name = "Hanni"):
    print("Hello {0}, My name is {1}".format(your_name, my_name))


print_sth_2("Minji", "Hanni")
print_sth_2("Minji")

1행에서 함수의 입력 인터페이스를 정의했는데, your_name 매개변수에는 기본값으로 “Hanni”가 지정된 것을 확인할 수 있습니다.

→ 함수를 호출할 때 your_name 매개변수에는 별도의 값을 할당하지 않아도 디폴트 값이 할당

 

 

>> 가변 인수

→ 함수의 매개변수 개수가 정해지지 않은 경우에 사용하는 방법 ex) 고객이 물건을 얼마나 구매할지 모르는 마트 계산 등…

→ * 로 표현 가능 ( * 는 asterisk라고 부름)

def asterisk_test(a, b, *args):
    return a + b + sum(args)


print(asterisk_test(1, 2, 3, 4, 5))

# args 는 argument를 줄인 것, 즉 인수들-이라는 뜻으로 사용…

함수 asteisk_test( )는 변수 a, b를 넘겨받고, 나머지를 *args로 넘겨받고 있습니다. 이때 사용하는 *args가 가변 인수라고 합니다.

즉, 1과 2는 각각 a와 b에 할당되고, 나머지 인수인 3, 4, 5가 모두 *args에 할당됩니다.

 

- 형태

가변 인수의 형태를 확인해보기 위해 직접 출력해보겠습니다!

def asterisk_test(a, b, *args):
    print(args)


print(asterisk_test(1, 2, 3, 4, 5))

출력해보니 결과값이 괄호에 묶여 출력됩니다.

이렇게 괄호로 묶여 출력되는 자료형을 튜플(tuple) 자료형이라고 합니다! (나중에 배우겠지만 리스트 자료형처럼 인덱스로 접근할 수 있습니다.)

 

- 특징

💬 가변 인수 * 는 반드시 일반적인 키워드 인수에 대한 선언이 끝난 후 가장 마지막에 선언되어야 합니다.

💬 가변 인수는 튜플 형태로 리스트와 같이 인덱스를 사용하여 접근할 수 있습니다.

💬 가변 인수의 개수를 정확히 안다면 언패킹을 할 수 있습니다.

def asterisk_test_2(*args):
    x, y, *z = args
    return x, y, z


print(asterisk_test_2(3, 4, 5, 6, 7))

→ * 는 기능이 다양하여 언패킹할 때도 값을 가변 인수의 형태로 받을 수 있습니다.

 

 

>> 키워드 가변 인수

→ 기존의 가변 인수는 변수의 이름을 지정할 수 없다는 단점이 있었습니다.

→ 키워드 가변 인수는 **를 사용하여 함수의 매개변수를 표시합니다.

def kwargs_test(**kwargs):
    print(kwargs)
    print("First value is {first}".format(**kwargs))
    print("Second value is {second}".format(**kwargs))
    print("Third value is {third}".format(**kwargs))


kwargs_test(first = 3, second = 4, third = 5) # 함수를 호출할 때 인수(변수)의 이름을 미리 정해놓는다.

# kwargs는 keyword arguments를 줄인 것, 즉 키워드 인수들-이라는 뜻으로 사용…

함수를 호출할 때 first, second, third 인수 총 3가지를 넘겼습니다. print 함수에서 그 인수들이 {’first’ : 3, ‘second’ = 4, ‘third’ = 5}와 같은 형태로 출력이 됩니다.

이렇게 { ‘변수명’ = 값, ‘변수명2’ = 값2 …} 와 같이 변수명과 값을 한 쌍으로 해서 저장하는 형태딕셔너리 자료형이라고 합니다.

→ 즉, 키워드 가변 인수는 딕셔너리 자료형으로 사용할 수 있습니다.

 

kwargs = {'first': 3, 'second': 4, 'third': 5}
print("Second value is {second}".format(**kwargs))
print("Second value is {second}".format(first =3, second = 4, third =5))

def kwargs_test(one, two, *args, **kwargs):
    print(one + two + sum(args))
    print(kwargs)


kwargs_test(3, 4, 5, 6, 7, 8, 9, first=3, second=4, third=5)

 

 

 03 좋은 코드를 작성하는 방법

> 좋은 코드의 의미

일반적으로 프로그래밍은 팀플레이입니다. 여러 사람과 함께 일하기 때문에 프레젠테이션 발표를 하듯 사람들과 소통하면서 프로그래밍해야 합니다.

더보기

“컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다.” - 마틴 파울러

🙌 즉, 다른 사람이 내가 작성한 코드를 굉장히 쉽게 이해할 수 있도록 프로그램을 작성해야 한다는 뜻입니다. (가독성)

👌 프로그램 코드는 많은 사람이 쉽게 읽고 이해할 수 있도록 가독성이 좋아야 합니다.

 

> 코딩 규칙

파이썬 키본 코딩 규칙 중 대표적인 것 👏

- 들여쓰기는 4 스페이스

- 한 줄은 최대 79자까지

- 불필요한 공백은 없애기

 

PEP-8 중 대표적인 것 👏

- 연산자는 한 칸 이상 띄우지 않는다.

- 주석은 항상 갱신하고 불필요한 주석은 삭제한다. 

- 소문자 l(엘), 대문자 O(오), 대문자 I(아이)는 사용을 금한다. 

lIO0 = "Hard to Understand"  # 구분하기 어렵습니다...

- 함수는 소문자로 구성하고, 필요하면 밑줄로 구분한다.

 

 

> 함수 개발 가이드라인

>> 함수의 이름

- 함수 내용은 가능하면 짧게 (줄 수를 줄여서) 작성할 것

- 함수 이름에 함수의 역할과 의도를 명확히 드러낼 것

주로 ‘동사+명사’의 형태로 이름을 지정할 때가 많습니다.

def print_hello_world():
    print("Hello, World")
def get_hello_world():
    return "Hello, World"

 

>> 함수의 역할

- 함수는 한 가지 역할을 명확히 해야 합니다.

- 최소한의 역할만 수행할 수 있도록!

def add_variables(x, y):
return x + y

def add_variables(x, y):
print(x, y)
return x + y

→ 두 변수를 더하는 함수하면 굳이 그 결과를 화면에 출력할 필요는 없다.

 

 

>> 함수를 만들어야 하는 경

1. 공통으로 사용되는 코드를 함수로 변환

a = 5
if (a>3):
    print("Hello World")
    print("Hello SWU")
if (a>4):
    print("Hello World")
    print("Hello SWU")
if (a>5):
    print("Hello World")
    print("Hello SWU")
def print_hello():
    print("HeUo World")
    print("Hello SWU")

a = 5
if (a > 3):
    print_hello()

if (a > 4):
    print_hello()

if (a >5):
    print_hello()

 

2. 복잡한 로직이 사용되었을 때 식별 가능한 이름의 함수로 변환

import math
a = 1; b = -2; c = 1

print((-b + math.sqrt(b ** 2 - (4 * a * c)) ) / (2 * a))
print((-b - math.sqrt(b ** 2 - (4 * a * c)) ) / (2 * a))

1.0

1.0

프로그램을 사용하는 입장에서 공식의 의미만 알면 되고 굳이 공식의 구현 과정까지는 알 필요 없습니다.

import math

def get_result_quadratic_equation(a, b, c):
    values = [ ]
    values.append((-b + math.sqrt(b ** 2 - (4 * a * c))) / (2 * a))
    values.append((-b - math.sqrt(b ** 2 - (4 * a * c)) ) / (2 * a))
    return values


print(get_result_quadratic_equation(1,-2,1))

[1.0, 1.0]