본문 바로가기
SSAFY

[수업기록] 파이썬 함수의 모든 것

by 주니코니 2024. 7. 17.

240717 파이썬반

 

1. 함수를 왜 쓸까?

def 함수 : 재사용을 위함. 가독성. 유지 보수.

(인자값만 바꿔서 재사용 가능)

 

2. 함수의 구조

input x , output f(x)

input == parameter

output == return value

함수란 논리적인 어떤 결과를 내는 것이다

 

3. 함수의 정의

def(ine) 키워드로 시작함

return == 종료시점 #모든함수는 동작 원리상 return None 자동 출력됨 ✔✔✔

# def 뒤 함수이름(매개변수==input 몇개인가):

def greet(name) : 

    """입력된 이름 값에 

        인사를 하는 메세지를 만드는 함수""" 
        #docstring(설명서) #써도되고선택임

   return message #return은 반드시 작성이 필요한 것은 아니다 
   #return == 종료시점 #모든함수는 동작 원리상 return None 자동 출력됨 ✔✔✔
   
   
result = greet('Alice') # call : 호출 #greet() #호출된 반환값이 result에 할당됨
독스트링은 함수 선언 시, def 바로 다음 줄에서 시작해서 첫 줄에는 함수의 목적을, 
다음 단락부터는 세부적인 함수의 동작에 대한 설명이나 인자, 반환 값 그리고 
외부에서 처리되어야 하는 예외에 대해서 설명하는 주석을 말함
(*함수 뿐만 아니라 나중에 배울 클래스, 패키지등 설명할때도 사용)

 

으 아래 헷갈려 ✔ ✔ ✔ ✔

def make_sum(p1, p2):

    return p1 + p2

result = make_sum(3, 4)

return_value = print(result)
print(return_value) #None #print()는 return이 없는 함수이다 ✔✔✔✔ 
#즉 리턴과  출력은 다른 개념이다 ✔✔✔✔
def my_func():
    print("bye")
    
result = my_func()
print(result)
#bye
#none

 


4. 매개변수와 인자

매개변수 : 정의할 때 쓸 수 있음. 정의할 때 함수가 받을 값을 나타내는 변수임 (parameter)

인자 : 함수를 호출될 때 실제로 전달되는 값 (argument)

매개변수 != 인자

def add_num(x,y): #x, y는 매개변수
	result = x+y
    return result
    
a = 2 
b = 3
sum_result = add_num(a,b) #인자
print(sum_result)

 

 

그리고 다양한 인자 종류가 있는데..

 

1) 위치인자( positional argument)

 위치에 따라 결과에 영향을 주는 인자로 위치인자는 함수 호출 시 반드시 값 전달 필요 ✔

def greet(name, age):

	print(f'안녕하세요, {name}님, {age}살이시군요')
    
greet('Harry', 24)
#안녕하세요, Harry님, 24살이시군요
greet('Harry') # TypeError: greet() missing 1 required positional argument: 'age'
greet(29, 'Harry') #안녕하세요, 29님, Harry살이시군요

 

2) 기본 인자값(default argument values)

함수 정의에서 매개변수에 기본값을 할당하는 것

함수 호출시 인자를 전달하지 않으면 기본값이 매개변수에 할당됨

def greet(name, age= 30):
	print(f'안녕하세요, {name}님, {age}살이시군요')

greet('Harry')
#greet('Harry', 24) #사용자 입력값으로 대체

 

3) 키워드 인자

함수 선언시 인자의 이름과 함께 값을 전달하는 인자

함수 선언시 꼭 위치 인자 뒤에 위치할 것 ✔✔✔✔✔✔✔✔✔✔✔✔✔✔✔✔

-키워드 인자 : 순서 상관없음(장점)

def greet(name, age= 30):
	print(f'안녕하세요, {name}님, {age}살이시군요')
 
#greet(name = 'Harry', age = 23)
greet(age =34, 'Harry') #오류
#greet(age =34, name = 'Harry')# 키워드 인자 : 순서 상관없음(장점)
#greet('Harry')

 

 

4) 임의의 인자 목록(0개 이상)

함수 정의시 매개변수 앞에 *를 붙여 사용, 여러개 인자를 (안전하게) tuple로 처리

*tuple : 개발자가 직접 쓰기보다 파이썬 내부적으로 동작할 때 쓰이는 dtype

*print()도 임의의 인자 목록을 지님 -> 그렇기에 몇개를 넣어도 출력되는 것 

# 4. Arbitrary Argument Lists
def calculate_sum(*args):
    print(args)
    print(type(args))

calculate_sum(1,100,50000, 2000, 30)

#(1, 100, 50000, 2000, 30)
#class 'tuple'>

 

아래 주의

-위치 인자가 앞에 올 것

# 4. Arbitrary Argument Lists
def calculate_sum(*args,params): #틀림 #위치인자는 앞으로 올것
    print(args)
    print(type(args))

calculate_sum(1,100,50000, 2000, 30)

# 4. Arbitrary Argument Lists 
def calculate_sum(params,*args): #위치인자는 앞으로 올것 # 1이 위치인자가 됨  ✔ ✔ ✔ ✔ ✔ ✔ ✔
    print(args)
    print(type(args))
    print(params)

calculate_sum(1,100,50000, 2000, 30)


#(100, 50000, 2000, 30)
#<class 'tuple'>
#1

 

 

5) 임의의 키워드 인자 목록

함수 정의시 매개변수 앞에 **를 붙여 사용, 여러개의 인자를 dict로 묶어 처리

# 5. Arbitrary Keyword Argument Lists
def print_info(**kwargs):
    print(kwargs)
    
print_info(name='David', age = 20) #key,value 입력
    #{'name': 'David', 'age': 20}

 

 

6) 함수 인자 권장 작성순서

위치 -> 기본 -> 가변 -> 가변 키워드

*매번 모든 인자를 다 쓰진 않음

# (굳이) 인자의 모든 종류를 적용한 예시
def func(pos1, pos2, default_arg='default', *args, **kwargs):
    print('pos1:', pos1)
    print('pos2:', pos2)
    print('default_arg:', default_arg)
    print('args:', args)
    print('kwargs:', kwargs)


func(1, 2, 3, 4, 5, 6, key1='value1', key2='value2')
# pos1: 1
# pos2: 2
# default_arg: 3
# args: (4, 5, 6)
# kwargs: {'key1': 'value1', 'key2': 'value2'}

 


5. 재귀 함수

자기자신을 그냥 호출하면 무한반복이 된다

그래서 종료될 수 있게 n-1,  팩토리얼을 쓰는것 

*근데 팩토리얼 없이도 물론 쓸 수 있음. 

- 상황에 따라 반복문보다 코드 간결해짐

def factorial(n):
	if n==0: #종료조건
    	return 1
    else:
    	return n*factorial(n-1)
        
print(factorial(3)) # 6
#3*f(2) == 3*2*1*1 
#2*f(1) 
#1*f(0)

 

6. 내장 함수(Built-in function : 이미 준비된, built in)

ex. print(), len(), min(), sum(), sorted(reversed= True *키워드인자)  

 

-유용한 내장함수 : 

1) map : 

map(function, iterable)

iterable : 반복가능한 객체(ex. collection : 리스트, 튜플, 딕셔너리 등)

iterable 요소 하나하나에 function 적용하게 하는 map()

function : 내가 새로 정의한 함수도 포함 -> 확장성 어마어마~

 

2) zip : ✔ ✔ ✔ ✔ ✔ ✔

zip(*iterables) -> (반복이 가능한 친구들을) 임의의 인자로 받는군

(파이썬이 임의로 묶는) 튜플로 반환

 

그럼 언제 쓸까 ? 

- 여러 개의 리스트 동시에 조회할 때

scores = [
    [10,20,30],
    [40,50,29],
    [30,20,13]
    ]
    # 행렬에서 열끼리 작업이 필요할 때

for score in zip(*scores):

    print(score)

 



7. python의 범위(scope)

함수 코드 내부에 local scope, global scope 개념을 살펴보자

 

-범위와 변수 관계 

-scope : 

1) global scope : 코드 어디에서든 참조 가능한 공간

2) local scope : 함수가 만든 scope(함수 내부에서만 참조 가능)

*함수 내에서 바깥 scope에 접근은 가능하나 수정 불가 ✔

def func():
	num =30
    print('local', num) #local 30

func()

print('global', num) #NameError, num is not defined

 

예제 하나 더

num = 0  #global

def increment():
    global num  #num을 전역변수로 선언해준 것
    num += 1

print(num)  # 0 # 아직 함수실행안함

increment()# 함수실행

#print(num)  # 1

 

아래 답 모게?????????? ✔                

a = 1
b = 4

def enclosed():
    a = 10
    c = 3

    def local(c):
        print(a, b, c)  #

    local(500)
    print(a, b, c)  #


enclosed()

print(a, b)  #

 

더보기

# 10 4 500 #내부에 없으며 한단계씩 위로 찾아감!!

# 10 4 3

# 1 4 #작은 쪽 영역에서 찾진 않는다!!

 

이건 답 모게

a = 1
b = 4

def enclosed():
    global a
    a = 10
    c = 3

    def local(c):
        print(a, b, c)  #

    local(500)
    print(a, b, c)  #


enclosed()

print(a, b)  #
더보기
10 4 500
10 4 3
10 4

 

-'global' 키워드

-내부에서 global로 선언시 전역 범위로 사용 가능

단,

1) 키워드 선언 전에 참조 불가 ✔ ✔ ✔ ✔ ✔ ✔

2) 매개변수로 global 키워드 사용 불가

#%%
num = 10

def increment():
    print(num) #SyntaxError: name 'num' is used prior to global declaration
    global num # 값을 바꾸려할 때 선언
    num = 3
    
increment()
print(num)

#%%
num = 10

def increment():
    print(num) #10
    #global num #참조만 하려면 global 안써도 됨, 값을 바꾸려할 때 선언
    #num = 3
    
increment()
print(num) #10

#%%
num = 10

def increment():
    #print(num) #10
    global num #바꿀게요 선언
    num = 3
    
increment()
print(num)
# 3

다른 예제

# map : iterable(리스트)한 객체를 통해 새로운 iterable(리스트)를 만들고 싶을때 
names = ['홍길동', '임꺽정', '김무아']
ages = [20,30,25]

# 딕셔너리 형태로 바꿔서 리스트로 저장
no = 0
def create_user(name, age):
    global no # 0으로 바꾸고 ✔ ✔  ✔ ✔
    no += 1 
    return {'번호':no, '이름':name, '나이':age}
members = list(map(create_user, names, ages))
print(members)

8. packing, unpacking

packing : 여러개의 값을 하나의 변수에 묶어서 담는 것 

1)  변수에 담긴 값들은 튜플 형태로 묶임 -> 파이썬 자체적 

2) *을 활용한 패킹

packed_values = 1,2,3
print(packed_values) #(1,2,3)

 

아래 *는 *b는 남은 요소들을 리스트로 패킹하여 할당 ✔ ✔

num = [1,2,3,4,5]
a , b* ,c = num
print(a) # 1
print(b) # [2, 3, 4]
print(c) # 5

 

함수로 표현해보면

def my_func(*obj):
    print(obj)  # (1, 2, 3, 4, 5)
    print(type(obj))  # <class 'tuple'>


my_func(1, 2, 3, 4, 5)
# (1, 2, 3, 4, 5)
# <class 'tuple'>

 

 

unpacking

1) 예제

packed_values = 1,2,3,4,5,6

a,b,c,d,e,f = packed_values

print(a,b,c,d,e,f)

 

2)  *는 리스트 요소(반복 가능한 객체)를 언패킹해서 인자로 전달 ✔ ✔ ✔ ✔

def my_func(x,y,z):

    print(x,y,z)
    
names = ['a', 'b'. 'c']

my_func(*names) #a b c

 

3) **을 활용한 언패킹     

딕셔너리 키-값 쌍을 언패킹하여 함수의 키워드 인자로 전달

def my_func(x,y,z):

    print(x,y,z)
    
names = ['a', 'b', 'c']
names2 = {'z':'c', 'x':'a', 'y':'b'} #딕셔너리일때는 키값과 매치되는 거라 순서가 상관없음

my_func(*names) #a b c
my_func(**names2) #a b c

 

9. 람다 표현식

1) 익명 함수를 만드는 표현식

2) 한줄로 간단한 함수를 정의

 

lambda 매개변수 : 표현식

*매개변수 여러개일땐 , 쉼표로 구분

*표현식 : return 포함

def add(x,y):

return x_y

result = add(3,2)
print(result) # 5

 

짜자잔

add = lambda x, y : x+y

result = add(3,2)
print(result) #5

 

어라 간결해보이지도 않는데 언제 씀? ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

1) map 함수와 함께 씀

2) 일회성 함수로 씀(def 함수는 재사용 가능이 특징)

 

예제 ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

#%%
# 람다 활용
radius =[1,2,5, 10] # 반지름 리스트
print(sorted(radius)) #오름차순 정렬
print(sorted(radius, reversed = True)) # 내림차순

# 원의 넓이 순으로 정렬
print(sorted(radius, key=lambda r:r**2*3*14))
# 람다식으로 정렬 조건 만들 수 있다
#사각형 예제
rects = [(1,2), (3,3), (1,1), (10,9)] #[(가로, 세로),]
print(sorted(rects)) #가로길이순 정렬
print(sorted(rects, key=lambda rect: rect[1])) #세로 길이순 오름차순 정렬
print(sorted(rects, key=lambda rect:rect[0]*rect[1])) #사각형 넓이순 정렬
# 정렬 조건 세분화 가능
# 정렬값이 동일한 경우 그 다음 정렬 조건으로 설정
# ex. 가로 길이 오름차순으로 정렬(가로길이 동일하면 세로 길이 내림차순 정렬)

print(sorted(rects, key=lambda rect:(rect[0], -rect[1])))
#원본 리스트 수정 여부 
rects.sort() #원본 리스트를 정렬
print(rects)
print(rects.sort()) #None # return 값 없음
#.sort() : 메소드 # sorted : 함수

헷갈리는 거 수업복습

#1. split() 내장함수
# string.split(seperator, maxsplit)
# str에 적용되는 함수
# 구분자를 기준으로 나눠서 리스트로 전환

# 1) .split() : 아무런 파라미터 넣지 않고 실행시, 띄어쓰기 혹은 개행문자에 맞춰 분할
ex = 'a b c d'.split()
print(ex)  #['a', 'b', 'c', 'd']

# 2) 예제 
ex1 = int(343).split()
print(ex1)
#AttributeError: 'int' object has no attribute 'split'

ex2 = str(343).split()
print(ex2) #['343']

ex3 = 'hello world'.split(' ')
print(ex3) #['hello', 'world']

ex4 = '1a2a34da5a23'.split('a')
print(ex4) 
# 내 답 ['1', 'a', '2', 'a', '34d', 'a','5', 'a', '23']
# 정답 ['1', '2', '34d', '5', '23']

ex5 = 'apple.banana.grape'.split('.',1) #구분자, 최대분할횟수
print(ex5)


# 3) .map()와 함께 쓸 때
# .map(함수, 리터러블)
num_1, num_2 = map(int, input().split())
print(num_1)
print(num_2)

num_3 = list(map(int, input().split()))
print(num_3)


## ------

#2. zip 내장함수
scores = [
    [10,20,30],
    [40,50,29],
    [30,20,13]
    ]

#행렬에서 열끼리 작업이 필요할 때 
for score in zip(*scores):

    print(score)
    #(10, 40, 30)
    #(20, 50, 20)
    #(30, 29, 13)



# ---

#3. 함수 (global 변수 )
pro_num = 10
global_data = {'subject': '김해준의 실용연기학원', 'day': 3, 'title': '안자는척 하기'}

def create_data(subject, day , title =None):
    global pro_num 
    pro_num += 1
    data = {'과목' : subject ,'일차' :  day, '제목' : title, '문제 번호' : pro_num}
    return data

result_1 = create_data('python',3)
print(result_1)

result_2 = create_data('web', 1, title = '몰래 많이먹기 액팅' )
print(result_2)

result_3 = create_data(**global_data)
print(result_3)


#{'과목': 'python', '일차': 3, '제목': None, '문제 번호': 11}
#{'과목': 'web', '일차': 1, '제목': '몰래 많이먹기 액팅', '문제 번호': 12}
#{'과목': '김해준의 실용연기학원', '일차': 3, '제목': '안자는척 하기', '문제 번호': 13}

 

global 변수 선언이 헷갈린다..