본문 바로가기
Python/Python 기초

[Python] 함수

by snow_white 2022. 3. 12.

파이썬 함수의 구조

def 함수명(매개변수):
    <수행할 문장1>	# 함수 선언
    <수행할 문장2>	# 함수 구현
    ...

 

함수 내에서 전역변수, 지역변수 변경

x = 1
print('전역변수 주소',id(x)) # 전역변수 주소 2984273930544
def func(a):
    x = 2
    print('함수 내부에서 x변수 주소',id(x)) # 함수 내부에서 x변수 주소 2984273930576
    return a+x

print(func(1)) # 3
print(x) # 1  함수 내에서 x값을 바꿨어도 전역변수로 취급하지 않기 때문에 두 x는 다른 객체임
print('전역변수 주소',id(x)) # 전역변수 주소 2984273930544

가장 위에 선언한 x = 1이라는 전역변수를 초기화하였다.

func() 함수 내부에서 x 값을 변경하였지만 함수를 빠져나와 x값을 출력해보면 변경되어 있지 않는다.

상수는 가변변수이기 때문에 값이 변경되는 개념이 아니라 함수 내부에서 x라는 새로운 객체를 만드는 것이다.

따라서 함수 외부에서의 x와 함수 내부에서의 x의 주소값이 서로 다른 것을 볼 수 있다.

함수 호출 전의 x 주소값과 호출 후의 x 주소값이 같다. (같은 객체이다)

 

함수 내부에서 전역변수 값 변경하기

x = 1
print('전역변수 주소',id(x)) # 전역변수 주소 2984273930544
def func(a):
    global x 
    x = 2    # 전역변수를 새로운 객체로 만드는 것과 같음
    print('함수 내부에서 x변수 주소',id(x)) # 함수 내부에서 x변수 주소 2984273930576
    return a+x

print(func(1)) # 3
print(x) # 2
print('전역변수 주소',id(x)) # 전역변수 주소 2984273930576

전역변수 x를 함수 내부에서 변경할 수는 없나? 있다!

함수 내부에서 global 키워드를 사용하여 x의 참조값을 받아오자.

그리고 x 에 값을 할당하면, 상수는 가변변수라고 언급했듯이 값이 변하는 것이 아니고 새로운 x 객체가 만들어져 전역변수의 역할을 수행하게 된다. 이제 전역변수는 함수 내부에서 초기화한 값을 가지고, 주소값도 새롭게 변경된 것을 볼 수 있다. 따라서 함수를 호출하기 전의 x와 호출 후의 x 주소값이 다르다. (다른 객체이다)

 

위치매개변수

  • 가장 기본적인 인자값 전달방식
  • 함수에서 정의한 위치대로 인자값이 passing into
  • 모든 함수는 return 구문이 있거나 없는 함수로 정의됨
  • 함수 return은 함수를 호출한 부분으로 돌아가게 됨
def cal(num1, num2):
    print('num1:',num1,', num2:',num2) # num1: 1 , num2: 2
    result = num1+num2
    return result

# => 함수가 동작하려면 무조건 호출 부분이 필요함
print('반환된 값:',cal(1,2))   #반환된 값: 3
 
# 리턴 값이 있는 함수
def calc(num1, num2=1):
    '''
    이 부분을 doc string
    자기가 만든 함수를 자신만 보는 것이 아니라 팀원 전원이 공유해야 하기에
    해당 함수에 대한 자세한 설명을 달아둔다.
    
    매개변수로 받은 값들을 더하는 기능
    2개의 인자값을 넘겨받는다.
    총합은 리턴한다.
    '''
    print('num1:',num1,', num2:',num2) # num1: 1 , num2: 1
    result = num1+num2
    return result
print('반환된 값:',calc(1)) #반환된 값: 2

__doc__ 속성과 help

생성한 함수에 대해 자세한 설명을 추가하고 싶을 때 사용

# 함수 내부에 정리한 doctring 보는 방법
# calc?
print(calc.__doc__)

help(print)
'''
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

'''
# 리턴값이 없는 경우
# return 문이 없으면 함수는 None 객체를 리턴한다.
def add(a,b):
    add_sum = a+b
    print('함수 출력 : %d와 %d의 합은 %d입니다.'%(a,b,add_sum))
    
add(3,4)    # 3와 4의 합은 7입니다.

print(add(3,4)) # None

 

기본매개변수

  • 변수값을 입력하지 않으면 기본값이 활성화됨.
  • 즉, 매개변수에 아무것도 입력하지 않아도 무조건 자동으로 들어가는 값
  • 기본매개변수는 반드시 일반매개변수 뒤에 나와야 한다.
  • pandas 라이브러리에서도 많이 사용된다.
# end:위치 매개변수, start:기본 매개변수
def calc1(end, start=0):
    total = 0
    for i in range(start, end): # 1~4 반복 (5는 제외)
        total += i
    return total
print(calc1(5,1))    
print(calc1(5))  # 에러 안 난다. 기본값이 활성화 된다.

※ 에러 코드

# end:위치 매개변수, start:기본 매개변수
# SyntaxError: non-default argument follows default argument
def calc1(start=0, end): # 기본 매개변수는 일반 매개변수 뒤에 반드시 와야 한다.
    total = 0
    for i in range(start, end):
        total += i
    return total
print(calc1(5,1))

 

 

키워드 매개변수

  • 매개변수에 직접 변수명을 명시하여 값을 넘겨주는데 이를 키워드 매개변수라 한다
  • 인자값의 순서, 위치에 상관없이 직접 매개변수를 지정해서 전달한다
  • 주의할 점은 함수 호출시에 매개변수명을 정확히 알아야 한다.
  • 인자값을 안 준다고 해서 기본으로 매개변수가 들어가지 않음!!!
def set_person(ssn, name, age):
    print(f"주민번호는 {ssn}, 이름은 {name}이고, 나이는 {age}살 입니다.")
    
set_person('홍길동',11, 19)    
# 주민번호는 홍길동, 이름은 11이고, 나이는 19살 입니다.

set_person(age=19, name='홍길동', ssn=1112)    
# 주민번호는 1112, 이름은 홍길동이고, 나이는 19살 입니다.
import pandas as pd
import numpy as np
from pandas import DataFrame

# DataFrame?
df1 = DataFrame(
    np.random.randn(4,4),
    columns=list('efgh'),
    index=list('abcd')
    
)
df1
'''
	e		f		g		h
a	1.383449	-0.246959	1.445928	0.067173
b	1.716845	1.064221	-0.235065	1.045301
c	-0.643746	-2.678772	0.499906	-0.033849
d	1.479113	-0.280167	0.261731	-2.730998
'''

 

가변매개변수

  • 인자값이 몇개인지 모르는 상황에서 사용
  • 일반매개변수와 다르게 변수명 앞에 *을 붙임
  • 가변 매개변수는 인자값을 튜플형태로 받는다
  • 역시 가변매개변수 뒤에 일반매개변수가 뒤에 올 수없다
  • 가변 매개변수는 하나만 사용해야 한다
  • 파이썬에서 print() 함수가 대표적인데, 원하는 만큼의 인자값을 받을수 있도록 작성
def calc3(*args):# 변수명은 바꿀 수 있지만 convention
    print(args) # (1,) 튜플 형식으로 매개변수 받아옴
    print(type(args)) # <class 'tuple'>
    sum=0
    for i in args:
        sum += i
    return sum        
result = calc3(1) 
print(result) # 1

 

가변매개변수

  • *이 2개붙는 경우
  • **딕셔너리형 매개변수

calc4({'name': 'James', 'age': 14}) => 불가능

calc4(name='James', age=14) => 가능

'''
**이 2개 변수명 앞에 붙을 때는
인자값 입력에 조금 더 주의를 요한다.

딕셔너리 타입(key, value 인자값 타입으로!)

인자값으로 딕셔너리 전체를 넘기는 방법
이때 주의할 점 값을 넘길 때도 앞에 **을 붙인다!
'''
def calc4(**args):
    print(args)

calc4(name='Mark', age=15)     # {'name': 'Mark', 'age': 15}
info = {'name': 'James', 'age': 14}    
calc4(**info)			 # {'name': 'James', 'age': 14}

 

일반매개변수와 가변매개변수를 함께 사용하는 경우

def calc5(name, *args):
    print(name, ':', args)
    
calc5('hi', 1,2,3)    # 3,4,5 가 하나의 덩어리로 args에 들어가 튜플 형식으로 출력됨
# hi : (1, 2, 3)

calc5(3,4,5,'hi')
# 3 : (4, 5, 'hi')
#가변매개변수 뒤에 일반매개변수가 뒤에 올 수없다
# 인자로 들어가는 모든 값들이 *args로 들어가게 되어 
# 두 번째 매개변수인 name에 할당되는 값이 사라집니다
def calc5(*args, name):
    print(name, ':', args)
    
# TypeError: calc5() missing 1 required keyword-only argument: 'name'    
calc5('hi', 1,2,3)   # Error! 

calc5(3,4,5,'hi') # 3,4,5 가 하나의 덩어리로 args에 들어가 튜플 형식으로 출력됨
# 3 : (4, 5, 'hi')

 

튜플형, 딕셔너리형 매개변수 함께 사용하는 경우

def calc6(name, **args):
    print(name, ':', args) # James : {'a': 1, 'b': 2, 'c': 3}
    
dict = {'a':1, 'b':2, 'c':3}    
calc6('James',**dict)
def calc6(*a, **args):
    print(a, ':', args) # ((1, 2, 3), 'ji') : {'a': 1, 'b': 2, 'c': 3}
    print(a[0][0]) # 1
    
dict = {'a':1, 'b':2, 'c':3}   
tu = (1,2,3)
calc6(tu,'ji',**dict)
def calc7(*a, **b):
    for i in a:
        print(i)
    print('=='*20)
    
    for k, v in b.items():
        print(k, v)
    print('@@'*20)
    
calc7(1,2,3,a=5,b=6,c=7)
'''
1
2
3
========================================
a 5
b 6
c 7
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'''
dict = {'name':'James', 'address':'NY'}   
calc7(1,2,3,**dict)
'''
1
2
3
========================================
name James
address NY
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'''

기본매개변수가 가변매개변수보다 앞에 올때

def my_func(num=1, *values):
    # num 횟수만큼 반복
    for i in range(num):
        # values 안에 있는 데이터를 반복하면서 출력
        for value in values:
            print(value)
        print()
my_func(2,'오늘은','함수 부분을','배워봅니다')    

'''
오늘은
함수 부분을
배워봅니다

오늘은
함수 부분을
배워봅니다
'''


def my_func(*values, num=2):
    # num 횟수만큼 반복
    for i in range(num):
        # values 안에 있는 데이터를 반복하면서 출력
        for value in values:
            print(value)
        print()
my_func('오늘은','함수 부분을','배워봅니다',num=3)
'''오늘은
함수 부분을
배워봅니다

오늘은
함수 부분을
배워봅니다

오늘은
함수 부분을
배워봅니다
'''

코드 라인이 없을 때는 함수 선언으로만

def func2(*values, a=10, b=20):
    print(values, a,b)
func2(1,2,3,4,5) # (1, 2, 3, 4, 5) 10 20

def func3(a=10, b=20,*values):
    print(a,b, values)
func3(1,2,3,4,5) # 1 2 (3, 4, 5)

람다함수 lambda

최신 프로그램 언어는 '함수'라는 기능을 '매개변수'처럼 전달하는 코드를 많이 사용한다.
파이썬에서는 이런 기법을 람다 기능으로 제공한다.

함수 정의에서 발생할 수 밖에 없는 코드 블락 작성과 코드 작성을 위한 공간이 낭비된다는 생각을 개발자들이 하게 되었고 그래서 람다라는 개념이 생겨났다.

람다는 함수를 보다 쉽게 선언하고 정의하는 방법 이다.

 

lambda 매개변수 : 리턴값(코드구현)

  • 이름없는 익명함수
  • 함수 정의에서 def 대신에 lambda 키워드를 사용
  • 한줄로 작성한다
# 람다함수 선언
power = lambda x : x * x
under_3 = lambda x : x<3
print(power(3)) # 9
print(under_3(3)) # False
# 위의 람다 형식을 함수로 변환
def double2(x):
    return x*x
print(double2(3)) # 9
# 람다식 표현
a = lambda x : x * 2
print(a(2)) # 4
# 매개변수 지정해서 함수 선언
g = (lambda x:x*x)(3)
print(g) # 9

람다식 표현도 함수처럼 다수의 매개변수를 받을 수 있다.

a = lambda x, y : x * y
print(a(1,2)) # 2

a = lambda x, y, z : x + y -z
print(a(10,2,7)) # 5

a = lambda x, y, z : x + y -z
print(a(y=10,z=2,x=7)) # 15

 

람다함수 안에서 조건문을 걸어줄 수 있다

a = lambda x, y : x * y if x>0 else y
a(3,4) # 12
a(-3,4) # 4

a = lambda x : x * 10 if x<2 else (x**2 if x <4 else x+10)
a(1) #10
a(3) # 9

 

map, filter, zip 함수

map

map() 함수는 리스트 요소를 넣고 리턴되는 값으로 새로운 리스트를 구성해주는 함수기능

  • map(함수, 리스트)
  • map(a,b) - b 리스트 값을 a 함수패턴으로 매핑시키는 기능

filter

리스트의 요소를 함수에 넣고
해당 조건을 만족하는 데이타만 필터링 해서 가져온다

  • filter(함수, 리스트)
  • filter(a,b) - b 리스트 값을 a 함수 조건을 만족하는 요소만 리턴함
sample = list(range(1,11))
sample # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

a = map(str,sample) # map 함수로 매핑한 후
list(a)    # list()함수로 변환
list(map(float, sample)) # [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
list(map(bool, sample))  # [True, True, True, True, True, True, True, True, True, True]
def power(value):
    return value * value

def under_3(value):
    return value<3

# 변수
list_input = [1,2,3,4,5]

# map() 사용
result_map = map(power, list_input)
print(list(result_map)) # [1, 4, 9, 16, 25]

result_map2 = map(under_3, list_input)
print(list(result_map2)) # [True, True, False, False, False]

result_map2 = filter(under_3, list_input)
print(list(result_map2)) # [1, 2]

 

  • map에 람다함수를 매핑
list_input = [1,2,3,4,5]
result = map(lambda x : x*2, sample)
list(result) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
  • map에 multi parameter를 넘겨줄 수 있다
sample = [1,2,3,4,5,6,7,8,9,10]
sample2 = [2,13,4,56,7]
list(map(lambda x,y: x+y, sample, sample2)) # [3, 15, 7, 60, 12]
# 매개변수로 넘겨진 리스트 개수가 달라고 길이가 작은 것을 기준으로 연산
  • filter에 람다함수를 매핑
list(filter(lambda x : True if (x>5) else False, sample)) # [6, 7, 8, 9, 10]

 

zip

  • zip은 원래 압축파일로 익숙한데 그 개념과는 다르다.
  • map이나 filter보다는 더 중요하게 사용되는 기능
  • 여러 샘플 데이타들 중에서 같은 인덱스끼리 그룹을 만들어 주는 기능
pro_number = [111,222,333]
pro_maker = ['notebook', 'smartphone', 'tv']
pro_price = [200, 80, 560, 220, 340000]

print(list(zip(pro_number, pro_maker))) # [(111, 'notebook'), (222, 'smartphone'), (333, 'tv')]
print(type(zip(pro_number, pro_maker))) # <class 'zip'>
print((zip(pro_number, pro_maker))) # <zip object at 0x000001B576472140>

list(zip(pro_number, pro_price)) # [(111, 200), (222, 80), (333, 560)]

list(zip(pro_number, pro_price, pro_maker)) # [(111, 200, 'notebook'), (222, 80, 'smartphone'), (333, 560, 'tv')]

 

zip을 활용한 딕셔너리 만들기

ssn = [7788,      1234,     6790]
name = ['강호동','민경훈','이상민']

my_dic = {}

for s,n in zip(ssn, name):
    my_dic[s]=n
print(my_dic) # {7788: '강호동', 1234: '민경훈', 6790: '이상민'}

for i in range(len(ssn)):
    my_dic[ssn[i]] = name[i]
print(my_dic) # {7788: '강호동', 1234: '민경훈', 6790: '이상민'}

 

이터레이터 객체의 정의

  • 순회 가능한 객체의 요소를 순차적으로 열거하도록 하는 객체
  • 리스트, 튜플, 문자열처럼 순회 가능한 시퀀스 형식에는 구현되어 있음

enumerate()   리스트 내부의 것을 열거하는 기능

# enumerate()
for i, v in enumerate([1,2,3,4,5]):
    print("{}번째 요소는 {} 입니다.".format(i,v))
'''
0번째 요소는 1 입니다.
1번째 요소는 2 입니다.
2번째 요소는 3 입니다.
3번째 요소는 4 입니다.
4번째 요소는 5 입니다.
'''

iter()  이터레이터 객체 만들기

next()  함수를 통해 호출하면 첫번째 리턴하고 다음번 방에 있는 값을 리턴하며, 값이 없으면 순회 작업이 중단

s = 'abc'
it = iter(s)
print(it)  # <str_iterator object at 0x00000222F6B3C5B0>
print(next(it)) # a

댓글