Data_Analysis_Track_33/Python

Python_04(함수)

lsc99 2023. 8. 18. 19:58

함수 : 사용자 정의 연산자라고도 한다. 연산처리결과를 반환한다.  
함수 -> 우리가 정의하는 연산자 -> 피연산자(parameter), 처리결과(return value)
변수를 생성 -> 변수 초기화 -> 변수 정의 : 파이썬 실행환경에 이 변수를 등록하는 작업
함수도 정의(define)한 뒤에 사용할 수 있다. -> 정의된 함수를 사용하는 것을 호출(call)한다라고 한다.

함수의 정의 : 새로운 함수를 만드는것.  (함수를 구현 -> 파이썬 실행환경에 새로운 기능으로 등록하는 과정을 말한다.)
구문 : def 함수이름([변수, 변수, 변수, ...]): # 선언 부(Header), 변수들 = Parameter
# 구현 부(Body)
실행구문1
실행구문2
실행구문3
...
[return [결과값]]  # 함수의 처리결과값이 없는 경우 return구문을 생략할 수 있다. (결과값의 defalut = None)

함수의 선언부(Header) : 함수의 이름과 입력값을 받을 변수(Parameter, 매개변수)를 지정한다. ( : 으로 선언부와 구현부를 구분한다.)
함수의 구현부(Body) : 함수가 호출 되었을 때 실행할 실행문들을 순서대로 작성한다. (코드블록 -> 들여쓰기로 블록을 묶어준다.)

# 함수 정의
# 1. 구현
def greet(): # Header(선언부) -> parameter가 없는 함수.
    # 구현부 (들여쓰기) -> 함수 body(block)
    print("안녕하세요.")
    print("반갑습니다.")
# 2. 구현된 함수를 파이썬 실행환경에 등록 -> 함수 구현한 것을 실행하면 됨.

# 함수 호출
# 함수이름({파라미터에 전달할 값들}), 파라미터가 없다면 생략
greet()
print("------------")
greet() # 반복 실행 가능하다.


Parameter(매개변수)는 argument(호출하는 곳에서 전달하는 함수의 입력값)를 받기 위한 변수로 0개 이상 선언할 수 있다.
함수이름은 보통 동사형으로 만든다. (변수 -> 값 : 명사형, 함수 -> 기능 : 동사형)
모두 소문자로 하고 여러단어로 구성할 경우 각 단어들을 _로 연결한다. (변수와 동일) (snake 표기법)
!기본적으로 함수를 호출할 때 parameter와 argument는 개수와 순서가 맞아야 한다.

# 파라미터가 있는 함수
def greet2(name): # 파라미터가 한개.(0개이상 선언 가능.)
    print(f"{name}님 안녕하세요.")
    print("반갑습니다.")
    
names = input("이름을 입력하세요.:")
greet2(names) # 입력받은 names변수(argument) ->  name 파라미터
# 파라미터가 여러개인 함수
def greet3(name, age, address):
    print(f"{address}에 사는 {age}세 {name}님 안녕하세요.") # 순서 맞추기
    print("반갑습니다.")
    
greet3("홍길동", 21, "서울시")
greet3("이순신", 25, "인천")

# 기본적으로 함수를 호출할 때 parameter와 argument는 개수와 순서가 맞아야 한다.
greet3(20, "서울", "홍길동") # 순서가 맞지 않는다.
greet3("이순신", 20) # parameter 3개, argument 2개 -> 에러 발생


return value(반환값) : 함수가 호출받아 처리한 결과값으로 호출한 곳으로 반환하는 값이다.(생략 가능)
정상적으로 끝나 호출한 곳으로 돌아간다는 의미, 만약 문제가 생겼다면 raise(추후에 학습)
함수 구현부에 return [값] 구문을 사용해 반환한다. return 값은 원칙적으로 하나만 가능하다.
return 값이 여러개일 경우 -> 자료구조로 묶어서 반환
! return 결과값이 변경되지 않아야 한다면 tuple 대입 이용, return 결과값이 변경되도 상관 없다면 list 대입 이용

def greet4(name):
    v = f"{name}님 안녕하세요.\n 반갑습니다."
    return v # return 반환값 -> 호출한 곳(caller)으로 반환값(v)를 가지고 돌아간다.
    print("abc") # return 밑으로는 실행되지 않는다. 실행되게 하려면 return 구문 위에 조건문과 같은 구문을 작성한다.
    
ret_value = greet4("홍길동")
print(ret_value)
# return 값은 1개만 가능. (파라미터는 원하는 개수만큼 선언가능.)
# return 값이 여러개일 경우 -> 자료구조로 묶어서 반환
# 사칙연산 처리
def calculate(num1, num2):
    r1 = num1 + num2
    r2 = num1 - num2
    r3 = num1 * num2
    r4 = num1 / num2
    # return [r1, r2, r3, r4] # return 값이 여러개 -> 리스트로 묶어서 반환 
    # return r1, r2, r3, r4 # tuple로 반환 ()생략 
    return {"plus" : r1, "minus" : r2, "multiply" : r3, "divide" : r4}  # 딕셔너리로 반환

result = calculate(10, 5)
result


Parameter(매개변수) : 기본값이 있는 Parameter
함수 정의시 기본값(defalut) 없는 매개변수, 있는 매개변수를 같이 선언할 수 있다.
이때 기본값 없는 매개변수들을 선언하고 그 다음에 기본값 있는 매개변수들을 선언한다.
default값이 있는 parameter들에게도 argument를 넣어줄 수 있다.
구문 : 함수명(매개변수1, 매개변수2, 매개변수3 = 10) -> argument를 입력받지 못한다면 매개변수3의 default값은 10이다.
이 때, 함수 호출할 때 뒤 쪽에 선언한 파라미터에게만 값을 전달하고 싶어도 구문상으로 앞에 선언한 파라미터들에게 값을 전달해줘야 한다 -> 이를 위해 keyword argument가 있다.

def print_info2(name = None): # name : 기본값이 있는 파라미터
    if name: # name is not None
        print(f"이름 : {name}")
    else: # name is None
        print("이름을 입력하세요")
        
print_info2("홍길동") # name = "홍길동"
print("-"*10)
print_info2() # name에 값을 전달안함 -> name = None(default 값)
def print_info(id, password, name, age = 0, weight = 0.0, tall = 0): # 기본값이 없는 parameter 먼저 선언 후 defalut 값을 줄 parameter 선언, defalut 값은 type 제약 받지 않는다.
    print(id, password, name, age, weight, tall)

print_info("id", "password", "name")
print_info("id", "password", "name", 30)
print_info("id", "password", "name", 30, 40, 50) # default 값이 있는 parameter에게도 argument를 줄 수 있다.
# default값이 없는 파라미터들, * , default값이 있는 파라미터들
# parameter에 *는 구분자로 사용
def print_info(id, password, name, *, age = 0, weight = 0.0, tall = 0):
    print(id, password, name, age, weight, tall)
    
print_info(1, 2, 3)
print_info(1, 2, 3, age = 10, weight = 20, tall = 30) # ' 뒤의 파라미터는 이름 = 값 형태로 전달


Positional argument
함수 호출 할때 argument(전달인자)를 Parameter 순서에 맞춰 값을 넣어서 호출.

keyword argument
함수 호출할 때 argument를 Parameter변수명 = 전달할값 형식으로 선언해서 어떤 parameter에 어떤 값을 전달할 것인지 지정해서 호출.
순서와 상관없이 호출하는 것이 가능. -> 원하는 parameter에게만 값을 전달할 수 있다.
parameter가 많고 대부분 기본값이 있는 함수 호출 할 때 뒤 쪽에 선언된 parameter에만 값을 전달하고 싶을 경우 유용하다.
Positional argument와 keyword argument 함께 사용 가능하다. positional 먼저 실행 후 keyword 실행

# Positional argument 사용
print_info()
print_info("my_id") # id 설정
print_info("my_id", "abcde")  # id, password (첫번째, 두번째 파라미터)
print_info(None, None, None, 0, 0, 0, "abc@abc.com") # email만 설정 (뒤쪽에 선언한 파라미터) -> Positional argument 사용시 불편하다.
# email만 설정 (뒷쪽에 선언한 파라미터에 값을 전달. 앞에 선언된 파라미터는 기본값을 사용)
print("-" * 10)
# Keyword argument 사용
print_info(email = 'aaaa@aaaa.com') # 원하는 파라미터에게만 값을 전달
print_info(password = 'asfsdgrh', tall = 181)
print_info(email = 'abc@asf.com', name = "홍길동") # 순서 상관없다.
# positional argument, keyword argument를 같이 사용가능하다. -> positioanl을 먼저 실행하고 keyword를 실행
print_info("my_id", "11111wd", email = "sewgji.com")


가변인자(Var args)파라미터 : argument로 받을 값들이 0 ~ n 개일 때 여러 개의 값들을 tuple이나 dictionary로 묶어서 받을 수 있도록 선언하는 parameter
argument를 0개든 몇개든 다 받아 처리한다.
호출하는 방식이 편하다.
구문 : def 함수명(*파라미터): -> 가변인자(positioanl argument)로 전달되는 인자값의 개수를 상관없이 받는다. (0개 이상)

전달된 값들은 tuple로 받아서 처리한다.
관례적으로 변수명은 *args 를 사용한다.

def 함수명(**파라미터): -> 가변인자(keyword argument) -> 개수 상관없이 전달 받는다.
전달된 값들은 dictionary로 받아서 처리한다.
관례적으로 변수명은 **kwargs 를 사용한다.
하나의 함수에 가변인자는 * 하나, ** 두개짜리 각각 한개씩만 선언할 수 있다.

파라미터 선언순서
1. 기본값이 없는 파라미터
2. 기본값이 있는 파라미터
3. *args
4. **kwargs

# 숫자 값들을 받아서 합계를 반환하는 함수 (positioanl argument)
def summation2(*nums):
        result = 0 # 총합을 저장할 변수
        print(type(nums))
        for v in nums : 
            result += v # result = result + v
        return result
        
print(summation2()) # args : 0
print(summation2(1, 2, 3)) # args : 3
print(summation2(1, 2, 3, 4, 5, 6, 7, 8, 9)) # args : 9
# keyword argument 개수 상관없이 전달 받는다.
def print_info(**user_info):
    print(type(user_info))
    print(user_info["name"], user_info["age"])
    
print_info(name = "홍길동", age = 20)
# 가변인자: 같이 선언. * 먼저 선언하고 다음에 ** 선언, 각각 한개씩만 선언 가능.
def test(*args, **kwargs):
    print(args)
    print(kwargs)
    
test(1, 2, 3, 4, 5, 6, a=10, b=10, t = "abc")
# 일반 파라미터, *가변인자, **가변인자 순으로 나열
def test2(p1, p2, p3, *args, **kwargs):
    print(p1, p2, p3)
    print(args)
    print(kwargs)
    
test2(10, 20, 30, 1, 2, 3, 4, 5, a='가', b='나')


변수의 유효범위(지역변수와 전역변수)
지역변수 : 함수 에 선언된 변수, 선언된 함수 안에서만 사용가능
전역변수 : 함수 에 선언된 변수, 모든 함수들이 사용가능, 모든 함수에 영향을 주기에 변경하지 않도록 한다.
!함수에서 변수를 조회할경우 지역변수를 먼저 찾고 없으면 전역변수를 찾는다.

서로 다른 함수의 지역변수는 각각 다른 메모리 영역(stack memory)에서 처리되기 때문에 이름이 같다할지라도 다른 변수이다.
전역 변수를 함수내에서 변경하는 방법 -> global 변수명 선언 후에 전역 변수 변경(되도록이면 변경하지 말 것)

name = '홍길동' # 전역 변수(global variable)

# 지역변수 : 함수가 실행되는 동안에만 메모리(stack 메모리 영역)에 올라간다.
def fn():
    age = 20 # fn()함수 안에 정의한 변수 -> fn()함수의 지역변수(local variable)
    print(name)
    print(age)
def fn2():
    name = '이순신' # fn2()함수의 지역변수를 정의
    age = 30 # fn2()함수 안에 정의한 변수 -> fn2()함수의 지역변수(local variable)
    print(name)
    print(age)
#  함수 fn()의 age 변수와 함수 fn2()의 age 변수는 다른 변수이다.

def fn3():
    global name # 전역변수 name을 사용하겠다고 선언
                # 전역변수의 값을 변경할 경우 반드시 지정, 지정하지 않으면 지역변수 정의가 된다.
    name = '유재석' # 전역변수를 변경, 되도록이면 전역 변수는 변경하지 않도록 한다.
    print(name)
    
fn()
fn2()
fn3()
fn()


함수는 일급시민(First class citizen)이다.
- 일급 시민
1. 변수에 대입할 수 있다.
2. Argument로 사용할 수 있다.
3. 함수나 메소드의 반환값으로 사용할 수 있다.
ex)my_hello = hello # hello함수를 my_hello란 변수에 할당

람다식/람다표현식(Lambda Expression)
구문 : 변수명 = lambda 매개변수, 매개변수, ... : 명령문(구문)
return을 넣지 않는다. 람다식은 함수의 매개변수로 함수를 전달하는 일회성 함수를 만들 때 주로 사용한다.

f1 = lambda x, y : x + y

print(f1(10,20), f2(10, 20))
f3 = lambda name : name.endswith(".exe") # parameter 1개인 경우
f3('test.exe'), f3('test.jpg')
f4 = lambda x, y : x ** y # parameter 2개인 경우
f4(10,2)


iterable 관련 함수에서 함수를 매개변수로 받아 처리하는 함수들
- sorted(), filter(), map()

list(filter(lambda x : x%2 == 0 , [10, 2, 5, 7, 4])) # 리스트 [10, 2, 5, 7, 4]에서 2의 배수만 추출
l = ['a', 'aa', 'aaa', 'aaaa', 'aaaaa']
print(sorted(l)) # 오름차순
print(sorted(l, reverse = True)) # 내림차순

# 글자수 순서대로 정렬
# 각 원소를 key 함수에 넣어서 반환되는 값을 기준으로 정렬
print(sorted(l, key=lambda x:len(x)))
# map() : iterable의 원소들을 일괄처리
# 글자수를 반환
list(map(lambda x : len(x), l))


함수에 대한 설명이 필요할 때 : 내장함수 -> help(함수명), 
주피터 기능 -> 함수명?, 함수명 + shift + tab

docstring : 함수에 대한 설명, """함수 설명""" -> 구현부에 작성


pass 키워드(예약어) : 빈 구현부를 만들 때 사용한다.
ex) def func():
pass
pass 대신 ...을 사용할 수 있다.
사용할 함수를 형식만 만들고 pass를 이용하면 자동으로 함수 들여쓰기에서 탈출하기에 코드 작성에 유용하다.

중요 부분

함수 : 입력(parameter) -> 함수 정의 -> 출력(return)
값을 제공(positional, keyword argument)
함수는 일급시민 : 변수에 대입할 수 있다, argument로 사용할 수 있다, 함수나 메소드의 반환값으로 사용할 수 있다.
람다식/람다표현식 : 함수를 하나의 식을 이용해서 정의할때 사용하는 표현식
def f(x): # parameter 1개인 경우
return x ** 2를 람다식으로 표현 -> f2 = lambda x : x ** 2, f2(10)
def f3(x, y): # parameter 2개인 경우
return x + y를 람다식으로 표현 -> f4 = lambda x, y : x + y, f4(10, 20)
sorted(), filter(), map()