<jupyter_start><jupyter_text>- 클래스보다 주피터 노트북에서 함수를 주로 많이 사용하게 될 것.- 머신러닝 패키지들 많이 사용하기 때문에 직접 그렇게 많지 않은 코드를 짜게 될 것이다.- 하지만 클래스를 만든 후 모듈이나 패키지 사용하는 연습이 코드의 복잡도를 낮춰준다.  Function- 선언, 호출- parameter, argument 개념 (엄밀히 따지면 두개가 다르기 때문에 개념 알아야~)- return : 특정 변수에 저장- "*args", "**kwargs" : 여러개의 파라미터를 받을 수 있게 해준다.- docstring : 함수를 만든 뒤에 함수에 대한 설명을 document로 남겨주는 것- scope(local, global) : 함수내 함수외의 변수 사용 범위가 달라지는데 글로벌과 로컬 영역으로 나눠지는데 - inner function : 함수 안의 함수를 사용하는 방법- lambda function : 함수를 간단하게 축약해서 쓰는 방법 (for문의 삼항연산처럼)- map, filter, reduce(list 데이터 수정이 쉬워진다.)- decorlater : 다른 언어에 많이 없다.  선언, 호출- def(definition의 약자), 함수도 하나의 변수이다. parameter 받아서 특정 로직을 수행하는 변수이다.- 선언def ():    code- 호출()<jupyter_code># 선언

def test():
    print("this is test function")
    
# 호출
test()
# parameter

def sum_function(a,b):
    print(a+b)
    
    
# argument
num1, num2 = 2, 5
sum_function(num1, num2)

# shift 이용해서 블럭설정 한 후에 ' 눌러주면 한번에 적용된다.
# keyword argument

# 문자열 포매팅 할 때처럼 함수의 argument도 마찬가지로 키워드 없이 그냥 입력하면 순서대로 적용이 되고
# 키워드 = 입력값 하면 찾아서 들어간다.


def div_func(a, b):
    print(a/b)

div_func(2, 10)
div_func(b=10, a=2)

print

# print도 docstring있다.
# default parameter

def sum_func(num1, num2 = 0):
    print(num1 + num2)
    
sum_func(3, 2)
sum_func(2)

# default 값을 함수 선언시에 작성을 해준다.
# default 되는 파라미터 값을 항상 가장 뒤에 작성해줘야한다.

def sum_func(num1, num2 = 0, num3 = 10):
    print(num1 + num2 + num3)

sum_func(10)
print("test")

print("test", end = '\t')
print("test")<jupyter_output><empty_output><jupyter_text>Return- 함수를 호출했을때 결과를 반환하는 용도로 사용합니다.<jupyter_code>def sum_func(a, b):
    return a + b
sum_func(1,2)
def calc_func(num1, num2):
    return num1+num2, num1-num2
calc_func(5,2)

# 튜플 형태로 return이 된다.

result_1, result_2 = calc_func(5,2)

# 두개로 나눠서 받을 수 도 있다. test set과 

print(result_1, result_2)<jupyter_output><empty_output><jupyter_text>*args,**kwargs- * : 전부, 모두, All이라는 의미를 갖는다.<jupyter_code># *args : 여러개의 parameter 를 넣고 싶을 때 사용한다. (키워드가 없는 경우)

def sum_func(*args):
    print(*args)
    print(type(args))
    print(args[0],args[1])
    return sum(args)
    
    
# *args를 여러개 넣어주니까 자동으로 () 튜플 형태의 데이터 타입이 만들어지게 된다.
# 튜플 형태이므로 index사용 가능하다.

sum_func(1, 3, 5, 7, 9)
ls = [1,2,3]
sum(ls)
# **kwargs (키워드가 있는 *args) 딕셔너리 형태로 나오게 된다.
def sum_func(**kwargs):
    print(kwargs)
    print(type(kwargs))
    print(kwargs["num1"],kwargs["num2"])
sum_func(num1 = 1, num2 = 2)
# 키워드가 없는 argument : args
# 키워드가 있는 argument : **kwargs

def fun(*args, **kwargs):
    print(args)
    print(kwargs)
    
fun(1,2,3, num1 = 2, num2 = 3)


# argument에 * 사용, 여기 다시 보기!!!!

def test(*args):
    print(args)
    
ls = [1,2,3]
test(*ls)<jupyter_output><empty_output><jupyter_text>docstring- 함수를 설명할때 사용됩니다.```def ():    """    description    """```- PEP20 : Zen Of Python에 - readablity counts: 가독성은 중요하다. - PEP8 : coding convention에 대해 나와 있다.- 두개 봐주면 좋을 것 같다.- snake case : first_number- carmel case : firstNumber- fiscar case : FirstNumber- l이나 0, o 같은 문자 사용하지 않는 것이 좋다.<jupyter_code>import this
def echo(anything):
    """
    echo resturns its input argument
    the operation is :
        1. print(anything)
        2. return (anything)
    """
    
    
    print(anything)
echo("dss")

# shift + tab, echo?, echo??, help() : 누르면 독스트링 나온다.
# 함수에 정의된 docstring 스타일 convention이 작성자에 따라 다르다.
# 함수에 대한 설명(필수), 파라미터에 대한 설명(필수), 코딩, 예제 등이 들어 있다.

# 독스트링 "" """""" 안에 작성해주면 된다.

echo?
echo??

help(echo)
print()
# help (내장함수 이다.)
# 내장함수 : 파이썬 내에 기본적으로 포함되어 있는 함수들

help(echo)<jupyter_output><empty_output><jupyter_text>scope- global, local<jupyter_code># global
# 함수 밖에 선언된 변수
gv = 10
def print_gv():
    print(gv)
print_gv()
gv = 10
gv2 = 20
def print_gv():
    gv = 100
    print(gv)
    gv2 = 200
    print(globals()["gv"], globals()["gv2"])
print_gv()
gv<jupyter_output><empty_output><jupyter_text>컴퓨터에 저장할 수 있는 영역이 나눠져있다. global, local```global :     gv = 10    print_gv (글로벌 영역에 함수가 만들어지고, 함수 내의 변수는 local영역으로 지정된다.)local :    print_gv함수의 gv = 100```<jupyter_code># globals(): 글로벌로 선언되어 있는 함수를 모두 보여준다.
gv = 10
gv2 = 20
def print_gv():
    
    def test():
        print(1)
    
    gv = 100
    print(gv)
    gv2 = 200
    print(locals()["gv"], locals()["gv2"])

    
print_gv()
# global : local에서 global 변수 사용하고 싶을 때



gv = 10
def change_gv():
    global gv
    gv = 100
    print(gv)
    
    # global 선언 한 뒤에 로컬 영역에서 gv다시 선언해도 소용 없다. 글로벌이 사용된다.
change_gv()<jupyter_output><empty_output><jupyter_text>Inner Function- global : 전역 (전역함수, 전역변수)- local : 지역 (지역함수, 지역변수)- 지역함수<jupyter_code>def outer(a, b):
    
    def inner(c, d):
        return c + d
    
    return inner(a,b)

    # return inner 이라고만 작성하면 함수 결과값이 리턴되지 않는다. () 꼭 적어주기

'''
왜 이렇게 사용을 하는가?

익명함수, 숨기고 싶어서 이너함수를 사용한다. return으로 불러온다.

inner함수 글로벌에서 사용 못한다.

이 코드는 알 필요 없거나 수정 하면 안되는 경우에 이너 함수를 만들게 된다.

'''

# decorator 도 이런 식으로 사용이 된다.
outer (1,2)
inner(1, 3) # inner함수 글로벌에서 사용 못한다. 에러발생<jupyter_output><empty_output><jupyter_text>lambda function- 간단한 함수를 선언하지 않고 함수처럼 사용하는 함수- `lambda  : `- 왜 사용하나요? :선언을 미리 하면 사용하지 않더라도 메모리를 가지고 있다.하지만 lambda를 이용해 호출시에 메모리 사용하기 때문에 절약할 수 있다.<jupyter_code>def sum_func(x, y):
    return x + y
sum_func(1, 2)
#위의 함수를 lambda를 이용해 간단하게 작성 해 줄수 있다.

sum_func2 = lambda x, y : x + y
sum_func2(1,2)
type(sum_func), type(sum_func2)
def test(func, num1, num2):
    return func(num2, num2)
def sum_func(x, y):
    return x + y
def div_func(x, y):
    return x / y
test(lambda x, y = 0: x - y, 1, 2 ) # default 값도 설정이 가능하다.

# : 다음에 삼항연산 등 자유롭게 작성가능하다<jupyter_output><empty_output><jupyter_text>Map, Filter, Reduce- 리스트(순서가 있는 데이터) 형태의 데이터를 함수와 함께 가공해주기 위해서 사용되는 함수- map : 리스트 안에 모든 value에 함수를 적용해서 결과 데이터를 리스트 형태로 반환- filter : 리스트 안에 있는 value 데이터를 특정 함수로 필터링 해주는 함수 입니다.- reduce : 리스트 안에 있는 vaule 데이터를 하나씩 함수에 적용해서 하나의 결과를 얻는 함수입니다. 함수- map : 같은 갯수의 값을 얻는다. 리스트 형태로 리턴```리스트 여러개 들어갈 수 있다. 함수의 파라미터 숫자랑 같아야 한다.ls = [1,2,3,4]function 을 만들어서 실행하면 결과가 y로 들어가게 된다.y = f(x) 이 함수를 모든 요소에 적용을 시키고 각각의 y값을 담은 리스트로 출력이 된다.함수에 return 값이 있어야 y에 해당하는 list 생기게 된다.map(함수, 파라미터들 적어준다.)map(func, ls1, ls2) 파라미터 여러개 들어가도 값은 1로 나오게 된다.y = f(ls1, ls2)```- filter : 함수를 이용해 리스트를 필터링 해준다. 같거나 작은 , 리스트 형태로 리턴```ls = [1,2,3,4]y = f(x)y값이 True, False 이여야 한다.True 값에 해당하는 데이터만 결과로 나오게 된다.filter(function, ls) > 리스트 하나밖에 못온다.ex > even - Trueodd - False[F,T,F,T]True인 데이터만 남기게 된다.[2, 4]filter(function, ls)```- reduce : 하나의 결과만 얻는다. 값의 형태로 리턴```ls = [1,2,3,4]y = f(결과값,다음값)a = f(1,2)b = f(a,3)c = f(b,4)파라미터 최소 2개는 있어야 한다.```이 3가지를 이용해서 편리하게 데이터를 필터링하거나 수정할 수 있다<jupyter_code># map : 내장함수로 들어있다 *iterable 여러가지 

# map?

ls = [1,2,3,4]
def sum_func(num):
    return num - 1

list(map(sum_func, ls))
# map

ls = [1,2,3,4]
def sum_func(num):
    return num - 1
list(map(sum_func, ls))

ls = [1,2,3,4]

list(map(lambda a : a if a % 2 ==0 else "짝수가 아님", ls))
# filter

# filter?

# iterable 하나만 들어올 수 있다.


def is_even(num):
    return True if num % 2 == 0 else False

list(filter(is_even, ls))
# reduce : 내장함수 아니라 import 해줘야 한다.

from functools import reduce


ls = [1,2,3,4]
def sum_func2(num1, num2):
    return num1 + num2

reduce(sum_func2, ls)

# reduce는 하나의 값을 내기때문에 list로 형변환이 안된다.
#reduce?

name_list = ["<NAME>", "<NAME>", "<NAME>", "<NAME>", "<NAME>"]
result = list(map(lambda x: x.split(" ")[0],name_list))
result
# map

# map 이 없을때

ls = [1,2,3,4,5]

def minus_one(number):
    return number - 1

result = []
for number in ls:
    result.append(minus_one(number))
result
# map 있을 때

list(map(minus_one,ls))
# lambda 넣을 수도 있음 / 리스트를 하나하나 함수에 넣어서 결과를 리스트로 출력

list(map(lambda number : number -1, ls))
# map 에는 여러개의 리스트 데이터를 넣을 수 있다. map(함수,리스트1, 리스트2) 리스트 1 2의 데이터가 차례대로 나와서 실행되고 리스트 갯수만큼 함수 파라미터가 있어야 한다.

ls1 = [1,2,3,4]
ls2 = [5,6,7,8]`

list(map(lambda num1, num2: num1 + num2,ls1,ls2))
# map을 이용하여 사람의 성만 결과로 출력하는 코드를 작성하세요
names = ["<NAME>", "Lee data","Park science", "Lee school"]

result = list(map(lambda x: x.split(" ")[0], names))

result
# 1~10 까지 숫자 데이터에서 짝수는 even 홀수는 odd를 출력하고 출력된 데이터를 key:value 의 dict형태로 출력

# 이 다시 문제 풀어보기!!!

ls = list(range(1, 11))

result = list(map(lambda x : "even" if x%2 == 0 else "odd", ls))

result = dict(zip(ls, result))

result

# 두개의 리스트
# 퀴즈 3 - map 함수를 구현하세요.
ls1, ls2, ls3 = [1,2,3,4], [5,6,7,8], [9,10,11,12]

def sum_func(*args):
    return sum(args)
    
def map_func(func, *args):
    result = []
    
    # TODO
    values_count = len(args[0]) # 4
    for idx in range(len(args)):
        values_count = values_count if values_count < len(args[idx]) else len(args[idx])  # 리스트 중 가장 적은 밸류를 가지고 있는 값으로 맞춰준다.
        
    params_count = len(args) # 3
    
    for idx1 in range(values_count): # 각 리스트의 밸류값만큼 for 문 동작할 것이다. 4번 뽑아내야 한다.  전체
        params = []
        for idx2 in range(params_count):  #  동시에 몇 개 뽑아내는지, 동시에는 3개를 뽑아내면 되서 리스트 갯수만큼만
            params.append(args[idx2][idx1])  # 리스트 0,1,2의 0번째 값, 1번째 값 ... 을 뽑아서 어팬드 한다.
        result.append(func(*params))

    
    return result

result = map_func(sum_func, ls1, ls2, ls3)
result
# result - [15, 18, 21, 24]
ls1, ls2, ls3 = [1,2,3,4], [5,6,7,8], [9,10,11,12]

def sum_func(*args):
    return sum(args)

def map_func(func, *args):
    
        result = []
        
        value_count = len(args[0])
        
        for i in range(len(args)):
            value_count = value_count if value_count < len(args[i]) else len(args[i])
        
        argu_count = len(args)
        
        
        for a in range(value_count):
            params = []
            for b in range(argu_count):
                params.append(args[b][a])
        result.append(func(*params))
    return result
        
result = map_func(sum_func, ls1, ls2, ls3)
result

# 퀴즈 3 - map 함수를 구현하세요.
ls1, ls2, ls3 = [1,2,3,4], [5,6,7,8], [9,10,11,12]

def sum_func(*args):
    return sum(args)
    
def map_func(func, *args):
    result = []
    
    # TODO
    values_count = len(args[0]) # 4
    for idx in range(len(args)):
        values_count = values_count if values_count < len(args[idx]) else len(args[idx])
        
    params_count = len(args) # 3
    
    for idx1 in range(values_count):
        params = []
        for idx2 in range(params_count):
            params.append(args[idx2][idx1])
        result.append(func(*params))
    
    return result

result = map_func(sum_func, ls1, ls2, ls3)
result
# result - [15, 18, 21, 24]<jupyter_output><empty_output><jupyter_text>Filter  -반드시  True, False 로 떨어져야 한다!!- 리스트 데이터에서 조건에 맞는 value 데이터만 남기는 필터링 기능을 하는 함수입니다.- filter의 아규먼트로 들어가는 함수는 항상 리턴값이 True 아니면 False로 리턴되어야 합니다.- True값인 데이터는 남고 False 값인 데이터는 제거됩니다.- `filter(함수, 리스트)`<jupyter_code># filter 를 사용해서 리스트에서 짝수데이터만 남기는 코드를 작성

ls = list(range(1,11))

list(filter(lambda x : x%2 == 0, ls))
# 퀴즈 - 성이 이씨인 사람의 이름만 결과로 출력하는 

names = ["K<NAME>", "Lee data","Park science", "Lee school"]

result = list(filter(lambda x : x.split(" ")[0] == "Lee", names))

result = [name for name in names if name.split(" "[0]) == "lee"]

result
names = ["K<NAME>", "Lee data","Park science", "Lee school"]

def name(x):
    if x.split(" ")[0] == "Lee":
        print(x.split(" ")[1])
        
list(filter(name,names))  
# filter function 구현 홀수와 짝수를 필터링 하는 함수

ls = list(range(1,11))

is_odd_even = {
    "odd": lambda num : num % 2 == 1,
    "even" : lambda num : num % 2 == 0,
}

def filter_func(func, data_list):
    result = []
    # todo
    # result = list(filter(func,data_list))
    
    for data in data_list:
        if func(data):
            result.append(data)
    
    return result

result_1 = filter_func(is_odd_even["odd"], ls)
result_2 = filter_func(is_odd_even["even"], ls)
result_1, result_2<jupyter_output><empty_output><jupyter_text>Reduce- 리스트 데이터를 처음부터 순서대로 특정 함수를 실행하여 나온 결과를 다음 데이터와 함께 또 다시 함수를 실행하여- 마지막에 하나의 데이터를 남기는 함수입니다.- `reduce(함수, 리스트)`<jupyter_code># reduce : reduce에 들어가는 파라미터 최소 두개 있어야 한다.

from functools import reduce

ls = [1,2,3,4,5]
reduce(lambda num1, num2: num1 + num2, ls)
# 가장 큰 수를 구하는 코드 : 하나하나씩 출력해서 계속 비교해서 큰것만 남기는 형태

ls = [1, 3, 7, 5, 2]
reduce(lambda num1, num2 : num1 if num1 > num2 else num2, ls)
# 퀴즈 1 - 사람 이름이 가장 긴 사람을 출력하는 코드를 reduce를 이용해서 작성해 주세요

names = ["<NAME>", "Lee data","Park science", "Lee school"]

reduce(lambda name1, name2: name1 if len(name1) > len(name2) else name2, names)
# 퀴즈 2 - reduce 구현 과제!!

ls = [1,2,3,4,5]

def reduce_func(func, data_list):
    return reduce(func, data_list)

reduce_func(lambda num1, num2 : num1 + num2, ls)
# 결과는 15로 나온다.<jupyter_output><empty_output><jupyter_text>Decolator 중요하다!!!!!    코드의 중복을 막고 유지보수를 위해서 사용한다.- 코드를 바꾸지 않고 함수의 기능을 추가할 때 사용됩니다.- 여러개의 함수에서 공통된 기능을 뽑아서 하나의 함수로 만들어서 사용할때 사용됩니다.- inner function, `*args`, `**kwargs`를 이용을 한다.- 함수 위에 `@ 함수명` 붙여서 사용한다.```def A():    `code1`    code2    `code3`    def B():    `code1`    code4    `code3`            1, 3 코드가 중복이 되는데 공통된거를 뽑아서 하나의 함수로 만드는데 이용한다.        함수 A, B 에서 코드 1, 3을 뽑아낸다.         ``````def C(func):    def wrapper(*args, **kwargs):        code1        result = func(*args,**kwargs)        code3        return result    return wrapper         함수를 리턴한다.@Cdef A(params):    result = code2    return result    @Cdef B():    code4 A() 실행시 -  code 1, code 2, code 3, return result.  B() 실행시 -  code 1 , code 4, code 3, return result A(params)= C(A)(params) : C에 (A)를 넣어준다. wrapper 를 가져와서 A의 나머지 채운다음에 공통된 것까지 함께 실행시켜준다.```<jupyter_code># display를 해주는 데코레이터를 만들어 보자

# def C()
def disp(func): 
    def wrapper(*args, **kwargs):
        print("running function name:", func.__name__)  # function 이름을 출력하는 것이다.
        print("args: ", args)
        print("kwargs:", kwargs)
        
        #code 2(A), code4(B)
        result = func(*args, **kwargs)
        
        # code 3
        print("result :", result)
        return result
    return wrapper #disp에 대한 함수의 리턴이다, 이너함수 호출
        

# def A():

@disp
def sum_func(a, b):
    #code1 - print(function name, args, kwargs 출력)
    print("{} + {} = {}". format(a, b, a+b))
    #code3 - print("result :", a + b)
    return a + b
sum_func(1, 2)
# def A():

@disp
def minus_func(a, b):
    #code1 - print(function name, args, kwargs 출력)
    print("{} + {} = {}". format(a, b, a-b))
    #code3 - print("result :", a - b)
    return a - b
sum_func(1, 2)
minus_func(10,5)
# timer decolater - 함수가 실행되는데 걸리는 시간을 측정하는 데코레이터

import time

def timer(func):
    def wrapper(*args, **kwargs): # 있을 수도 있으니까 둘다 적어 줘야 한다.
        start_time = time.time() # time.time() : 현재시간 나온다.
        result = func(*args, **kwargs)
        end_time = time.time()
        print("running time : ",  end_time - start_time)  #앞 뒤로 현재시간 잰거를 빼준다.
        return result
    return wrapper


import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time=time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("running time : ", end_time - start_time)
        return result
    return wrapper


@timer
def pow_func(num1, num2):
    return num1 ** num2
def pow_func(num1, num2):
    return num2 ** num2

@timer
def pow_func(num1, num2):
    return num2 ** num2
pow_func(2,1000)
# 많이 사용하니까 꼭 이해해야한다.

# 데코레이터를 사용해서 관리자계정이면 패스워드를 출력하고 관리자 계정이 아니면 패스워드를 출력하지 않는 데코레이터를 만들어 보자

admin_ls = ["pdj", "dss"]
pwd = "<PASSWORD>" # 관리자 계정이면 패스워드를 출력한다.


#C
def admin(func):
    def wrapper(*args, **kwargs):
        is_admin = False
        user_if = func(*args, **kwargs)  # 계정을 받는 함수를 만들것이다.
        if user_id in admin_ls:
            is_admin = True
        
        if is_admin:
            print("password : ", pw)
        
           
        else:
            print("you are not admin!")
            
        return is_admin
    
    return wrapper
@admin
def input_user():
    return input("insert user id : ")
names = ['<NAME>', '<NAME>', '<NAME>']

def a(name):
    if name.split(" ")[0] == "Lee":
        return name

result = list(a , names)
result<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13881616754996487, 'fraction_numerical': 0.02809526850137284, 'mean_word_length': 2.932211900577454, 'pattern_counts': {'":': 3, '<': 65, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '168613', 'license': 'MIT', 'n_tokens_mistral': 8710, 'n_tokens_neox': 10065, 'n_words': 1985, 'path': 'python/01_python_basic/04_function.ipynb', 'repo_name': 'hyelansgithub/fastcampus-programming', 'size': '15705'}