Python Functions & Scope

miscaminos·2021년 4월 20일
0

python & data analysis

목록 보기
4/7
post-thumbnail

Functions

다시 리뷰하면서 remind 할것들을 정리한다.

수식: 변수, 연산자, 함수 호출 등 최종값을 만들 수 있는 것
문장: 수식을 포함해 한줄을 구성할 수 있는 모든 것

eval(), exec(), compile()
eval(): python 수식 형탱의 문자열을 인수로 받아서 실제로 실행시킬 수 있는
파이썬의 수식을 변환하여 실행까지 해준다 (문장은 넣을수없고 수식만 넣어야함)
exec(): 문장을 받아 파이썬 코드로 변환하고 실행해주는 함수

dir(), help(), input()
dir() : 현재 사용할 수 있는 변수들을 보여준다.
dir(객체) : 객체가 사용할 수 기능들을 보여준다.

help() : 주어진 값에 대한 도움말 기능이다.
print(help(myList.append)) #append()의 사용법이 출력된다.

input()는 사용자의 키보드 입력을 기다리기 때문에 화면을 잠시 정지시킬 수 있다. 엔터를 치면 다음 코드를 실행한다.

Scope

python namespace

python 변수 이름공간 namepace & scope
프로그래밍언어에서 Scope는 어떠한 객체(변수,함수 등)의 유효한 범위이다.
범위를 벗어나면 해당 객체는 사용될 수 없다.

변수를 찾을때 다음과 같은 순서의 범위에서 찾는다:
Local -> Enclosed -> Global -> Built-in

1) Local scope

def funcs():
    a=1
    print(a)

a는 funcs라는 함수안의 지역변수이다. 함수 밖에서 호출할수 없다.

2) Enclosed scope

함수 안에 또 다른 함수가있을때 적용되는 scope
밖의 함수가 부모 함수. 부모 함수에서 선언된 변수는 중첩함수 안에서도 유효한 범위를 갖는다

def outer():
    a=1
    print(a)
    def inner():
        b=7
        print(a+b)
    inner()
    print(b)

b는 inner()의 지역변수이기때문에, 부모함수 outer()에서 호출할 수 없다.

3) Glocal scope

global scope는 함수 밖에서 선언된 변수나 함수를 맣한다.
선언된 지점과 동일한 지역, 그리고 더 안쪽의 지역들까지 범위가 유효하다
선언된 지점이 해당 파일에서 가장 바깥쪽에서 선언되므로 해당 파일에서 선언된 지점
아래로는 다 유효한 범위를 가지고 있다.

k=1
def outer():
    a=1
    print(a+k)
    def inner():
        b=7
        print(a+b+k)
    inner()

4) Built-in scope

built-in scope는 scope중 가장 광범위한 scope이다
파이썬안에 내장되어 있는, 파이썬이 제공하는 함수 또는 속성들이 built-in scope를 가지고 있다.
built-in scope는 따로 선언이 없이도 모든 파이썬 파일에서 유요한 범위를 가지고 있다.

vars(), globals()

vars(): 이름공간에서 객체의 정보를 가져온다
globals(): 전역 이름공간에서 객체의 정보를 가져온다

x=100
vars()['x'] #결과값: 100
globals()['x'] #결과값: 100

지역변수를 전역변수로 바꾸고 싶으면 global keyword를 사용한다

var = '전역변수'
def scope():
    global var #global 명령어가 없으면 새로운 지역변수가 생성
    var = 'global 명령어의 역할'
    print('함수 안 var:',var)
    
scope()

scope()호출의 결과:
함수 안 var: global 명령어의 역할

함수에 함수 적용하기

outer() & inner():
inner 함수에서 inner()의 지역변수 y와 outer()의 지역변수 x를 사용한다.

def outer(x):
    def inner(y):
        return x+y
    return inner(5)
    
outer(20)

outer(20) 결과: 25

주의할점:

def outer(x):
    def inner(y):
        x+=1 # x=x+1 <-- 지역변수 x생성 = x검색
        return x+y
    return inner(5)
    
 outer(20)

outer(20) 결과: 에러
==> 여기 outer()의 변수x를 inner()에서 생성하려했기 때문에, 에러가 발생한다.
x=x+1 이 부분에서, 먼저 inner(local)에서 x를 찾는데, x는 inner에서 생성된적이 없기때문에 에러가 발생하는 것임.

def outer(x):
     def inner(y) : 
          nonlocal x #외부함수 영역에서 x변수를 찾아서 가져온다.
          x += 1  # x=x+1 <-- x가 nonlocal이기때문에, 지역변수 생성OK = 검색OK
          return x + y
     return inner(5)

outer(20)

outer(20) 결과: 26
위 example과는 다르게 다음에서는 에러가 발생하지 않는 이유는 nonlocal을 선언했기때문이다.

closure(클로져)

python은 함수를 객체로 처리함으로, 함수를 변수에 할당하거나 자료구조 안에 저장할 수 있다. 함수를 argument(인자)로 다른 함수에 전달해서 결과를 출력할 수 있다.

closure란 외부 함수로 부터 생성되 변수값을 내부 함수에서 바꾸거나 저장할 수 있는것이다. closure는 일반함수와 달리 자신의 영역 밖에서 호출된 함수의 변수를 사용할 수 있다. closure는 일반함수와 달리 생성 당시의 상태를 저장할 수 있다는점이 유용하다.

closure가 아닌 경우:

#외부함수의 지역변수는 그안의 모든 함수에서 접근할 수 있다
def outer_funce() :
    message = "python"
    def inner_funce():
        print(message)
    return inner_funce() #자신의 영역안에서 함수호출(클로저아님)

outer_funce()

outer_funce() 호출 결과:
python

내부함수에서 외부함수의 변수를 사용하면 외부함수의 변수가 자유변수가 된다. (자유변수(free variable)는 내부함수에서 사용됐지만, 그 내부함수 안에서 정의되지 않은 변수를 뜻함.) 내부함수에서 외부함수의 변수를 nonlocal로 정의할 경우 외부함수의 변수를 바로 참조해서 갱신할 수 있다.

클로저 환경을 구성하여 내부함수가 처리될때 외부함수의 변수도 계속 갱신처리하고 내부함수가 사용될 동안 외부함수의 변수를 내부함수에서 계속 사용이 가능하다.

closure만들기:

외부함수를 정의할때 내부함수를 실행하지 않고, 내부 함수 그 자체를 반환한다. 정의된 외부함수를 실행해서 변수에 할당하고, 그 변수의 정보를 확인하면 내부함수가 저장된것을 확인할 수 있다.

def closure(x):
    def inner(y):
        nonlocal x
        x = x * y
        return x
    return inner# 내부함수 자체를 리턴한다.
 
clo=closure(10)

clo

clo호출 결과:

<function __main__.closure.<locals>.inner(y)>

clo를 보면, inner(y) 내부함수가 저장되었다.

clo(30)

clo(30)호출 결과:
300
(외부함수의 결과값, 선언된 함수의 다른영역에서 내부함수 실행)

Function Decorator(함수 데코레이터)

함수의 인자로 함수를 받아 내부 함수에서 실행할때 다양한 공통기능을 처리한다. 함수 데코레이터를 만드려면, 데코레이터 기능을 처리하는 함수와 실제 실행하는 함수 두개를 만들어야함. 데코레이터 기능을 하려면 내부함수를 만드는데 그 내부함수는 항상 전달된 함수를 실행한 결과를 반환한다.

first class citizen: 변수에 할당할 수 있고, 다른 함수의 인자로 넘길 수 있는 함수를
일급객체(일급시민, first class citizen)라고 한다.

# 데코레이터 예시1
def alert_start(func):
    def new_func(*args, **kargs):
        print("함수가 시작됩니다")
        return func(*args, **kargs)
    return new_func

alert_start(print)('python')

출력결과:
함수가 시작됩니다
python


위 예시의 상세 과정:
start_func = alert_start(print) 
start_func('python')

alert_start(print)가 return하는 (print함수를 return할 예정인)new_func을 start_func변수가 받는다.

그리고, start_func가 실행되면 담아두었던 new_func가 실행되면서 "함수가 시작됩니다"가 출력되고 start_func, 즉 new_func()의 인자값으로 들어간 'python'이 print함수로인해 출력된다.



# 데코레이터 예시 2
def alert_end(func):
    def new_func(*args, **kargs):
        result = func(*args, **kargs)
        print("함수가 끝났습니다")
        return result
    return new_func

alert_end(print)('Java')

출력결과:
Java
함수가 끝났습니다


위 예시의 상세 과정:

end_func = alert_end(print)
end_func('Java')

alert_end(print)가 return하는 (new_func안에 정의된 내용을 구현할 예정인)new_func 함수를 end_func 변수가 받는다.

end_func가 실행되면, 담아두었던 new_func가 실행되면서 먼저 result=func('Java') 즉 result=print('Java')가 실행되고, 그 다음 줄 print("함수가 끝났습니다") 실행된다.



annotation 사용 decorator
# annotation으로 데코레이터 사용 예시
@alert_start
def sum_all(*args):
    return sum(args)
sum_all(1,2,3,4,5)

출력결과:
함수가 시작됩니다
15

# 여러개의 데코레이터 사용
@alert_end
@alert_start
def sum_all(*args):
    return sum(args)
sum_all(1,2,3,4,5)

출력결과:
함수가 시작됩니다
함수가 끝났습니다
15

아래와 같이 길게 늘어지는 코드를 decorator를 사용해서 더 간결하게 코드를 작성할 수 있다.

def sum_all(*args) :
    return sum(args)
 
sum_all(1,2,3,4,5)
 
alert_end(alert_start(sum_all))(1,2,3,4,5)

출력결과:
함수가 시작됩니다
함수가 끝났습니다
15

profile
Learning to code and analyze data

0개의 댓글