파이썬 튜터리얼 정리 4.7 - 함수 정의 더 보기
(인자. 람다. 독스트링. 어노테이션 )
참고)
정해지지 않은 인자들로 함수를 정의하는 것도 가능.
- 3가지 방법이 있음 ( 기본값 / 키워드 / 임의 개수 인자)
- 조합 할 수 있음.
1. 기본 인자 값
- 가장 많이 사용하는 형식으로 하나 이상 기본값을 지정.
- 정의 된 파라미터보다 적은 인자로 함수 호출 가능.
ex)
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
위 함수는 아래와 같이 여러 방법으로 호출이 가능합니다.
- 필수 args만 (여기서 필수 args는 'prompt')
- :
ask_ok('Do you really want to quit?')
- 필수 + 하나 (prompt, retries)
- :
ask_ok('OK to overwrite the file?', 2)
- 모든 인자 (prompt, retries, reminder)
- :
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes orno!')
위 함수에서 'if - in' 키워드도 확인 할 수 있다.
- 시퀀스 안에 in( )값이 있는지 검사
* 함수의 기본값은 정의 시점에 정의되고 있는 스코프에서 구해집니다.
i = 5
def f(arg=i):
print(arg)
i = 6
f()
결과 : 5
* 중요한 주의사항 :
기본값은 오직 한 번만 값이 구해집니다.
이것은 기본값이 리스트, 딕셔너리, 대부분의 클래스의 인스턴스와 같은 가변 객체일 때 차이를 만듭니다.
예를 들어, 다음 함수는 계속되는 호출로 전달된 인자들을 누적합니다.
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
결과 :
[1]
[1, 2]
[1, 2, 3]
연속된 호출 간에 공유되지 않기를 원한다면 (호출 시, 항상 새로운 값으로)
처음부터 가변객체를 none값으로 정의하면서 시작
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
2. 키워드 인자
함수는 '키워드 = 값' 형식으로 키워드 인자를 사용해 호출될 수 있습니다.
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
위 함수에서
- 필수 인자 (voltage) + 3개의 선택적 인자 (state, action, type)
위 함수는 아래와 같이 호출가능하다.
parrot(1000) # 1 필수
parrot(voltage=1000) # 1 키워드 (필수)
parrot(voltage=1000000, action='VOOOOOM') # 2 키워드 (필수 + a)
parrot(action='VOOOOOM', voltage=1000000) # 2 키워드 (필수 + a. 순서상관x)
parrot('a million', 'bereft of life', 'jump') # 3 위치 인자 (필수, 인자, 인자)
parrot('a thousand', state='pushing up the daisies') # 1 위치(필수), 1 키워드
* 위 함수 호출 시, 필수 인자인 'voltage'를 키워드로
parrot(action='VOOOOOM', voltage=1000000) 식으로 준다면 순서는 상관없다.
하지만, 아래는 모두 에러
parrot() # 필수인자x
parrot(voltage=5.0, 'dead') # 키워드 인자 뒤, 위치인자 x
parrot(110, voltage=220) # 인자값 중복 입력 x
parrot(actor='John Cleese') # 잘못된 키워드 인자
- 필수 인자는 필수로!
- 키워드 인자 뒤에 위치 인자 x. 무조건 키워드 인자는 뒤로!
- 어떤 인자도 두 개 이상의 값을 받을 수 없음.
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for keyword argument 'a'
- 인자 'a'에 2가지 값 입력시, 에러발생하는 예제
**args
- **args : 각 매개변수에 대응하고 '남은 모든 키워드 인자들' -> '딕셔너리'로 받음.
- *args와 조합될 수 있음. 형식 매개변수 목록 밖 인자들 -> '튜플'을 받음.
- *args, **args 순서
ex)
함수정의
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
for kw in keywords:
print(kw, ":", keywords[kw])
함수호출
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
결과
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
* 함수 호출로 '전달된 순서'= '인쇄되는 키워드 인자순서'
3. 임의 인자 리스트
- (가장 사용빈도가 낮음)
- 함수 정의 시, 입력 인자 수를 지정하지 않음.
- 입력된 인자들은 '튜플'로 묶임
- 보통 매개변수 목록 마지막에 옴 (정해진 인자 외 나머지를 모으기 때문)
- *args 매개변수 뒤에는 **args 매개변수만 올 수 있다.
ex)
>>> def concat(*args, sep="/"):
... return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
4. 인자목록 언패킹
- 이미 만들어진 '리스트', '튜플'의 분리된 인자들을 요구하는 함수가 있을 수 있다.
ex) range( ) 함수는 시작 값과 끝값을 입력해야 한다.
- 리스트 / 튜플 언패킹 : *args
- 딕셔너리 언패킹 : **args
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
5. 람다
- 키워드'lambda' : 이름없는 작은 함수를 만들 수 있다.
- 문법적으로 하나의 표현식으로 제한
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
* .sort(key=정렬기준)
- 여기서 '정렬기준' (= pair : pair[1] )
: 숫자x -> 알파벳 순으로 정렬
6. 도큐멘테이션 문자열(독 스트링)
- 객체의 설명문
- 첫 줄
- 대문자로 시작 / 마침표로 끝
- 객체의 목적 (짧고 간결하게 요약)
- 간결함을 위해 함수의 이름, 형을 명시적으로 언급 x
- 여러 줄
- 두 번째줄은 비워서, 시각적으로 분리
- 객체의 호출 규약, 부작용 등을 설명
- 독스트링 : 필요하면 들여쓰기를 제거한다. (탭, 스페이스 8개)
ex)
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
7. 함수 어노테이션
- 함수 어노테이션
- 사용자 정의 함수가 사용하는 형들에 대한 완전히 '선택적인 메타데이터 정보'
- 함수의 __annotations__어트리뷰트에 딕셔너리로 저장
- 함수의 다른 부분에는 아무런 영향을 미치지 않음.
- 매개변수 어노테이션
- 매개변수 + ' : '
- 값을 구할 때, 어노테이션의 값을 주는 표현식이 뒤따름
- 리턴 값 어노테이션
- 리터럴 + '->'
- 매개변수 목록과 def문의 끝을 나타내는 콜론 사이에 위치.
ex)
>>> def f(ham: str, eggs: str = 'eggs') -> str:
... print("Annotations:", f.__annotations__)
... print("Arguments:", ham, eggs)
... return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'