상세 컨텐츠

본문 제목

사용자 정의 함수

인공지능_2026/1. 파이썬

by Ryuzy 2026. 4. 27. 14:14

본문

반응형

1. 사용자 정의 함수

사용자 정의 함수란 사용자가 특정 작업을 수행하기 위해 직접 작성한 함수를 의미합니다. 파이썬에는 많은 내장 함수들이 있지만, 때로는 우리의 요구사항에 맞게 동작하는 함수를 직접 만들어야  때가 있습니다. 이때 사용자 정의 함수를 작성하게 됩니다.

 

1. 함수의 동작

def 함수명(매개변수1, 매개변수2, ...):
    # 함수 내용
    return 결과값

 

이름의 함수를 만드는 것이 아니라, 정확히는 다음처럼 동작합니다.

1. 함수 객체를 메모리에 생성
2. 그 함수 객체에 함수명 이름을 붙임

 

def hello():
    print("안녕하세요")

a = hello
a()

👉  a = hello는 함수를 복사한 것이 아니라, 같은 함수 객체를 참조하는 이름을 하나 더 만든 것입니다.

 

2. 함수 객체

function object
├── 함수 이름
├── 매개변수 정보
├── 실행할 코드 정보
├── 기본값 정보
├── 전역 네임스페이스 정보
└── 클로저 정보

 

print(a) # 함수 객체: 함수 자체를 나타내는 객체
print(a.__code__) # 코드 객체: 함수 안에서 실행할 실제 바이트코드 정보를 담고 있는 객체

 

3. 함수 호출 시 메모리에서 일어나는 일

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

x = add(3, 5)

1. add 이름이 가리키는 함수 객체를 찾음
2. 함수 실행을 위한 새 공간 생성
3. 매개변수 a, b에 값 연결
4. 함수 본문 실행
5. return 값 반환
6. 함수 실행 공간 제거

👉  이때 만들어지는 새 공간을 스택 프레임(stack frame) 또는 함수 호출 프레임이라고 합니다.

 

함수 호출 프레임

함수 호출 프레임(call frame)은 파이썬에서 함수가 호출될 때마다 생성되는 독립적인 실행 공간으로, 해당 함수의 매개변수, 지역 변수, 반환 주소, 그리고 실행 상태(어디까지 실행했는지 등)를 저장하는 구조입니다. 이 프레임은 스택(stack) 형태로 관리되어 함수가 호출될 때 쌓이고, 실행이 끝나면 제거되며, 이를 통해 함수 간 변수 충돌 없이 안전하게 실행됩니다. 즉, 같은 함수를 여러 번 호출하더라도 매번 새로운 프레임이 만들어지기 때문에 각 호출은 서로 영향을 주지 않고 독립적으로 동작합니다.

 

 

2. 함수 만들기

1. 매개변수와 반환 값이 없는 함수

def func1():
    print('처음으로 만드는 함수!')
    
func1()
func1()

for i in range(5):
    func1()

 

2. 매개변수가 있고 반환 값이 없는 함수

def func2(num):
    print(f'입력받은 숫자: {num}')
    
func2(10)
func2(4)

 

def func3(start, end):
    sum = 0
    for i in range(start, end+1):
        sum += i
    print(f'{start}부터 {end}까지의 합: {sum}')

func3(1, 10)
func3(1, 100)

👉   함수 안의 지역 변수는 매번 새로 만들어집니다. 새로운 함수 호출 프레임이 만들어지고, 함수가 끝나면 사라지기 때문입니다.

 

3. 반환 값이 있는 함수

def func1():
    print('처음으로 만드는 함수')

func1()
temp = func1()
print(temp)

temp = func1
print(temp)
temp()

 

def func4():
    return '🎁'

print(func4())
temp = func4()
print(f'temp에 저장된 값: {temp}')

 

def func5(num1, num2):
    sum = num1 + num2
    return sum

print(func5(10, 5))
temp = func5(4, 3)
print(temp)

print(func5(10)) # TypeError: func5() missing 1 required positional argument: 'num2'

 

def funcA():
    print("A 시작")
    result = funcB()
    print("A 끝")
    return result

def funcB():
    print("B 시작")
    result = funcC()
    print("B 끝")
    return result

def funcC():
    print("C 실행")
    return 100

# 실행
value = funcA()
print("최종 결과:", value)

👉 함수 호출은 스택 구조(LIFO) 로 관리되며, 가장 나중에 호출된 함수가 가장 먼저 종료됩니다.

 

4. 기본값이 설정된 매개변수

기본 매개변수는 함수 생성 시 한 번 만들어집니다

def func6(num1=0, num2=0):
    sum = num1 + num2
    return sum
    
print(func6())
print(func6(10))
print(func6(10, 3))
# print(func6(, 3))
# print(func6(None, 3))
print(func6(num2=3))

 

def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item("사과"))
print(add_item("바나나"))
print(add_item("오렌지"))

👉 items=[]는 함수가 호출될 때마다 새로 만들어지는 것이 아니라, 함수 객체가 만들어질 때 한 번 생성됩니다. 그래서 모든 호출이 같은 리스트를 공유합니다.

 

안전하게 사용하는 방식은 아래와 같습니다.

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("사과"))
print(add_item("바나나"))
print(add_item("오렌지"))

 

None

None은 파이썬에서 값이 존재하지 않음을 나타내는 특별한 객체입니다. 모든 None은 비교 시 == 대신 is를 사용하는 것이 권장됩니다(x is None). 함수에서 return을 명시하지 않으면 자동으로 None이 반환되며, 변수 초기화나 “아직 값이 정해지지 않음”을 표현할 때 자주 사용됩니다. 또한 None은 False로 평가되지만 0, "", [] 등과는 의미적으로 구분되며, 연산 대상이 아니기 때문에 산술 연산에 사용하면 오류가 발생합니다.

 

5. 가변 매개변수

함수를 호출할  * 사용하면 시퀀스(리스트, 튜플 등)의 요소를 개별적인 위치 인자로 풀어서 전달할  있습니다.

def func7(*args):
    return args
    
print(func7())
print(func7(10))
print(func7(10, 30, 50))

 

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

numbers = [1, 2, 3]
print(func8(*numbers))

 

6. 키워드 매개변수

키워드 매개변수는 일반적으로 기본값이 설정된 매개변수와 함께 사용됩니다. 함수의 매개변수에 기본값을 설정하면, 함수를 호출할 때 해당 매개변수를 생략할 수 있습니다.

def func9(id, name, age):
    print(f'아이디: {id}')
    print(f'이름: {name}')
    print(f'나이: {age}')
    
func9('apple', '김사과', 20)
func9(age=30, id='orange', name='오렌지')

# 매개변수명과 딕셔너리의 키가 같아야함
# 딕셔너리의 키는 반드시 문자열 형태
dic1 = {'age':25, 'id':'banana', 'name':'반하나'}
func9(**dic1)

# *의 데이터를 보낼 경우 키가 저장
func9(*dic1)

 

7. 여러개의 반환 값

def func10(num1=0, num2=0):
    return num1+num2, num1-num2, num1*num2, num1/num2

result = func10(10, 3)
print(result)

result1, result2, result3, result4 = func10(10, 3)
print(f'덧셈:{result1}')
print(f'뺄셈:{result2}')
print(f'곱셈:{result3}')
print(f'나눗셈:{result4}')

_, _, result3, _ = func10(10, 3)
print(f'곱셈: {result3}')

 

li1 = [10, 20, 30, 40, 50]

for _, v in enumerate(li1):
    print(f'값: {v}')

 

 

3. 변수의 범위

변수의 범위(scope)는 해당 변수가 프로그램 내에서 참조되고 변경될  있는 영역을 의미합니다.

def local_example():
    local_var = "로컬 변수"
    print(local_var)

local_example()

👉 지역변수: 가장 내부의 범위로, 함수 내에서 정의된 변수들이 해당됩니다. 함수 내에서만 접근할 수 있습니다.

 

global_var = "I'm a global variable"

def test_global_scope():
    print(global_var)

test_global_scope()

👉  전역변수: 스크립트 전체에서 사용되는 범위로, 함수 외부에 정의된 변수가 해당됩니다. 모든 함수에서 접근할 수 있지만, 함수 내부에서 수정하려면 global 키워드가 필요합니다.

 

global_var = 10

def modify_global():
    global global_var
    global_var = 20

modify_global()
print(global_var)  # 출력: 20

 

def outer_function():
    enclosing_var = "둘러싼 범위 변수"
    
    def inner_function():
        print(enclosing_var)
    
    return inner_function

f = outer_function()
f()

👉   클로저 변수: 내부 함수가 외부 함수의 지역 변수를 사용하면, 파이썬은 그 값을 바로 삭제하지 않고 클로저 공간에 보관합니다.

 

클로저 공간

클로저 공간은 내부 함수가 외부 함수의 변수를 계속 사용할 수 있도록, 그 값을 따로 저장해두는 메모리 영역(정확히는 객체 구조)입니다. 일반적으로 함수가 끝나면 그 안의 지역 변수는 사라지지만, 내부 함수가 그 변수를 참조하고 있으면 파이썬은 해당 값을 지우지 않고 함수 객체 안에 __closure__라는 형태로 보관합니다. 이때 저장되는 값은 보통 cell 객체로 감싸져 유지되며, 내부 함수는 실행될 때 이 클로저 공간을 통해 외부 변수에 접근합니다.

 

len = 5  # 내장 함수 'len'을 덮어씀
print(len([1, 2, 3]))  # 오류 발생! len이 함수가 아니라 변수로 인식됨

👉 빌트인 함수: 파이썬에서 별도의 import 없이 바로 사용할 수 있도록 기본적으로 제공되는 함수들을 의미합니다. 예를 들어 print(), len(), type(), range() 같은 함수들이 이에 해당하며, 파이썬이 실행될 때 자동으로 Built-in 네임스페이스에 등록되어 있기 때문에 어디서든 이름만으로 호출할 수 있습니다. 변수 이름을 찾을 때 적용되는 LEGB 규칙(Local → Enclosing → Global → Built-in)에서 마지막 단계에 해당하며, 만약 같은 이름의 변수를 직접 정의하면 Built-in 함수는 가려질 수 있습니다.

 

 

4. 함수 메모리 제거

함수도 파이썬 객체이므로 참조 카운팅과 가비지 컬렉션의 원칙에 따라 동작합니다. 함수를 참조하는 변수나 요소가 없게 되면 해당 함수는 가비지 컬렉터에 의해 메모리에서 제거될 수 있습니다. del 명령어를 사용하여 함수에 대한 참조를 명시적으로 제거할  있지만 이것이 함수가 즉시 메모리에서 제거된다는 것을 보장하지는 않습니다.

def func1():
    print('처음으로 만드는 함수')

del func1
# 이후 func1()을 호출하려고 하면 오류가 발생합니다.

 

 

5. 콜백 함수

콜백 함수(callback function)는 다른 함수에 인자로 전달되어, 특정 시점이나 조건이 되었을 때 나중에 호출되는 함수를 의미합니다. 파이썬에서는 함수도 객체이기 때문에 변수처럼 전달할 수 있으며, 이를 활용해 어떤 작업이 끝난 뒤 실행할 동작을 미리 정의해 둘 수 있습니다. 즉, 콜백 함수는 “지금 바로 실행하는 함수”가 아니라, 다른 함수에게 맡겨두었다가 필요할 때 호출되도록 하는 함수입니다.

def say_hello(name):
    print(f"{name}님 안녕하세요!")

def execute(callback):
    print("작업을 시작합니다.")
    callback("김사과")
    print("작업을 종료합니다.")

execute(say_hello)

👉 여기서 say_hello가 콜백 함수입니다.

 

def print_score(score):
    print(f"점수: {score}")

def print_pass_fail(score):
    if score >= 80:
        print(f"{score}점: 합격")
    else:
        print(f"{score}점: 불합격")

def print_bonus_score(score):
    print(f"보너스 적용 점수: {score + 5}")

def process_scores(scores, callback):
    for score in scores:
        callback(score)

scores = [80, 95, 70, 100, 60]

print("원점수 출력")
process_scores(scores, print_score)

print("합격 여부 출력")
process_scores(scores, print_pass_fail)

print("보너스 점수 출력")
process_scores(scores, print_bonus_score)

👉 콜백 함수는 공통 작업은 그대로 두고, 세부 동작만 바꾸고 싶을 때 유용합니다.

 

students = [
    {"name": "김사과", "score": 90},
    {"name": "반하나", "score": 75},
    {"name": "오렌지", "score": 100}
]

def get_score(student):
    return student["score"]

result = sorted(students, key=get_score)

print(result)

👉 sorted()는 학생 하나하나를 비교할 때마다 get_score()를 호출해서 정렬 기준값을 얻습니다.

 

 

6. 람다 함수

람다 함수(lambda function)는 파이썬에서 이름 없이 간단한 함수를 한 줄로 정의할 수 있는 익명 함수로, 주로 짧고 일회성으로 사용되는 연산을 표현할 때 활용됩니다. 일반 함수(def)에 비해 구조는 제한적이지만 코드가 간결해지고, 특히 sorted, map, filter 같은 함수에서 콜백 함수로 자주 사용됩니다.

lambda 매개변수: 반환할_표현식

 

# 일반 함수
def square(x):
    return x * x

print(square(5))

# 람다 함수
square = lambda x: x * x

print(square(5))

 

multiply = lambda a, b: a * b

print(multiply(3, 4))

 

pass_fail = lambda score: "합격" if score >= 60 else "불합격"

print(pass_fail(80))
print(pass_fail(45))

 

students = [
    {"name": "김사과", "score": 90},
    {"name": "반하나", "score": 75},
    {"name": "오렌지", "score": 100},
]

result = sorted(students, key=lambda student: student["score"], reverse=True)
print(result)

 

scores = [70, 80, 90]

result = list(map(lambda score: score + 10, scores))
print(result)

👉  map()은 리스트의 각 요소에 같은 작업을 적용할 때 사용합니다.

 

scores = [45, 70, 88, 52, 100]

passed = list(filter(lambda score: score >= 60, scores))
print(passed)

👉  filter()는 조건을 만족하는 값만 골라낼 때 사용합니다.

 

반응형

'인공지능_2026 > 1. 파이썬' 카테고리의 다른 글

객체지향 프로그래밍 4대 패러다임  (0) 2026.04.28
객체지향 프로그래밍(OOP)  (0) 2026.04.27
제어문 - 반복문  (0) 2026.04.17
제어문 - 조건문  (0) 2026.04.17
컬렉션 타입(세트, 딕셔너리)  (0) 2026.04.16

관련글 더보기