15. 매개변수전달과 반환값
함수매개변수는단순히전달된입력객체를참조하는이름일뿐
변경 불가능한값: 값에의한전달
변경 가능한객체: 참조에의한전달
변경 가능한객체가 함수에전달되어그 값이변경되면원래객체값에영향
>>> a = [1, 2, 3, 4, 5]
>>> def square(items):
... for i, x in enumerate(items):
... items[i] = x * x
...
>>> square(a)
>>> a
[1, 4, 9, 16, 25]
15
39. 생성기와yield
>>> c = countdown(3)
>>> type(c)
<class 'generator'>
반환된생성기 객체를이용해실제함수실행
Python3 에서는__next__(), Python2 에서는next() 호출
>>> c.__next__()
Counting down from 3
3
>>> c.__next__()
2
>>> c.__next__()
1
>>> c.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
39
40. 생성기와yield
생성기 실행순서
__next()__ 를호출하면생성기 함수는yield문까지실행
yield문은결과를생성해반환하고 __next()__ 호출전까지실행중단
함수실행은yield바로다음문장에서재개
보통은생성기를직접호출하기보다는순서열을소비하는for, sum() 혹은
기타연산에서__next()__ 호출이사용됨
>>> for n in countdown(3):
... print(n)
...
Counting down from 3
3
2
1
>>> sum(countdown(3))
Counting down from 3
6
40
41. 생성기와yield
생성기 함수를부분적으로만실행하는경우에는close() 메서드를호출해
명시적으로생성기 객체에종료를알려주는것이가능
>>> c = countdown(10)
>>> c.__next__()
Counting down from 10
10
>>> c.__next__()
9
>>> c.close()
>>> c.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
41
42. 생성기와yield
생성기 함수안에서는yield문에서GeneratorExit 예외가 발생하는것으로
외부에서close() 함수호출한것을알수있음
>>> def countdown(n):
... print("Counting down from %d" % n)
... try:
... while n > 0:
... yield n
... n -= 1
... except GeneratorExit:
... print("Only made it to %d" % n)
...
>>> c = countdown(10)
>>> c.__next__()
Counting down from 10
10
>>> c.__next__()
9
>>> c.close()
Only made it to 9
42
43. 코루틴과 yield표현식
함수안에서yield문을대입연산자오른쪽에두고 값을받아오도록하는것이
가능
>>> def receiver():
... print("Ready to receive")
... while True:
... n = yield
... print("Got %s" % n)
...
위의코드처럼yield를사용하는함수를코루틴(coroutine) 이라고 함
함수외부에서보내준값에답하여실행
동작방식은생성기와매우유사
43
53. 생성기와코루틴사용
import os
import fnmatch
def find_files(topdir, pattern):
for path, dirname, filelist in os.walk(topdir):
for name in filelist:
if fnmatch.fnmatch(name, pattern):
yield os.path.join(path, name)
def opener(filenames):
for name in filenames:
f = open(name)
yield f
def cat(filelist):
for f in filelist:
for line in f:
yield line
def grep(pattern, lines):
for line in lines:
if pattern in line:
yield line
53
56. 생성기와코루틴사용
@coroutine
def find_files(target):
while True:
topdir, pattern = yield
for path, dirname, filelist in os.walk(topdir):
for name in filelist:
if fnmatch.fnmatch(name, pattern):
target.send(os.path.join(path, name))
@coroutine @coroutine
def opener(target): def cat(target):
while True: while True:
name = yield f = yield
f = open(name) for line in f:
target.send(f) target.send(line)
@coroutine @coroutine
def grep(pattern, target): def printer():
while True: while True:
line = yield line = yield
if pattern in line: sys.stdout.write(line)
target.send(line)
56
60. 리스트내포
리스트내포의일반적인문법
[표현식 for 항목1 in 반복가능객체1 if 조건1
for 항목2 in 반복가능객체2 if 조건2
...
for 항목n in 반복가능객체n if 조건n ]
이문법은대략다음코드로변환가능
s = []
for 항목1 in 반복가능객체1:
if 조건1:
for 항목2 in 반복가능객체2:
if 조건2:
...
for 항목n in 반복가능객체n:
if 조건n:
s.append(표현식)
60
61. 리스트내포
>>> a = [-3, 5, 2, -7, 10, 4]
>>> b = 'abcd'
>>> c = [2 * i for i in a]
>>> c
[-6, 10, 4, -14, 20, 8]
>>> d = [i for i in a if i >= 0]
>>> d
[5, 2, 10, 4]
>>> e = [(x, y) for x in a
... for y in b
... if x > 0 ]
>>> e
[(5, 'a'), (5, 'b'), ... , (4, 'b'), (4, 'c'), (4, 'd')]
61
62. 리스트내포
>>> f = [(1, 2), (3, 4), (5, 6)]
>>> g = [math.sqrt(x * x + y * y) for x, y in f]
>>> g
[2.23606797749979, 5.0, 7.810249675906654]
리스트내포안에서정의한반복변수유효범위
Python2 에서는리스트생성연산수행후에도남아있음
Python3 에서는내부변수로만사용됨
62
63. 생성기 표현식
생성기 표현식(generator expression)은리스트내포와동일한계산수행
결과를반복적으로생성하는객체
문법은괄호사용
실제로리스트를생성하거나표현식을바로평가하지않음
반복을통해필요할때값을생성하는생성기 객체반환
생성기 표현식문법
(표현식 for 항목1 in 반복가능객체1 if 조건1
for 항목2 in 반복가능객체2 if 조건2
...
for 항목n in 반복가능객체n if 조건n )
63
64. 생성기 표현식
>>> a = [1, 2, 3, 4]
>>> b = (i * i for i in a)
>>> b
<generator object <genexpr> at 0x10f235678>
>>> b.__next__()
1
>>> b.__next__()
4
>>> b.__next__()
9
생성기 표현식와리스트내포에대한연산결과는큰차이가 없지만,
특정응용프로그램상황에따라성능과 메모리효율을증가시킬수있음
64
65. 생성기 표현식
파일에서줄을추출해공백을제거하고 주석을추출하는부분은
실제로전체파일을읽지않음
실제파일내용은for 루프에서반복을시작할때줄단위로읽어
사용할뿐전체파일내용을메모리에올리는일은없음
>>> f = open('python_sample.py')
>>> lines = (t.strip() for t in f)
>>> comments = (t for t in lines if len(t) > 0 and t[0] ==
>>> for c in comments:
... print(c)
...
# db.app = flask_app
# db.init_app(flask_app)
# db.create_all()
...
65
71. 재귀
재귀를이용한factorial() 함수구현예
>>> def factorial(n):
... if n <= 1:
... return 1
... else:
... return n * factorial(n - 1)
...
>>> factorial(10)
3628800
71
72. 문서화문자열
함수의첫번째문장은주로함수를설명하는문서화문자열인경우가 많음
문서화문자열은함수의__doc__ 속성에저장
IDE 에서이를활용해도움말표시
>>> def factorial(n):
... """Computes n factorial. For example:
... >>> factorial(6)
... 120
... >>>
... """
... if n <= 1:
... return 1
... else:
... return n * factorial(n - 1)
...
>>> factorial.__doc__
'Computes n factorial. For example:nn >>> factorial(6)n
72
73. 문서화문자열
>>> help(factorial)
Help on function factorial in module __main__:
factorial(n)
Computes n factorial. For example:
>>> factorial(6)
120
>>>
(END)
73
74. 문서화문자열
장식자를사용할경우에는장식자래퍼로인해문서화문자열을
제대로가져오지못하는문제점발생
>>> def wrap(func):
... def call(*args, **kwargs):
... return func(*args, **kwargs)
... return call
...
>>> @wrap
... def factorial(n):
... """Computes n factorial. For example:
... """
...
>>> help(factorial)
Help on function call in module __main__:
call(*args, **kwargs)
(END)
74
75. 문서화문자열
장식자함수에서함수이름과 문서화문자열을가져오도록구현하는것 필요
>>> def wrap(func):
... def call(*args, **kwargs):
... return func(*args, **kwargs)
... call.__doc__ = func.__doc__
... call.__name__ = func.__name__
... return call
...
>>> help(factorial)
>>>
Help on function factorial in module __main__:
factorial(*args, **kwargs)
Computes n factorial. For example:
>>> factorial(6)
120
>>>
(END)
75