• 여러 개의 수행문을 묶은 실행단위
  • 반복 소스의 단순화(재활용 가능)
  • python은 멀티 패러다임이 가능한 언어 : 객체,절차,함수 지향 모두 지원
  • 내장함수와 외장함수가 있다.

내장함수

  • 일부만 사용해보았다.
# 합연산
sum([3,4,6])
# 캐스팅
int('5'); float('5.5'); str(5)+'오'
#eval
a=10
eval('a + 5')
# round
round(1.2); round(1,5) #round 반올림
# math
import math
math.ceil(1.2) #ceil 올림
math.floor(1.2) #floor 버림

bb = [1,2,3,5,1,1,2]
#all
res = all(a<5 for a in bb)
print('모든숫자가 5미만인가?',res)
#any
res = any(a<5 for a in bb)
print('숫자중 5미만이 있나?',res)
#zip : 각 객체가 담고 있는 원소를 튜플의 형태로 차례로 접근할 수 있는 반복자(iterator)를 반환
x = [1,2,3]
y = ['a','b']
for i in zip(x,y):
    print(i)

사용자 정의 함수

def DoFunc1():
    print('DoFunc1 수행')

DoFunc1() #사용시
DoFunc1 #함수 정보 확인
  • 파라미터 사용시
def DoFunc2(para1,para2):
    su1 = para1
    imsi = su1 + para2
    result = DoFunc3(imsi)
    print(result + 'DoFunc2 수행 끝',)

def DoFunc3(param1):
    print(param1)
    return "DoFunc3 성공 - "

DoFunc2(5,7)
============
12
DoFunc3 성공 - DoFunc2 수행 끝

사용자 정의함수 응용

if조건식에 함수사용.

  • 홀짝여부를 확인하여 True/False를 반환하는 사용자 정의 함수.
  • dict comprehension + for-if로 dict자료를 생성했다. 응용한 구조를 잘 확인하자
def isOdd(para):
    return para % 2 == 1

mydict = {x:x*x for x in range(1,11) if isOdd(x)}
mydict #{1: 1, 3: 9, 5: 25, 7: 49, 9: 81}

생존범위

  • 변수가 저장되는 공간은 어디서 선언되고, 치환됐는가에 따라 생존범위가 결정

  • 변수 접근 순서
    Local > Enclosing function > Global > Built-in

Local > Enclosing function 예시

player = '전국대표' #전역변수

def FuncSoccer():
    name = '임영웅' #지역변수
    player = '지역대표' 
    print(name,player) #지역변수를 우선 사용.

FuncSoccer() #임영웅 지역대표

global , nonlocal예시

  • global : 전역 변수의 값을 함수 내부에서 변경하고 싶을때 사용
  • nonlocal : 중첩 함수 내에서 비지역(nonlocal/closing) 변수를 대상으로 사용한다. (함수 바깥에서 선언된 비지역 변수의 값을 함수 안에서 갱신하고 싶은 경우)
#2 global 
a=10; b=20; c=30
print('함수 수행 전 : a:{},b:{},c:{}'.format(a,b,c))
def Foo():
    a = 40
    b = 50
    def Bar():
        global c # 지역내에서도 전역멤버로써 가르킴
        nonlocal b #b는 Bar의 멤버가 아닌 Foo의 멤버가 됨
        print('함수 수행 중 : a:{},b:{},c:{}'.format(a,b,c))    
        c = 60 #<<< !
        b = 70 #<<< !
    Bar()

Foo()
print('함수 수행 후 : a:{},b:{},c:{}'.format(a,b,c))   

함수 수행 전 : a:10,b:20,c:30
함수 수행 중 : a:40,b:50,c:30
함수 수행 후 : a:10,b:20,c:60
  • ! : 전역변수를 지역변수로 호출. c는 null이므로 err. global 사용시 전역변수로써의 변수저장이 이뤄짐

  • ! : 변수 앞에 nonlocal 키워드를 붙여주면 해당 변수는 새로운 지역 변수가 되지 않고 함수 밖에서 이미 선언된 비전역 변수를 가리키게 됨


인수와 매개변수 매칭 * / **

  • 매개변수 유형 : 위치, 기본값, 키워드,가변 매개변수 4가지가 있다.
#위치를 파라미터로.
def ShowGugu(start,end=5): #param-end에 기본값을 줌.
    for dan in range(start,end+1):
        print(str(dan) + '단출력')        
        
ShowGugu(3) #arg
ShowGugu(start=1,end=4) #키워드 명시 인수. 순서바꾸기 가능
# ShowGugu(start=1,4) # 주의 : 2번째 인자가 그냥 주어질시 err. 
  • * :packing 연산자를 사용하여 가변 인수 처리.
    인수의 개수가 가변적일 경우 사용한다.
def func1(*param):
    print(param)
    for i in param:
        print('음식 : ' + i)
    
func1('공기밥','김밥','주먹밥') #tuple
$result... ('공기밥', '김밥', '주먹밥')

==============
# 첫 인수가 a로, 나머지는 packing된다. *이 앞에있으면 err
def func2(a,*param):
    print(a)
    print(param)
func2('공기밥','김밥','주먹밥') 
  • packing 응용.
    choice에 문자열이 담기고,ar에 1~5 튜플저장.
def selectProcess(choice,*ar):
    if choice == 'sum':
        re = 0
        for i in ar:
            re += i
    elif choice == 'mul':
        re = 1
        for i in ar:
            re *= i
    return re

selectProcess('sum',1,2,3,4,5)
selectProcess('mul',1,2,3,4,5)
  • 사전형 데이터인 경우**을 사용한다
# 사전형 데이터인 경우 **을 사용
def func3(w,h,**other):
    print('몸무게{},키{}'.format(w,h))
    print(other)
    
# 인수1,인수2,dict(키:값),dict(키:값)
func3(66,177,irum='지구인',nai=22) 

def func4(a,b,*c,**d):
    print(a,b)
    print(c)
    print(d)
    
func4(1,2)
func4(1,2,3,4,5) #3,4,5는 튜플로
func4(1,2,3,4,5,x=6,y=7) # 3,4,5 튜플 / dict형 2개

클로저 Closure

  • 함수 내에서 선언한 변수,객체를 함수 밖에서도 참조하고 싶을 때 사용한다.
  • Scope에 제약을 받지 않는 변수들을 포함하고 있는 코드블럭.
  • 내부 함수의 주소를 반환함으로 해서 함수 내의 멤버를 밖에서 참조가능
def outer():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    #inner()
    return inner #<-clouser : 내부함수의 주소 반환
    
var1 = outer()
print(var1()) # 1 (var1주소) 
aa = var1()
print(aa) # 2 (var1주소)

var2 = outer()
print(var2()) #1 (var2주소) 
  • 함수 내 count 변수를 함수 밖에서 참조했다. 내부의 함수 주소를 반환하는 것이 포인트.
  • java의 new 인스턴스와 같이 각기 다른 객체가 사용됨

closure param 응용

#수량 * 단가 * 세금(분기마다 다름)을 출력하는 함수 작성
#Closure parameter사용
def outer2(tax):
    def inner2(su,dan):
        amount = su * dan * tax
        return amount
    return inner2

#1분기: tax: 0.1부과 
q1 = outer2(0.1) #객체 생성시 outer(tax) 주어짐.
result1 = q1(5,50000) #인스턴스 사용시 inner(su,dan) 사용됨
print('result1 : ',result1)
result2 = q1(2,10000)
print('result2 : ',result2)

#2분기: tax : 0.05부과
q2 = outer2(0.05) #객체 생성시 outer(tax) 주어짐.
result3 = q2(5,50000) #인스턴스 사용시 inner(su,dan) 사용됨
print('result1 : ',result3)
result4 = q2(2,10000)
print('result2 : ',result4)

1급 함수

  • 특정 프로그래밍 언어에서 함수가 일급이라는 것은 다음의 조건을 만족하는 경우 일급 함수라고 한다.
  1. 함수 안에 함수 선언가능
  2. 인자로 함수 사용가능
  3. 반환값이 함수일때,

아래 1급함수 코드에서 조건 3개를 확인해보자.

def func1(a,b):
    return a+b

def func2(param1): #조건 2
    def func3(): #조건 1
        print('내부함수 print')
    func3()
    return param1 #조건 3

#mbc는 func1의 주소를 갖게됨.
mbc = func2(func1)  #조건 2
print(mbc(3,4))

람다 함수

  • 이름이 없는 함수 (축약함수)
  • def를 쓸만큼 복잡하지 않거나 def를 쓸 수 없는 곳에서 사용할 수 있다.

먼저 함수의 원형을 확인해보자.

def hap(x,y):
    return x+y
hap(1,2)

당연히 결과는 3이다. 람다함수로 바꿔 표현해보았다.

#1>
(lambda x, y:x + y)(1,2)

#2>
aa = lambda x, y:x + y
aa(1,2)
  • lambda키워드 다음 파라미터 x,y:연산식 그리고 직접 사용될 인수값 1과 2를 넣는다.

  • 인수가 없을땐 bb = lambda:5+10 와 같이 작성할 수 있다.

위에서 했던 기본값, 이름에 의한 매핑을 람다에서도 사용할 수 있다.

kbs = lambda a ,su=10:a + su
print((kbs(3))) #13
print((kbs(3,6))) #9

인자를 1개 줬을때 a=3, su=10(기본값) 으로 연산.
인자를 2개 줬을때 a = 3, su=6으로 연산된다.

키워드와 가변인자 + 람다

sbs = lambda a, *tu,**di:print(a,tu,di)
sbs(1,2,3,m=4,n=5)
# 출력 : 1 (2, 3) {'m': 4, 'n': 5}..
  • a = 1
  • *tu = 2,3 (tuple)
  • **di = m=4,n=5 (dict)

lambda 배열 일괄 계산

li = [lambda a,b:a+b, lambda a,b:a*b]
li[0](3,4)
li[1](3,4)

filter함수에서 lambda 축약 사용하여 리스트 만들기

  • filter(조건 함수, 순회가능한 데이터)
  • 여러개의 데이터로부터 일부의 데이터만 추려낼때 사용
list(filter(lambda a:a < 5,range(10)))

list(filter(lambda a:a % 2,range(10))) #0이면 false. 짝수를 필터링한다.

# 1~100 사이 정수 중 5의 배수이거나 7의 배수만 걸러 출력
list(filter(lambda a:a%7==0 or a%5==0,range(101)))

함수장식자 function decorator @

  • 함수를 수정하지 않고도 유연하게 함수에 특정 동작을 추가하거나 작동 방식을 바꿀 수 있다.

먼저 원형을 확인해보자

# 원형
def make2(fn):
    return lambda:'안녕'+fn()
def make1(fn):
    return lambda:'반가워' + fn()
def hello():
    return '홍길동'

hi = make2(make1(hello))
print(hi())

함수를 인자로 받는 함수를 장식자로 정리 해버릴 수 있다

# 함수 장식자
@make2
@make1
def hello2():
    return '홍길동'

hello2()

다른 형태로도 확인해보았다.

def trace(func):
    def wrapper(a,b):
        r = func(a,b)
        print('함수명 {0} (a={1},b={2})->{3}'.format(func.__name__,a,b,r)) 
        return r
    return wrapper #closure

@trace
def add(a,b):
    return a+b

add(10,20)

#result : 함수명 add (a=10,b=20)->30
  • trace함수는 함수를 인자로 받고, 내부에 wrapper라는 함수를 선언하고있다.
    wrapper함수는 trace함수의 인자로 넘어온 함수를 호출한다.

  • 이제 add함수를 trace함수로 인자로써 넘겨보자.
    add가 실행되기 이전에 데코레이터인 @trace 함수가 실행되어 출력되었다


재귀함수

  • 함수가 자신을 호출
def countDown(n):
    if n == 0:
        print('함수 수행 완료')
    else:
        print(n,end=" ")
        countDown(n-1) #재귀함수
        
countDown(5) 
#5 4 3 2 1 함수 수행 완료

0개의 댓글