7. Functions

7.1. Writing Functions That Accept Any Number of Arguments

P : 인자 수가 가변인 함수를 만들고 싶다.

S : * 연산자, ** 연산자를 사용한다.

def avg(first, *rest):
    return (first + sum(rest)) / (1 + len(rest))

# Sample use
avg(1, 2)          # 1.5
avg(1, 2, 3, 4)    # 2.5

import html

def make_element(name, value, **attrs):
    keyvals = [' %s="%s"' % item for item in attrs.items()]
    attr_str = ''.join(keyvals)
    element = '<{name}{attrs}>{value}</{name}>'.format(
                  name=name,
                  attrs=attr_str,
                  value=html.escape(value))
    return element

# Example
# Creates '<item size="large" quantity="6">Albatross</item>'
make_element('item', 'Albatross', size='large', quantity=6)

# Creates '<p>&lt;spam&gt;</p>'
make_element('p', '<spam>')

def anyargs(*args, **kwargs):
    print(args)      # A tuple
    print(kwargs)    # A dict

7.2. Writing Functions That Only Accept Keyword Arguments

P : 키워드 인자만 받는 함수를 만들고 싶다.

S : * 연산자로 받는 인자를 버린다.

def recv(maxsize, *, block):
    'Receives a message'
    pass

recv(1024, True)        #  TypeError
recv(1024, block=True)  # Ok

def mininum(*values, clip=None):
    m = min(values)
    if clip is not None:
        m = clip if clip > m else m
    return m

minimum(1, 5, 2, -5, 10)          # Returns -5
minimum(1, 5, 2, -5, 10, clip=0)  # Returns 0

7.3. Attaching Informational Metadata to Function Arguments

P : 함수 인자에 가독성을 위한 정보를 추가하고 싶다.

S : 다음과 같이 쓰면 된다.

def add(x:int, y:int) -> int:
    return x + y

7.4. Returning Multiple Values from a Function

P : 함수에서 여러 값을 묶어 리턴하고 싶다.

S : 튜플을 리턴한다.

>>> def myfun():
...     return 1, 2, 3
...
>>> a, b, c = myfun()
>>> a
1
>>> b
2
>>> c
3

7.5. Defining Functions with Default Arguments

P : 함수 인자에 기본값을 지정하고 싶다.

S : 기본값을 지정하면 된다. 단 이 인자들은 맨 끝부분에 위치해야 한다. 타입이 변형 가능한 컨테이너라면 아래와 같이 쓴다.

def spam(a, b=42):
    print(a, b)

spam(1)      # Ok. a=1, b=42
spam(1, 2)   # Ok. a=1, b=2

# Using a list as a default value
def spam2(a, b=None):
    if b is None:
        b = []
    ...

_no_value = object()

def spam3(a, b=_no_value):
    if b is _no_value:
        print('No b value supplied')
    ...

7.6. Defining Anonymous or Inline Functions

P : 간단한 함수를 별도의 정의 없이 만들고 싶다.

S : 람다 함수를 쓴다.

>>> add = lambda x, y: x + y
>>> add(2,3)
5

7.7. Capturing Variables in Anonymous Functions

P : 람다 함수 내의 변수가 정의되는 시점의 값을 유지하게 하고 싶다.

S : 다음과 같이 써야 한다.

>>> x = 10
>>> a = lambda y, x=x: x + y
>>> x = 20
>>> b = lambda y, x=x: x + y
>>> a(10)
20
>>> b(10)
30
>>>

7.8. Making a N-argument Callable Work As a Callable with Fewer Arguments

P : 여러 인자를 받는 함수에 더 적은 인자를 받을 수 있도록 하고 싶다.

S : functools.partial()을 쓴다.

def spam(a, b, c, d):
    print(a, b, c, d)

>>> from functools import partial
>>> s1 = partial(spam, 1)       # a = 1
>>> s1(2, 3, 4)
1 2 3 4
>>> s1(4, 5, 6)
1 4 5 6
>>> s2 = partial(spam, d=42)    # d = 42
>>> s2(1, 2, 3)
1 2 3 42
>>> s2(4, 5, 5)
4 5 5 42
>>> s3 = partial(spam, 1, 2, d=42) # a = 1, b = 2, d = 42
>>> s3(3)
1 2 3 42
>>> s3(4)
1 2 4 42
>>> s3(5)
1 2 5 42
>>>

7.9. Replacing Single Method Classes with Functions

P : __init__()밖에 없는 클래스를 함수 하나로 대체하고 싶다.

S : 클로져를 사용한다.

from urllib.request import urlopen

def urltemplate(template):
    def opener(**kwargs):
        return urlopen(template.format_map(kwargs))
    return opener

# Example use
yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo(names='IBM,AAPL,FB', fields='sl1c1v'):
    print(line.decode('utf-8'))

7.10. Calling Extra State with Callback Functions

P : 콜백 함수에 별도의 상태를 저장하고 싶다.

S : 핸들러에 변수를 저장한다.

class ResultHandler:
    def __init__(self):
        self.sequence = 0
    def handler(self, result):
        self.sequence += 1
        print('[{}] Got: {}'.format(self.sequence, result))

>>> r = ResultHandler()
>>> apply_async(add, (2, 3), callback=r.handler)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=r.handler)
[2] Got: helloworld
>>>

7.11. Inlining Callback Functions

P : 콜백 함수를 절차적으로 짜고 싶다.

S : 제네레이터와 코루틴을 사용한다.

def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)

    # Invoke the callback with the result
    callback(result)

def add(x, y):
    return x + y

from queue import Queue
from functools import wraps

class Async:
    def __init__(self, func, args):
        self.func = func
        self.args = args

def inlined_async(func):
    @wraps(func)
    def wrapper(*args):
        f = func(*args)
        result_queue = Queue()
        result_queue.put(None)
        while True:
            result = result_queue.get()
            try:
                a = f.send(result)
                apply_async(a.func, a.args, callback=result_queue.put)
            except StopIteration:
                break
    return wrapper

@inlined_async
def test():
    r = yield Async(add, (2, 3))
    print(r)
    r = yield Async(add, ('hello', 'world'))
    print(r)
    for n in range(10):
        r = yield Async(add, (n, n))
        print(r)
    print('Goodbye')

>>> test()
5
helloworld
0
2
4
6
8
10
12
14
16
18
Goodbye

7.12. Accessing Variables Defined Inside a Closure

P : 클로져 안의 변수에 접근하고 싶다.

S : 접근자 함수를 쓴다.

def sample():
    n = 0
    # Closure function
    def func():
        print('n=', n)

    # Accessor methods for n
    def get_n():
        return n

    def set_n(value):
        nonlocal n
        n = value

    # Attach as function attributes
    func.get_n = get_n
    func.set_n = set_n
    return func

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중