len('happy!')
word = 'happy!'
cnt = 0
for char in word:
cnt += 1
len()과 cnt는 같은 기능이다.
하지만, 약간 다르다.
무엇이 다를까? 우리는 왜 함수를 사용할까?
- Decomposition
- 기능을 분해하고 재사용이 가능하다.
# 변수들이 선언된 코드
# 반복문을 통해 합과 카운트를 같이 진행한다.
numbers = [1, 10, 100]
result = 0
cnt = 0
for number in numbers:
result += number
cnt += 1
print(result/cnt)
# 함수를 사용한 코드
print(sum(numbers)/len(numbers))
두 코드를 비교하면 함수를 사용한 코드가 더욱 편리해지고 간결해지고 재사용이 용이해진다.
- Abstraction(추상화)
- 복잡한 내용을 숨기고, 기능에 집중하여 사용한다.
- 블랙박스
- 재사용성, 가독성, 생산성을 높인다.
추상이란? 뽑아낸다 라는 뜻이 있다. 어떠한 부분만 뽑아서 보는 의미이다.
name = '파이썬'
name에 파이썬이란 문자열을 변수로서 할당하며 사용하고 있다.
어떠한 객체 정보와 주소가 컴퓨터 메모리 상에 저장되어 있다.
우리는 메모리에 대한 이해 없이 '파이썬'의 타입과 name이라는 이름을 붙여 편리하게 사용하고 있다.
즉, 수없이 많은 데이터들을 복잡한 내용에 대한 이해 없이 이름을 붙여 편리하게 사용하고 있다.
이러한 상황을 추상화라고 부를 수 있다.
함수의 정의
함수란?
특정한 기능을 하는 코드의 조각(묶음)이다.
코드를 매번 다시 작성하지 않고, 필요할 때에 호출하여 간편하게 사용하는 것이다.
사용자 함수 (Custom Function)
사용자가 직접 함수를 정의하고 사용하는 것이다.
def function_name
# 기능
return retuting_value
함수를 사용해야 하는 이유
- 코드를 한 눈에 알아볼 수 있도록 하기 위함이다.
- 재사용이 용이하다.
- 코드 중복 방지를 위한다.
기본 구조
- 선언과 호출(define & cell)
- 입력(Input)
- 범위(Scope)
- 결과값(Output)
선언과 호출
- def (definition) 키워드를 활용한다.
- 들여쓰기해서 funtion body를 작성한다.
- parameter를 넘겨줄 수 있다.
- 함수명()으로 호출한다.
- return으로 결과값을 전달한다.
# 함수를 정의한다.
def add(a, b): # Input으로 2개의 숫자를 받아서
return a + b # 더한 값을 반환한다.
# 반환 후 함수가 종료된다.
add() # 호출
정의한 후 여러번 호출하며 사용할 수 있다.
# 예시 1
num1 = 0
num2 = 1
def func1(a, b):
return a + b # 0 + 5
def func2(a, b):
return a - b # 5 - 1
def func3(a, b):
return func1(a, 5) + func2(5, b) # (0, 1) 첫번째로 봐야한다. # 5 + 4
#0, 5 5, 1
print(result)
함수의 결과값 (Output)
- 함수는 반드시 값을 하나만 return한다.
- return할 값이 없는 경우 None을 반환한다.
이 코드의 문제점은?
def minus_and_product(x, y):
return x - y # 함수를 실행하고 여기서 return하기 때문에 여기서 종료된다.
return x * y # 도달할 수 없는 코드이기 때문에 실행되지 않는다.
그렇다면 return문을 사용해서 두개의 값을 반환하는 방법은?
def minus_and_product(x, y):
return x - y, x * y #하나의 튜플을 반환하는 것이다.
def no():
a = 1
result = no()
print(result, type(result)) # 출력하긴 했지만, nonetype이다.
# print 함수는 출력을 해주고 return 값은 없다. (None type)
return은 함수 안에서 값을 반환하기 위해 사용되는 키워드이고,
print는 출력을 위해 사용되는 함수이다.
함수의 입력(Input)
- Parameter
- 변수의 이름을 지어주는 것
- 함수 내부에서 사용되는 식별자
- Argument
- 호출이 되면서 넘어가는 값
- 호출 시 넣어주는 값
def function(ham): # parameter: ham
return ham
function('spam') # argument: spam
Argument란?
- 함수 호출 시 함수의 parameter를 통해 전달되는 값을 의미한다.
- 필수 Argument: 반드시 전달되어야 하는 Argument
- 선택 Argument: 반드시 전달되지 않아도 되는 Argument
- positional argument (기본)
위치로 파악하는 것이다.
def add(x, y):
return x + y
add(2, 3)
# x, y = 2, 3 으로 이해할 수 있다.
- **keyword arguments**
def add(x, y):
return x + y
add(x = 2, y = 5) # -> keyword
add(2, y = 5)
`add (x=2, 5)` 는 사용할 수 없다. 키워드를 쓰게되면 뒷 부분은 위치를 못쓰기 때문이다.
즉, keyword argument 다음에는 positional argument를 사용할 수 없다.
- **Default Arguments Value**
기본값을 지정하여 함수를 호출하면 argument 값을 설정하지 않도록 하는 것이다.
def add(x, y=0): # y=0: 기본값 설정
return x + y
add(2)
# 결과: 2
정해지지 않은 개수의 Keyword Arguments
함수가 임의의 arguments 개수를 받아서 keyword arguments로 호출되도록 지정하는 것이다.
def my_func(**kwargs):
return kwargs
result = my_func(name='홍길동', age='100', gender='M')
print(result, type(result))
key와 value를 쌍으로 넘겨주기 때문에 **딕셔너리** 타입이다.
**는 묶어주는 역할로 사용하는 기호로 생각하면 된다.
함수의 범위 (Scope)
함수는 코드 내부에 local scope를 생성하며, 그 외의 공간은 global scope이다.
- global scope
- 코드 어디에서든 참조할 수 있는 공간
- local scope
- 함수 내부에서만 참조 가능
def foo():
a = 1
foo()
print(a)
# 오류가 발생한다.
# 함수는 def foo(), a=1에 대한 공간이 있다. local 공간에 있는 것이다.
# 함수 밖에서는 a라는 것이 없으니까
# 즉, global 공간에는 a라는 정보가 없으니 출력할 수 없다.
객체 생명주기
- built-in scope
- 이미 내장되어 있는 것
- 영원히 유지된다.
- print, sum, len
- global scope
- 모듈이 호출된 시점 이후 혹은 인터프리터가 끝날 때까지 유지한다.
- a = 3 과 같이 직접 정의한 것
- local scope
- 함수 종료 후 없어진다
이름 검색 규칙 (Name Resolution)
이름을 탐색하는 규칙이 있다.
LEGB Rule 이라고 부른다.
- Local scope: 함수
- Enclosed scope: 특정 함수의 상위 함수
- Global scope
- Built-in scope
가장 안쪽에 있는 local부터 찾는다.
함수 내에서는 바깥 scope의 변수에 접근이 가능하지만 수정할 수 없다.
sum = 5
print(sum([1, 2, 3]))
# 오류가 발생한다.
# Built-in scope에 sum 함수가 있다. global scope에 sum 이름의 변수를 만들었다.
# global을 먼저 불렀기 때문에 (L -> E -> G -> B) 이후 빌트인 함수를 부를 수 없게 되는 것이다.
map
특정한 함수를 반복적으로 적용하고 싶을 때 활용한다.
**반복 가능한 객체(것)들의 모든 요소에 각각 특정 함수를 적용한 결과들로 구성된 것으로 나타내려고 하는 것이다.**
예시 1.
numbers = ['1', '2', '3']
# 숫자로 바꿔서 쓰고싶다면
n = int(numbers) # 안된다. 리스트를 숫자로 바꿀 방법은 없다. 다만, 숫자 형태의 문자를 변환할 수 있다.
a = int(numbers[0])
b = int(numbers[0])
c = int(numbers[0]) # 가능하지만 100개, 1000개를 일일이 다 할 수 없다.
new_numbers = [a, b, c] # 숫자로 타입이 변경된다.
# 반복문을 활용하자
numbers = ['1', '2', '3']
print(numbers)
new_numbers = []
for number in numbers:
new_numbers.append(int(number))
print(new_numbers)
# map을 활용하자
numbers = ['1', '2', '3']
new_numbers_2 = map(int, numbers) # 적용하고 싶은 타입과 함수를 정한다.
print(new_numbers_2) #이미 함수가 모두 적용되었다.
print(list(new_numbers_2)) #리스트로 형 변환해서 보면 바뀌어있다.(반드시 리스트로 바꿔야 하는 것은 아니다.)
예시 2.
# 직사각형의 넓이를 구하시오. 직사각형 세로는 n, 가로는 m이다.
# input으로 10 20을 넣는다.
n,m = map(int, input().split())
print(n*m)
# input(): 타입은 항상 문자열이다.
# .split(): 구분값을 기준으로 쪼개겠다는 의미이다. 반환 결과는 항상 리스트이다.
# input().split():'문자열로 받을 것을 각각의 공백을 기준으로 리스트로 쪼개겠다'
# map(...): 어떤 함수를 반복 가능한 것들의 요소에 모두 적용시킨 결과를 의미한다. 즉, int함수를 input().split() 리스트의 모든 요소에 적용한 결과이다. 결과는 map opject(맵 어떤 것)
# 결과적으로 n, m = [10, 20]이다.
예시 3.
# 내장함수를 10을 다 더해주는 함수가 있다고 가정해보자.
def plus10(n):
return n + 10
numbers = [10, 20, 30]
new_numbers = list(map(plus10, numbers)) #list로 출력하기 위해
print(new_numbers)
# 출력 결과: [20, 30, 40]
예시 4.
# 방법 1
a, b = input().split()
c = int(a)-int(b)
print(c)
# 방법 2
a, b = map(int, input().split())
print(a-b)
input().split()의 결과인 리스트의 모든 요소에 각각 int 형변환 함수를 적용한 결과로 구성된 것을 만들어주는 것이 map이다.
(split()은 문자열을 공백 단위로 쪼개서 리스트로 바꿔준다. a와 b의 값 입력 시 한줄로 값을 입력하기 위할 때 사용한다.)
다시 말해, Map은 특정한 함수를 반복적으로 적용하고 싶을 때 사용하는 것이다.
즉, 반복적으로 사용하는 것(객체)들을 묶어서 한번에 특정 함수로 적용하게 하는 것이다.
위 예시들을 통해 map()은 코드의 양을 효과적으로 줄일 수 있다.
또한, 어떤 함수든 모두 적용할 수 있다.
'Python' 카테고리의 다른 글
프로젝트 정리 - JSON, 모듈, 파일 읽고 쓰기 (00-03) (2) | 2022.07.15 |
---|---|
데이터의 구조 (Data Structure) (0) | 2022.07.14 |
제어문 (Control Statement) - 반복문과 조건문 (0) | 2022.07.12 |
Python 개념 - 컨테이너 (0) | 2022.07.11 |
Python의 개념 및 기초 문법 (0) | 2022.07.11 |