Python 08. 함수

jonghyuck’s velog·2022년 7월 27일
0

Python 정리

목록 보기
9/12

✅ 함수를 왜 사용할까?
✅ 함수의 종류
✅ 함수의 입력(Input)
✅ 파이썬의 범위(Scope)
✅ 함수 응용

✅ 함수를 왜 사용할까?

  • 함수의 사용 이유는 크게 두가지로 나눌 수 있다.
    • Decomposition(분해)(모듈화)
      • 기능을 분해하고
      • 재사용 가능하게 만든다
    • Abstraction(추상화)
      • 복잡한 내용을 모르더라도 사용할 수 있도록(스마트폰처럼) 재사용성과 가독성, 생산성을 올린다

✅ 함수의 종류

  1. 내장함수
    • 파이썬에 기본적으로 포함된 함수
  2. 외장함수
    • import문을 통해 사용하며, 외부 라이브러리에서 제공하는 함수
  3. 사용자 정의 함수
    • 직접 사용자가 만드는 함수

📍 함수(function)의 정의

  • 특정한 기능을 하는 코드의 조각 혹은 묶음

  • 특정한 코드를 매번 다시 작성하지 않고, 필요시에만 호출하여 간편히 사용

    위 사진과 같이, 함수의 기본 구조에는
    1. 선언과 호출(define & call)
    2. 입력(Input)
    3. 문서화(Docstring)
    4. 범위(Scope)
    5. 결과값(Output)

모든 언어가 공통적이지만, 함수는 크게 4가지로 구분지을 수있다.

  1. 파라미터와 리턴이 없는 경우
  2. 파라미터는 있고 리턴이 없는 경우
  3. 파라미터는 없고 리턴이 있는 경우
  4. 파라미터와 리턴 모두 있는 경우

한참 코딩을 배우는 시기라면 모르겠지만, 자신이 능력있는 개발자로 거듭나고 싶다면 이러한 분류를 잘 알고 사용해야 한다.

  • 1번의 경우는 대부분 print또는 전역변수를 건드릴 때 사용하기 좋지만 실제 개발에서 전역변수를 직접적으로 건들이는 경우는 많이 없기 때문에 단순print용으로 많이 사용한다.
  • 2번의 경우 역시 마찬가지이다.
  • 3번의 경우 파라미터가 없고 리턴이 있다. 이런 경우가 필요할 때가 있을수도 있다. 하지만 이럴경우 대게는 class와 인스턴스를 활용하여 사용하기 대문에 이또한 많이 사용하지 않는다.
  • 4번의 경우가 가장 대표적으로 사용하는 함수이다.

✅ 함수의 입력(Input)

'Parameter'와 'Argument'의 차이를 알고있는가?
대부분의 경우에서 이 두 단어는 비슷하게 사용된다. 하지만 이 둘은 다른 뜻을 지니고 있다.

def function(ham)
	return ham
function('spam')
여기에서 1번째 줄에 ham은 파라미터, 3번째 줄에 'spam'은 알규먼트이다. 
  • 즉, parameter는 함수를 정의할 때, 함수 내부에서 사용되는 변수이고,
  • argument는 함수를 호출할 때 parameter를 통해 전달되는 값이다.

📍 Positional Arguments

기본적으로 이 argument는 함수 호출시 위치에 따라 함수 내부에 전달된다.
argument의 순서대로 parameter에 대입되는것이다.
하지만, argument의 순서대로가 아닌 특정 변수명을 직접 parameter에 넣고싶다면?

📍 Keyword Argumets

그럴때 사용하는 것이 Keyword Arguments이다.

위 사진과 같이 x,y라는 파라미터에 x=2, y=5를 통하여 keyword argumets를 넣어주었다. 이는 위치가 바뀌어도 상관없이 정해진 파라미터에 들어가게 된다.

하지만 주의해야 할 점은 'Keyword Arguments'와 'Positional Arguments'를 함께 사용할 때 발생한다.

Keyword Arguments 뒤에 Positional Arguments를 넣게되면 
함수는 제대로 인식할 수 없게 된다.

📍 Default Arguments Values

이번엔 Argument에 기본 값을 지정하는 방법을 알아보자.

그렇다면 정해지지않은 여러 개의 Arguments를 처리하기 위해서는 어떻게 해야 할까?

바로, 언패킹 연산자라 불리는 '*'애스터리스크(asterisk)를 사용하면된다.

📍 가변인자(*args)

  • 가변인자란?
    • 여러 개의 Positional Argument를 하나의 parameter로 받는 값이다.
    • 몇 개의 Argument를 받을지 모른다면 유용하게 사용할 수 있는 방법이다.

😬 패킹 / 언패킹

  • 가변 인자를 이해하기 위해서는 먼저 패킹과 언패킹을 알아야 한다.
  1. 패킹
    여러 개의 데이터를 묶어서 변수에 할당하는 것
    numbers = (1,2,3,4,5) # 패킹
    print(numbers) # (1,2,3,4,5)
  2. 언패킹
    시퀀스 속의 요소들을 여러 개의 변수에 나누어 할당하는 것
    numbers = (1,2,3,4,5)
    a,b,c,d,e = numbers # 언패킹
    print(a,b,c,d,e) # 1 2 3 4 5

쉽게 말하자면 패킹과 언패킹은 말 그대로 어떤 변수에 여러개의 값을 묶고 푸는 것이다.
하지만, 여기서도 언패킹시에는 지켜야 할 규칙이 있다.
바로, 변수의 개수와 할당하고자 하는 요소의 갯수가 동일해야 한다는 것이다.
그렇다면 패킹은 아무때나 사용할 수 있고 언패킹은 반드시 갯수를 알아야 사용할 수 있을까? 그렇지 않다.

numbers = (1,2,3,4,5)
a,b,*temp = numbers
print(a,b,temp)
a,*temp,b = numbers
print(a,temp,b)

1 2 [3,4,5]

[2,3,4]

이처럼 *연산자를 사용하면 갯수를 몰라도 언패킹을 진행할 수 있고 이를 응용하면 파라미터에서도 사용이 가능하다.

def print_name(father, mother, *pets):
	print(f'아버지 : {father})
    print(f'어머니 : {Mother})
    print('반려동물들..')
    for name in pets:
    	print(f'반려동물:{name}')
print(print_name('재헌', '상분', '강아지', '고양이')

아버지 : 재헌
어머니 : 상분
반려동물들..
강아지
고양이
None

📍 가변 키워드 인자(**kwargs)

  • 몇 개의 키워드 인자를 받을지 므는 함수를 정의할때 유용
  • 가변인자랑 무엇이 다른가?
    • 가변 키워드 인자는 딕셔너리로 묶어 처리된다.
def print_family_name(father,mother,**pets):
    print('아버지 : ', father)
    print('어머니 : ', mother)
    if pets:
        print('반려동물들..')
        for species, name in pets.items():
            print(f'{species} : {name}')

print_family_name('재헌', '상분', dog = '강아지', cat = '고양이')

아버지 : 재헌
어머니 : 상분
반려동물들..
dog : 강아지
cat : 고양이

✅ 파이썬의 범위(Scope)

  • scope
    • global scope : 코드 어디에서든 참조 가능
    • local scope : 함수가 만든 scope(지역변수)
  • variable
    • global variable : global scope에 정의된 변수
    • local variable : local scope에 정의된 변수

variable의 수명

  1. built-in scope
    • 파이썬이 실행된 이후부터 영원히 유지
  2. global scope
    • 모듈이 호출된 시점 이후 혹은 인터프리터가 끝날 때까지 유지
  3. local scope
    • 함수가 호출될 때 생성되고, 함수가 종료될 때까지 유지

📍 Scope별 변수 탐색 순서

  • 그렇다면 다양한 변수들중 이름이 같다면, 파이썬은 어떤 순서로 변수를 탐색할까?

     이와 같은 순서로 탐색하게 된다.
     1. Local scope
     2. Enclosed scope
     3. Global scope
     4. Built-in scope

함수에서 글로벌 변수에 접근하는 방법

a = 10
def func1():
	global a
    a = 3
print(a) # 10
fuc1()
print(a) # 3

✅ 함수 응용

📍 Built-in Function

map

map(function, iterable)

  • 순회 가능한 데이터구조(iterable)의 모든 요소에 함수 적용을하고, 결과를 반환
n, m = map(int, input().split()) # 3,5 입력
print(n,m) # 3, 5
print(type(n)), type(m)) # <class 'int'> <class 'int'>

filter

filter(function, iterable)

  • 순회 가능한 데이터구조(iterable)의 모든 요소에 함수를 적용하고, 결과가 True인 것들을 반환
def odd(n):
	return n%2
numbers = [1,2,3]
result = filter(odd,nubmers)
print(result, type(result))
# <filter object at 0x000001FB4B217F40>
# <class 'filter>
print(list(result)) # [1,3]

zip

zip(*iterables)

  • 복수의 iterable을 모아 튜플을 원소로 하는 zip object를 반환
girls = ['jane', 'ashley']
boys = ['justin', 'eric']
pair = zip(girls, boys)
print(pair, type(pair))
print(list(pair))

<zip object at 0x105bdd600> <class 'zip'>
[('jane', 'justin'), ('ashley', 'eric')]

📍 재귀 함수

  • 자기 자신을 호출하는 함수
  • 절대 무한한 호출을 하지말것(call지옥)
  • 1개 이상의 base case(종료되는 상황)을 만들고 수렴하도록 작성

왜 재귀를 사용할까?

  • 반복문으로도 재귀함수와 비슷한 역할을 만들 수 있다. 하지만 팩토리얼 또는 2진법 문제와 같이 재귀를 사용시 편한 상황에서는 재귀를 사용한다.

하지만, 재귀를 사용할 때는 항상 주의가 필요하다.

  1. 재귀는 base case에 도달할때까지 호출
  2. 메모리스택을 그만큼 잡아먹는다.
  3. 파이썬에서는 최대 재귀 깊이가 1000번으로 이를 넘어가면 Recursion Error가 발생한다.(물론 편법은 존재)
  4. 재귀 호출은 입력 값이 커질 수록 연산 속도가 오래 걸림
  5. 재귀 호출은 변수 사용을 줄여줄 수 있음

0개의 댓글