함수(function - oop method) oop 객체지향에서는 method라고 표현¶

  • 코드 재사용
  • 가독성 향상
  • 유지보수 용이
  • 디버깅 용이
  • 모듈화(import utils)
def 함수이름([매개변수, 매개변수, .........]) : 실행할 코드 return 결과값(내장변수타입) # 반환이 필요없다면 생략 가능
In [27]:
print('working - ')
print('default parameter - ')
def greet(name='guest'):
    '''사용자에게 인사하는 함수'''
    return (f'hi ~, {name}')
working - 
default parameter - 
In [31]:
print('caller - ')
result = greet()
print(result)
caller - 
hi ~, guest
In [21]:
def userAdd(a,b):
    return a ** b
In [32]:
print('positional argument - ')
result = userAdd(3,2)
print('type - ', type(result))
print('result - ', result)
positional argument - 
type -  <class 'int'>
result -  9
In [33]:
print('keyword argument - ')
result = userAdd(b=3,a=2)
print('type - ', type(result))
print('result - ', result)
keyword argument - 
type -  <class 'int'>
result -  8
  • 람다 함수(Lambda function) == 익명의 함수(anonymous)
  • lambda 매개변수 : 실행문 (return 키워드 없이 결과값을 바로 반환)
  • map, filter~
In [38]:
add = lambda x, y : x + y
print('type - ', type(add))
type -  <class 'function'>
In [39]:
result = add(3, 5)
print('result - ', result)
result -  8
In [57]:
lst = [1,2,3,4,5,6,7,8]

print('case01 - ')
result = [data ** 2 for data in lst]
print(result)

print('case02 - ')
print('map - 열거형 타입(반복 가능한 요소에 대해서 특정 함수를 적용하고 그 결과를 map 객체로 반환)')
print('map(function, iterable)')
double = list(map(lambda data : data ** 2 , lst ))
print(double)

print()
print('case03 - ')
print('filter(function, iterable) ')
even = list(filter(lambda data : data % 2 == 0 , lst ))
print(even)
case01 - 
[1, 4, 9, 16, 25, 36, 49, 64]
case02 - 
map - 열거형 타입(반복 가능한 요소에 대해서 특정 함수를 적용하고 그 결과를 map 객체로 반환)
map(function, iterable)
[1, 4, 9, 16, 25, 36, 49, 64]

case03 - 
filter(function, iterable) 
[2, 4, 6, 8]
In [61]:
wordLst = ['pineApple', 'cherry', 'watermelon', 'banana', 'apple']
result = sorted(wordLst, key=lambda x : len(x))
print(result)
['apple', 'cherry', 'banana', 'pineApple', 'watermelon']
In [76]:
# 반환예시) [ 'www.skshielus.com', 'www.samsung.com' , etc .....]
def makeUrl(lst : list) -> list :
    #return [f'www.{data}.com' for data in lst]
    return list(map(lambda x: 'www.'+x+'.com', lst))
In [81]:
companyLst = ['skshieldus', 'samsung', 'lgcns', 'skcnc', '<script>alert(1)</script>']
urls = makeUrl(companyLst)
print(urls)
['www.skshieldus.com', 'www.samsung.com', 'www.lgcns.com', 'www.skcnc.com', 'www.<script>alert(1)</script>.com']
In [96]:
# 코드의 개선점
# 내부값이 문자열인지, 악성문자열 검증
# 웹 페이지에 출력하면 XSS 취약점 발생
# quote() : 공백, 특수문자 등을 안전하게 인코딩

from urllib.parse import quote

# def safemakeUrl(lst : list) -> list :
#     return list(map(lambda x: 'www.'+quote(x)+'.com', lst))

# isinstance 입력받은 lst 타입이 list 타입인지
def safemakeUrl(lst : list) -> list :
    if not isinstance(lst, list):
        raise TypeError("입력은 리스트 타입으로 전달 부탁드립니다.")
    if not all(isinstance(name, str) for name in lst) :
        raise ValueError("요소의 타입은 문자열")
    # 안전하게 URL 인코딩
    return list(map(lambda x: 'www.'+quote(x)+'.com', lst))
In [98]:
companyLst = ['skshieldus', 'samsung', 'lgcns', 'skcnc', '<script>alert(1)</script>']
urls = safemakeUrl(companyLst)
print(urls)
['www.skshieldus.com', 'www.samsung.com', 'www.lgcns.com', 'www.skcnc.com', 'www.%3Cscript%3Ealert%281%29%3C/script%3E.com']
In [119]:
def myColor(name, color, isLike : bool) :
    print(f'{name}님은 {color}색을 {'좋아' if isLike else '싫어'}합니다.')
In [120]:
# 출력예시) XXX님은 xxx색을 좋아(싫어)합니다.
myColor('섭섭님', 'red', False)
myColor('섭섭님', 'blue', True)
섭섭님님은 red색을 싫어합니다.
섭섭님님은 blue색을 좋아합니다.
  • 변수의 스코프에 대한 이해(LEGB)
In [133]:
# 전역변수
globalVar = 10 

def outer() :
    # 외부 함수 변수
    enclosingVar = 20
    def inner() :
        # 지역변수
        localVar = 30
        print('global - ', globalVar)
        print('enclosingVar - ', enclosingVar)
        print('localVar - ', localVar)
    inner()
    # error
    # print(localVar)
In [134]:
outer()
print('globalVar - ', globalVar)
# error
# print(enclosingVar)
global -  10
enclosingVar -  20
localVar -  30
globalVar -  10
In [135]:
x = 10
def test() :
    x = 20
    
In [136]:
test()
print('x - ', x)
x -  10
In [146]:
cnt = 0

def increment () :
    global cnt
    cnt += 1
    
In [147]:
increment()
increment()
increment()
print('cnt - ', cnt)
cnt -  3
In [156]:
def outer() :
    outerVar = 10
    def inner() :
        nonlocal outerVar # nonlocal 외부 함수를 호출 가능하게 해줌
        outerVar += 1
        print('inner outerVar : ', outerVar)
    inner()
    print('outer outerVar : ', outerVar)
In [161]:
outer()
inner outerVar :  11
outer outerVar :  11
  • 클로저(Closure)(중첩함수 - 함수내부에서 외부함수의 변수를 기억)
  • 함수가 종료되어도 외부 변수를 기억하는 것이 핵심
  • 상태유지(전역변수를 쓰지 않고도 함수 내부에서 상태 유지 가능)
  • 함수 장식자(데코레이터) : 클로저 기반
In [171]:
def outer(name : str):
    def inner():
        return f'hi ~ , {name}'
    return inner # 함수반환
        
In [175]:
msg = outer('jslim')
print('type - ', type(msg))
print('result - ', msg())
type -  <class 'function'>
result -  hi ~ , jslim
In [179]:
# 전역변수를 사용하지 않고 상태를 유지하는 코드 개선

def counter():
    count = 0
    def increase():
        nonlocal count
        count += 1
        return count
    return increase
In [180]:
cnt = counter()
print(cnt())
print(cnt())
print(cnt())
print(cnt())
print(cnt())
1
2
3
4
5
  • decorator(함수 장식자)
  • 함수를 감싸서 기능(공통의 로직)을 추가시켜주는 것
  • 현업에서 자주 사용되는데 : 로깅, 권한체크, 실행시간 측정, etc......
In [198]:
def commonChecking():
    print('>>>>>>>>> permission check')
def commonLogging() :
    print('>>>>>>>>> log......')

def decorator(checkingFunc, loggingFunc):
    def logic():
        checkingFunc()
        print('업무로직')
        loggingFunc()
    return logic
In [199]:
innerLogic = decorator(commonChecking, commonLogging)
innerLogic()
>>>>>>>>> permission check
업무로직
>>>>>>>>> log......
In [213]:
def clo(num):
    x = 10
    def test():
        nonlocal x
        x = x + num
        return x
    return test

a = clo(1)
print(a())
print(a())
print(a())
11
12
13
In [20]:
print('실행시간 성능 로그 - ')
from time import time, sleep

def timer(func): 
    def wrapper(*args, **kwargs):
        start = time()
        result = func(*args, **kwargs)
        elapsed = time() - start
        if elapsed > 2 :
            print(f'경고 : {func.__name__}, 실행시간 : {elapsed:.2f}초 초과되어서 알림')
        return result
    return wrapper

def timerFunc():
    sleep(1)
    return '성능확인'
    
실행시간 성능 로그 - 
In [21]:
# 함수 장식자
@timer
def timerFunc():
    sleep(1)
    return '성능확인'

inner = timerFunc()
print(inner)
성능확인
In [22]:
def timerFunc():
    sleep(1)
    return '성능확인'

inner = timer(timerFunc)
print(inner())
성능확인
  • 가변인자 함수 : 몇개의 매개변수가 전달될지 모르는 것
  • *args : tuple
  • **args : 키워드 인자로 dict
In [227]:
def variableLenArgs(*args : int) -> None :
    print('type - ', type(args))
    total = sum(args)
    return total
In [230]:
result = variableLenArgs(1,2,3)
print(result)
result = variableLenArgs(1,2,3,4,5)
print(result)
result = variableLenArgs(1,2,3,4,5,6,7)
print(result)
type -  <class 'tuple'>
6
type -  <class 'tuple'>
15
type -  <class 'tuple'>
28
In [250]:
def variableLenArgsDict(**args) :
    print('type - ', type(args))
    for key, value in args.items():
        print(key,value)
In [251]:
variableLenArgsDict(name='jslim',age=30,region='seoul')
type -  <class 'dict'>
name jslim
age 30
region seoul
In [269]:
def variableLenArgsMix(subject, *args, **kwargs):
    print('subject - ', subject)
    print('args - ', args)
    print('kwargs - ', kwargs)
In [273]:
variableLenArgsMix('사용자 정보 ', '임섭순', '섭섭해', '쉴더스', a=1,b=2)
subject -  사용자 정보 
args -  ('임섭순', '섭섭해', '쉴더스')
kwargs -  {'a': 1, 'b': 2}
In [313]:
# endpoint
# Quiz
# 아래와 같은 api 요청을 생성
# https://api.v1.example.com/search?q=secure&page=2
def makeApiRequest(endpoint, **params) :
    query = "&".join([f"{k}={v}" for k, v in params.items()])
    print(f'{endpoint}?{query}')
    return (f'{endpoint}?{query}')


    
In [314]:
api = makeApiRequest('https://api.v1.example.com/search', q='secure', page=2)
print(api)
https://api.v1.example.com/search?q=secure&page=2
https://api.v1.example.com/search?q=secure&page=2
In [295]:
def makeApiRequest(endpoint, **params):
    # params를 key=value 형태로 연결
    query = "&".join([f"{k}={v}" for k, v in params.items()])
    url = f"{endpoint}?{query}"
    print(url)
    return url

def makeApiRequest(endpoint, **params):
    query = ""
    for k, v in params.items():
        if query == "":
            query += f"{k}={v}"
        else:
            query += f"&{k}={v}"
    url = endpoint + "?" + query
    print(url)
    return url    
In [296]:
api = makeApiRequest('https://api.v1.example.com/search', q='secure', page=2)
print(api)
https://api.v1.example.com/search?q=secure&page=2
https://api.v1.example.com/search?q=secure&page=2
In [303]:
from urllib.parse import urlencode
params = {'q' : 'secure', 'page' : 2} 
queryString = urlencode(params)
print(queryString)
q=secure&page=2
In [305]:
from urllib.parse import urlencode
def makeApiRequest(endpoint, **params) :
    queryString = urlencode(params)
    return endpoint+'?'+queryString

api = makeApiRequest('https://api.v1.example.com/search', q='secure', page=2)
print(api)
https://api.v1.example.com/search?q=secure&page=2
In [311]:
print('보안 - 코드 개선')
from urllib.parse import urlencode
def makeApiRequest(endpoint, **params) :
    
    whiteLst = {'q', 'page', 'lang'}
    safeParams = { k : v for k, v in params.items() if k in whiteLst}
    queryString = urlencode(safeParams)
    return endpoint+'?'+queryString
보안 - 코드 개선
In [312]:
api = makeApiRequest('https://api.v1.example.com/search', q='secure', page=2)
print(api)
https://api.v1.example.com/search?q=secure&page=2
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: