# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# 함수도 오브젝트 중 하나입니다.  
# 예제를 위해 팩토리얼 함수를 만듭니다.

def factorial(n):
    sum = 1
    for i in range(n, 1, -1):
        sum *= i
    return sum


factorial(5)


# 위치 인자는 함수를 호출할 때 나열된 순서대로 할당됩니다.

def factorial2(n, stop):
    if n == 0:
        return n, 1   # 팩토리얼 정의에 따라 0일 경우 1을 리턴합니다.
    elif n < 0:
        return n, None  # 팩토리얼 정의에 따라 음수의 경우는 제외합니다.
    sum = 1
    for i in range(n, stop, -1):
        sum *= i
    return n, sum


factorial2(5, 1)

factorial2(0, 5)

factorial2(-5 ,1)

# 키워드 인자는 위치 인자 뒤에 나열되어야 합니다.

factorial2(n=5, stop=1)

factorial2(stop=1, n=5)

factorial2(stop=1, 5)

factorial2(5, stop=1)


# 파라메타에 디폴트 값을 부여할 수 있습니다.  
# 디폴트 값이 있는 파라메타는 함수 선언 맨 뒤에 위치해야 합니다.

def factorial3(n, stop=1):
    if n == 0:
        return n, 1   # 팩토리얼 정의에 따라 0일 경우 1을 리턴합니다.
    elif n < 0:
        return n, None  # 팩토리얼 정의에 따라 음수의 경우는 제외합니다.
    sum = 1
    for i in range(n, stop, -1):
        sum *= i
    return n, sum


factorial3(n=5, stop=1)

factorial3(n=5)

factorial3(5)


def factorial3(n=5, stop):
    pass


# 재귀 함수는 종료 조건과 리턴 값의 갯수에 주의해야 합니다.

def factorial4(n, stop=1):
    if n < stop or n <= 0:
        return 1
    return n, n*factorial4(n-1, stop)


factorial4(5, 4)


def factorial4(n, stop=1):
    if n < stop or n <= 0:
        return 1
    return n*factorial4(n-1, stop)


factorial4(5, 4)


# 익명의 위치인자는 몇개의 인자가 전달될 지 확실히 알 수 없을 때 사용합니다.

def menu(soup, main, *args):
    print('Soup is %s' % soup)
    print('Main is %s' % main)
    for other in args:
        print('Other is %s' % str(other))


menu('mushroom', 'steak', 'wine', 100)

menu('egg', 'wine', 100)


# 익명의 키워드 인자는 딕셔너리로 함수 내부에 전달됩니다.

def menu(*args, **kwargs):
    for other in args:
        print('Order is %s' % str(other))
    for k in kwargs:
        print('Menu is %s: %s' % (k, kwargs[k]))


menu('mushroom', drink='wine', tip=100)

# 함수 내부에서 참조하는 변수가 함수 내부에 없으면 전역 변수를 참조합니다.

a = 'dog'
id(a)


def f1():
    print(id(a))
f1()


# 함수내에서 변수에 값이 할당되면 새로운 전역변수와는 구분됩니다.

def f2():
    a = 'cat'
    print(id(a))
f2()

id(a)


# 지역변수가 할당되기 전에 먼저 참조가 일어나면 에러가 발생합니다.

def f3():
    print(id(a))
    a = 'cat'
f3()


# 명시적으로 전역변수를 사용하고 싶을 때에는 global 키워드를 이용합니다.

def f4():
    global a
    print(id(a))
    a = 'cat'
    print(id(a))
f4()

id(a)

# 파라메타로 전달되는 것은 오브젝트를 가리키는 참조입니다.(call-by-object-reference)

a = 'dog'
def f5(a):
    print(id(a))
    a = 'cat'
    print(id(a))
f5(a)

id(a)

a = ['dog']
id(a)


def f6(a):
    print(id(a))
    a.append('cat')
    print(id(a))
f6(a)

a


# 내부함수는 함수 안에 함수를 정의하는 것 입니다.

def outer():
    def inner():
        print('inner')
    inner()


outer()


def inner():
    print('global inner')
outer()


# 외부함수에서 넘겨진 인자값을 기억하는 함수를 만들어 리턴합니다.(클로저)

def cookbook(name):
    def recipe(no):
        print("%s's recipe no.%d" % (name, no))
    return recipe


python_recipe = cookbook('python')
perl_recipe = cookbook('perl')

python_recipe(1)

perl_recipe(2)

id(python_recipe), id(perl_recipe)

# 제너레이터는 큰 배열을 효율적으로 생성할 때 사용합니다.

import random
def gaus_dist(n):
    while n > 0:
        yield random.random()
        n -= 1


gd = gaus_dist(5)
for i in gd:
    print(i)

gd = gaus_dist(5)
next(gd)

next(gd)

sum(gd)

list(gaus_dist(5))


# 함수 바디 첫번째 라인의 주석은 독스트링으로 관리됩니다.

def sample(a = 0):
    '''this is sample function'''
    pass


# +
# sample?
# -

help(sample)

StarcoderdataJupyterScriptsDedupFiltered