본문 바로가기
Python

Python - functions

by DGK 2021. 10. 15.

 

인프런 파이썬 입문 수업을 듣고 중요한 내용을 정리했습니다.
개인 공부 후 자료를 남기기 위한 목적이므로 내용 상에 오류가 있을 수 있습니다.

 

functions

 

  • 기본 개념
# 기본 구조

def funciton_name(parameter):

       code
       
funciton_name(argument)




# 활용 예시

def first_func(w):
    print("Hello, ", w)
 
word = "Goodboy"

first_func(word)

# 결과 : Hello,  Goodboy



def return_func(w1):
    value = "Hello, " + str(w1)
    return value                    

x = return_func('Goodboy2')
print(x)			

# 결과 : Hello, Goodboy2

# value = "Hello, " + str(w1)
# return value 
# 이러한 두 줄의 코드를 아래의 간결한 코드로 대체할 수도 있다.
# return "Hello, " + str(w1)



def func_mul(x):
    y1 = x * 10
    y2 = x * 20
    y3 = x * 30
    return y1, y2, y3       

a, b, c = func_mul(10)

print(a, b, c)

# 결과 : 100, 200, 300

# 위와 같은 방법으로 y1, y2, y3의 변수들을 
# return으로 동시에 반환할 수 있다.(다중반환 or 다중리턴)

# a, b, c = func_mul(10) 코드는 언팩킹을 의미하며,
# 위에서 y1, y2, y3으로 반환된 값을 각각 a, b, c에 풀어서 넣어준다.



def func_mul2(x):
    y1 = x * 10
    y2 = x * 20
    y3 = x * 30
    return (y1, y2, y3)    

q = func_mul2(20)

print(type(q), q)

# 결과 : <class 'tuple'> (200, 400, 600)

# return (y1, y2, y3) 코드는 팩킹을 의미하며,
# 튜플 형태로 y1, y2, y3 변수들을 묶어준다.
# 이것이 print(q)의 결과가 튜플 형태인 이유이다.



def func_mul3(x):
    y1 = x * 10
    y2 = x * 20
    y3 = x * 30
    return [y1, y2, y3]

p = func_mul3(30)

print(type(p), p)

# 결과 : <class 'list'> [300, 600, 900]

# return [y1, y2, y3] 코드는 팩킹을 의미하며,
# 리스트 형태로 y1, y2, y3 변수들을 묶어준다.
# 이것이 print(p)의 결과가 리스트 형태인 이유이다.



def func_mul4(x):
    y1 = x * 10
    y2 = x * 20
    y3 = x * 30
    return {y1, y2, y3}

r = func_mul4(40)

print(type(r), r)

# 결과 : <class 'set'> {400, 800, 1200}

# return {y1, y2, y3} 코드는 팩킹을 의미하며,
# 집합(set) 형태로 y1, y2, y3 변수들을 묶어준다.
# 이것이 print(r)의 결과가 집합(set) 형태인 이유이다.



def func_mul5(x):
    y1 = x * 10
    y2 = x * 20
    y3 = x * 30
    return {'v1': y1, 'v2': y2, 'v3': y3}

k = func_mul5(50)

print(type(k), k)

# 결과 : <class 'dict'> {'v1': 500, 'v2': 1000, 'v3': 1500}

print(k.get('v2'), k.items(), k.keys())

# 결과 :
# 1000
# dict_items([('v1', 500), ('v2', 1000), ('v3', 1500)])
# dict_keys(['v1', 'v2', 'v3'])

# return {'v1': y1, 'v2': y2, 'v3': y3} 코드는 팩킹을 의미하며,
# 딕셔너리 형태로 y1, y2, y3 변수들을 묶어준다.
# 이것이 print(k)의 결과가 딕셔너리 형태인 이유이다.

 

 

  • 응용 개념
# 언팩킹 

# *args(튜플 자료형 언팩킹)

def args_func(*args):      
    for i, v in enumerate(args):
        print('Result : {}'.format(i), v)
    print('----------')

args_func('Lee')
args_func('Lee', 'Park')
args_func('Lee', 'Park', 'Kim')

# 결과 :

# Result : 0 Lee
# ----------
# Result : 0 Lee
# Result : 1 Park
# ----------
# Result : 0 Lee
# Result : 1 Park
# Result : 2 Kim
# ----------

# args_func( ) 함수의 파라미터는 반드시 *args일 필요가 없으며,
# 자유롭게 파라미터 이름을 넣어주면 된다.(ex : *a)

# args_func( ) 함수의 파라미터로 *args를 넣으면,
# 몇 개의 전달인자가 팩킹 형태로(묶여서) 파라미터로 들어오든 상관없이,
# 하나씩 언팩킹하여(풀어서) 함수코드에 적용할 수 있다.
# 즉, 튜플 형태의 전달인자가 파라미터로 들어오면 튜플의 데이터를 하나씩 언팩킹하여
# 함수 코드에 적용하는 것이다.

# enumerate( ) 함수는 팩킹된 데이터의 인덱스 번호와 데이터 요소를 반복문에
# 적용하는 함수이다.

# 즉, 파라미터 *args안에 튜플 형태의 전달인자가 들어왔기 때문에,
# enumerate( ) 함수는 튜플의 인덱스 번호는 i에 넣어주고, 데이터 요소는 v에 넣어준다.



# **kwargs(딕셔너리 자료형 언팩킹)

def kwargs_func(**kwargs):
    for v in kwargs.keys():
        print("{}".format(v), kwargs[v])
    print('---------')

kwargs_func(name1='Lee')                                
kwargs_func(name1='Lee', name2='Park')
kwargs_func(name1='Lee', name2='Park', name3='Kim')

# 결과 : 

# name1 Lee
# ---------
# name1 Lee
# name2 Park
# ---------
# name1 Lee
# name2 Park
# name3 Kim
# ---------

# 기본적으로 위의 *args 코드와 원리는 동일하다.
# 단지 전달인자로 파라미터에 넘기는 자료형이 다를 뿐이다.(딕셔너리)

# kwargs_func(name1='Lee')에서 name1은 키, Lee는 벨류이다.
# 즉, 전달인자로 파라미터 **kwargs에 딕셔너리 형태의 데이터를 넘긴 것이다.




# *args와 **kwargs의 활용 예시

def example(args_1, args_2, *args, **kwargs):
    print(args_1, args_2, args, kwargs)

example(10, 20, 'Lee', 'Kim', 'Park', age1=20, age=20, age3=40)

# 결과 :
# 10 20 ('Lee', 'Kim', 'Park') {'age1': 20, 'age': 20, 'age3': 40}

# 전달인자 10과 20은 파라미터 args_1과 args_2에 각각 할당되고,
# 전달인자 'Lee', 'Kim', 'Park'는 파라미터 *args에 할당되어 튜플 형태로 출력된다.
# 이 때 전달인자가 몇 개이든 상관없이 모두 튜플 형태로 묶여서 출력된다.

# 또한, 키와 벨류로 구성된 전달인자 age1=20, age=20, age3=40는 
# 파라미터 **kwargs에 할당되어, 딕셔너리 형태로 출력된다.
# 마찬가지로 전달인자가 몇 개이든 상관없이 모두 딕셔너리 형태로 묶여서 출력된다.




# 중첩함수

def nested_func(num):
    def func_in_func(num):
        print(num)
    print("In func")
    func_in_func(num + 100)

nested_func(100)

# 결과 : In func 200

# 중첩함수의 실행 원리는 다음과 같다.

# 우선, nested_func( ) 함수를 전달인자 100을 넣어 호출하면,
# nested_func( ) 함수 안에서 func_in_func( ) 함수가 새롭게 정의되고,
# 동시에 print("In func") 코드와 func_in_func( ) 함수가 호출된다.

# 이 때, nested_func( ) 함수의 전달인자인 100은 파라미터 num에 들어가고,
# num에 들어간 100이 func_in_func( ) 함수가 호출되는 과정에서
# num + 100의 전달인자에 들어간다.

# 즉, func_in_func( ) 함수는 전달인자 200을 갖고 호출되며,
# 전달인자 200은 func_in_func( ) 함수의 파라미터로 들어가서,
# print(num) 코드를 통해 출력되는 것이다.


# 참고로 func_in_func( ) 함수를 nested_func( ) 함수 밖에서
# 호출하면 에러가 발생한다. 
# 그 이유는 nested_func( ) 함수를 호출해야만, func_in_func( ) 함수가
# 정의되기 때문이다.

# 즉, nested_func( ) 함수의 호출 없이 독자적으로 func_in_func( ) 함수를 호출하면,
# 정의되지 않은 함수를 호출하는 것과 동일하므로 에러가 발생하는 것이다.




# lambda(람다식)

# 람다식은 메모리를 절약하고, 코드가 간결하여 가독성이 향상된다는 장점이 있다.
# 하지만 람다식을 너무 남발하는 경우에는 오히려 가독성이 떨어진다는 반론도 존재한다.

# 일반함수는 객체를 생성하고 메모리에 할당되지만,
# 람다식은 즉시실행 함수이기 때문에 Heap영역에 저장되고 메모리가 초기화되어,
# 메모리를 효율적으로 사용한다는 차이점이 있다.



# 기본 구조

# 일반함수의 구조

def mul_func(x, y):

	return x * y   



# 람다식의 구조

lambda x, y: x * y


# 위의 코드와 동일한 기능을 람다식 코드로 구현한 것이다.
# 람다식은 이름이 없기 때문에, 변수에 담아서 쓰거나 함수의 인자로 넘겨서 사용한다.




# 활용 예시

# 예시1

# 일반함수 사용 예시

def mul_func(x, y):
    return x * y

q = mul_func(10, 50)
print(q)			# 함수 호출방법1

print(mul_func(30, 50))		# 함수 호출방법2

mul_func_var = mul_func
print(mul_func_var(20, 50))	# 함수 호출방법3

# 일반 함수는 함수명이 존재하기 때문에 객체를 생성하고 메모리에 할당되어 실행된다.


# 람다식 사용 예시(동일한 기능 구현)

lambda_mul_func = lambda x, y: x * y

print(lambda_mul_func(50, 50))

# 람다식은 단순히 변수에 할당되어 곧 바로 실행된다.(함수명 존재X)



# 예시2

# 일반함수 사용 예시

def mul_func(x, y):
    return x * y

mul_func_var = mul_func

def func_final(x, y, func):
    print(x * y * func(100, 100))

func_final(10, 20, mul_func_var)


# 람다식 사용 예시(동일한 기능 구현)

def func_final(x, y, func):
    print(x * y * func(100, 100))

func_final(10, 20, lambda x, y: x * y)

# 이처럼 람다식은 일반함수를 정의하지 않고, 함수의 기능을 즉시 실행할 수 있다.

'Python' 카테고리의 다른 글

Python - class  (0) 2021.10.15
Python - input  (0) 2021.10.15
Python - while문  (0) 2021.10.14
Python - for문  (0) 2021.10.14
Python - if문  (0) 2021.10.14

댓글