본문 바로가기

노력/인공지능

4. 파이썬 개인공부 4 (반복)

피보나치 수열 : 1 1 2 3 5 8 13 ...



dynamic programming : 결과를 계속 이어서 사용하는 기법 -> 가장 기본적으로 피보나치 구현하는 방법


def fib(n):

    a, b = 0, 1

    while a < n:

        print(a, end=' ')

        a, b = b, a+b

    print()

    

이런 식으로 구현하면 dynamic programming이라고 할 수 있다.


a = 3

b = 4


a,b = b,a 이런식으로 스왑가능하다. -> 이 기법에 익숙해져야 한다.


재귀 : 나를 나보다 더 작은 단위로 나누어서 다시 호출하는 방식



느려서 재귀방식을 쓰지 말라고 하는 언어가 있다.


현대적인 언어들은 언어단에서 function의 결과를 저장해서 다시 재귀함수의 속도가 느리지 않다.


파이썬은 tail recursion이라는 방법이 언어단에서 지원되지 않기 때문에 느리다.


인공지능에서는 재귀적 기법을 사용하면 당연히 느릴 수 밖에 없다.


look-up table : base case는 미리 다 계산해놓고 사용하는 것, 자주 사용하는 것은 그냥 저장되어 있어서 가지고 온다.

 

def fibBB(num): 

    if num < 10:

        return [0,1,1,2,3,5,8,13,21,34,][num]#17 base cases

    return fibBB(num-1) + fibBB(num-2)




    


    

dynamic programming도 look-up table을 미리 만들어 놓을 수 있다. (memoization)




def memoize(function):

    dict = {}                      

    def wrapper(num):           

        if num not in dict:

            dict[num] = function(num)

        return dict[num]

    return wrapper


@memoize    

def fibB(num):    

    if num < 3: return 1

    return fibB(num-1) + fibB(num-2)

    

@memoize를 사용하면

재귀함수임에도 동적으로 사용할 수 있게 해준다.



프로파일링 : 메모리, 속도체크하는 것




로컬변수와 글로벌변수 ->  


for i in range(1, 100):

    print(i)


이것을 입력하고 나면 i가 쓰레기값이 될거라고 생각하지만 파이썬에서는 기존값이 그대로 남아있다.


i를 다시 출력해보면 i는 99가 나온다


print(i) : 99




파이썬에서는 로컬변수라고 할 수 있는 애는 함수만 사용한다. 클래스는 조금 더 다르다.


로컬변수 -> 함수안에 있는 변수


def x(a):

    b = a+1

    return b

    

함수안에서 일시적으로 사용되는 변수.


함수에서 나와서 b를 입력하면 값이 없다. 함수 안에서만 유효하기 때문이다.




c = 7

def x():

    return c

    

c는 정상적으로 출력된다. c라는 글로벌변수를 x()라는 함수에서 사용가능하다.





c = 7

def x():

    c = c+1

    return c





정상적으로 실행된다. 구문 맞음.


x() -> UnboundLocalError : 참조만 할 수 있다. 글로벌변수가 사용가능하다는 것은 참조가 가능하다는 것이지 값을 바꿀 수는 없다.






c = 7

def x():

    global c

    c = c+1

    return c

    

x() : 8


global이라는 키워드를 사용해 글로벌변수에 대한 접근권한을 가지고 올 수 있다. 사용할 수 있게 된다.


6번째 할당 : global


global 있지만 쓰지 말라고 함. (goto처럼 이론상 별로 좋지 않다.)


함수 밖의 값을 바꾸게 되기 때문에 실수가 생길 확률이 높다.



c = 7

def x():

    d = c+1

    return d

    

x() : 8




고차함수 (higher-order function) : 


def outer():

    def inner():

        return 1

    return inner

    

x = outer()


x() : 1





def outer():

    n = 4

    def inner():

        a = 3

        return 1

    return inner

    

inner입장에서는 n이 로컬변수도 아니고 글로벌변수도 아니다. 이런 변수를 nonlocal 변수라고 부른다.



a = 3

def x():

    a = 5

    return a

    

x() : 5  -> 5가 출력된다.


LEGB순서대로 찾는다. Local, E(겹쳐져있을 때 바로 밖의 함수 변수), Global, Built-in



def outer():

    a = 3

    def inner():

        nonlocal a

        a = a+1

        return a

    return inner()

    

이런 형태로 사용하면 global도 아니고 local도 아닌 바로 밖의 함수변수 nonlocal 변수를 변경할 수 있다.




a = 7

def outer():

    a = 3

    def inner():

        global a

        a = a+1

        print(a)

        return a

    return inner()


    

global과 nonlocal을 명시함으로써 어디에 있는 변수를 변경하고 사용할 지 알 수 있다. (접근권한)




builtin은 import builtins 안써도 사용할 수 있다.




advanced pattern : text.upper() -> 대문자로 바꾸어 주는 함수


__add__ : 매직 메소드, 스페셜 메소드





def yell(text):

    return text.upper()+'!'


yell('sun')

'SUN!'


bark = yell (복사된다. 참조가 아니라)




bark('woof')

'WOOF!'



del yell (yell을 삭제한다.)


bark('hey')

'HEY!' yell이 삭제되어도 bark는 멀쩡하다.




First Class Function : Function이 값처럼 쓰일 수 있다.


파이썬은 argument에 function을 넣을 수 있다.


값이니까 배열도 만들 수 있고, function에도 넣을 수 있고, 뭐든지 할 수 있다.



funcs = [bark, str.lower, str.capitalize]


funcs[0]('aaa')


배열 안의 값이 함수일 수도 있다.



def greet(func):

    greeting = func('Hi, I am a Python Programmer')

    print(greeting)

    

greet(bark) : HI, I AM A PYTHON PROGRAMMER!


함수 이름이 들어오면 바로 'Hi, I am a Python Programmer' 이 문자열에 적용된다.



def whisper(text):

    return text.lower() + '...'


greet(whisper)


함수에서 다시 함수 이름을 쓰면 바로 기능이 변경된다.    


*args -> 가변인자


**kwargs -> 가변positional




map(func, *iterables) --> map object


*iterables  




unpacking advanced : 




a = {'a':1, 'b':2}


return b

def x(**b):

    return b


    

x(a=1, b=2)

{'a': 1, 'b': 2}


x(**a)

{'a': 1, 'b': 2}



딕셔너리는 언패킹해서 쓰려면 **를 사용해야 한다.



a = {'a':1, 'b':2}

b = {*a}


b

{'a', 'b'} : 별표를 하나만 사용하면 키만 사용할 수 있다.



a = {'a':1, 'b':2}

b = [*a]


이것처럼 별표 하나만 써서 키의 리스트를 만들 수도 있다.



b = {**a, 'b':7}


이것처럼 다른 a라는 딕셔너리를 언패킹하면서 'b'라는 키의 값을 변경할 수도 있다.









map(func, *iterables) --> map object


*iterables 


t = map(bark, ['hello', 'hey'])


t[0] : TypeError -> 순서가 없다는 것을 알 수 있다. 인덱싱이 불가능함


for i in map(bark, ['hello', 'hey']):

    print(i)

    

위의 문법이 가능하다. iterable이라는 것을 의미함.



함수의 이름만 있으면 함수를 반환하는 것이고 함수에 괄호까지 달려있으면 값을 반환하는 것이다.


def speak(text):

    def whisper(t):

        return t.lower()+'...'

    return whisper(text)

    

text가 whisper(text)에 들어와서 whisper 실행.







import에 대해 배우기 시작:


LEGB, Advanced_function, Accumulation Pattern, 다시보기



import라는 것은 기본적으로 모듈을 가져오는 것이다.



moon.py : 


a = 3




import moon


moon.a : 3출력된다.


import의 기본사용법은 이런식이다.



from moon import a


%whos

Variable      Type      Data/Info

---------------------------------

a             int       3

antigravity   module    <module 'antigravity' fro<...>a3\\lib\\antigravity.py'>

autopep8      module    <module 'autopep8' from '<...>e-packages\\autopep8.py'>

json          module    <module 'json' from 'C:\\<...>\lib\\json\\__init__.py'>

moon          module    <module 'moon' from 'C:\\<...>ers\\ultim\\ai\\moon.py'>



from을 사용하면 namespace 안에 들어오기 때문에 내가 쓰고싶은대로 쓸 수 있다.


하지만 a처럼 쉬운 이름을 가진 식별자가 내 프로그램에도 있을 수 있다. 충돌의 가능성이 있다.


import 대신에 as를 사용해서 더 작게 사용가능하다.



import moon as m


m.a : 3


이렇게 축약해서 사용할 수 있다.




from moon import a as ab


이렇게 가져온 함수나 이름에게도 별칭을 만들어서 별칭으로 사용할 수 있다.



import에는 파이썬 파일만 사용할 수 있다.



import sys

sys.path : list 반환


list에 넣어주면 된다. import 할 위치를 추가할 수 있다.