TIL #31 Python : Nested Function( + Decorator) / Scope / Class

채록·2021년 1월 19일
0

Python & Django

목록 보기
3/34
post-thumbnail

🐶 들어가는 말

Python Repl.it : #53 ~ #58 에서 다룬 개념들을 정리했다.!
확실히 text를 읽는것보단 실습이, 실습보단 개념을 정리해 나의 단어로 정리하는것이 이해하는데 가장 효과적인거같다! (내 기준!!ㅎㅅㅎ)





I. Nested Function 중첩함수

중첩 함수는 말 그대로 함수를 중첩해서 사용하는 것이다. 즉, 함수 속에 또다른 함수가 존하여 내부 함수의 값이 부모 함수의 값에 영향을 준다.

다음과 같은 예시가 있다.

def parent_function():
    def child_function():
        print("this is a child function")
    child_function()

parent_function()
-> "this is a child function"

먼저 부모함수인 parent_function() 안에 내부함수인 chile_function()이 존재한다. 각각 함수의 기능은 다음과 같다.

  • 내부함수는 "this is a child function"이라는 구문을 출력하는 기능을 하는 함수
  • 부모함수는 child_function이라는 기능을 수행하는 기능을 하는 함수이다.

때문에 부모함수의 기능을 호출하면 결론적으로 내부함수의 기능까지 수행되는 것이다.



1. 중첩 함수의 의의

크게 두가지가 있다.

  1. 가독성
  2. Closure

1) 가독성

여러개의 함수가 존재하는데 그 함수들 안에 모두 공통된 코드가 존재한다면? 매번 같은 코드를 입력하는 것은 비 효율적이고, 한눈에 같은 코드임을 파악하기가 어렵다! 때문에 반복되는 코드는 또 다른 함수로 정의하여 함수안에 함수로 입력하는 것이다.

2) Closure

사전적 의미로 폐쇄를 뜻한다 즉, "무언갈 가둔다" 라는 것이다.

Python의 중첩함수에서 closure는 중첩 함수가 부모 함수의 변수나 정보를 가두어 사용하는 것을 의미한다!!
그리고 나서 부모함수는 중첩 함수를 return 한다.

부모함수의 변수를 외부로부터 직접적인 접근은 격리 하면서, 동시에 중첩 함수를 통해 격리된 부모함수의 변수를 사용한 연산은 가능하게 한다.

이런 특성을 이용해 중첩함수를

" 어떤 정보를 기반으로 연산을 실행하고 싶지만 기반이 되는 정보는 접근을 제한하여 노출이 되거나 수정이 되지 못하게 하고 싶을 때 "

사용한다.



2. 중첩함수 예시

다음과 같은 코드가 있다고 가정한다.

def calculate_power_of_two(power):
    return 2 ** power


calculate_power_of_two(7)
-> 128

수 2에 대해 특성 숫자(변수 power에 대입) 승을 구하는 함수이다. (출력예시 = 2의 7승 => 128)

만약 수 2 뿐만이 아니라 다양한 수에 대해서 위와 같은 계산을 진행하고 싶다면?? 새로운 숫자에 대한 함수를 만들면 된다!

def generate_power(base_number):
    def nth_power(power):
        return base_number ** power
        
    return nth_power

calculate_power_of_two = generate_power(2)

calulate_power_of_two(7)
-> 128

사실 위의 예시로는 이해가 잘 안됐다. 문제의 개념을 직관적으로 파악하기 어려운 구조라고 생각한다;;;;,,, (내 기준)

다음에 나올 Decorator의 개념을 알면 더 쉽게 이해할수 있다!!



3. Decorator

Decorator는 closure 개념을 이용해 사용하는 고급 기능이다.
표현은 @데코레이터명으로 표현한다.


1) Decorator의 기능

Decorator는 방금 말했듯이 closure 개념을 이용해 사용하는 고급 기능이다. 따라서

  • (closure 처럼) 중첩함수를 리턴하는 함수이다.
  • 특정 함수를 실행하기 전에 강제적으로 다른 함수가 먼저 실행된 후 실행되도록 하는 강제성을 제공하는 기능이다.

2) 사용 예시

def welcome_decorator(hello):
  def wrapper():
    return hello() + "welcome to WECODE!"
  return wrapper


@welcome_decorator
def greeting():
  return "Hello, "

이거은 welcome_decorator라는 데코레이터를 사용한 것이다. 이는 중첩함수인 wrapper를 리턴하는 함수로, 그 함수가 실행되기 전에 강제적으로 greeting함수가 먼저 실행되도록 한다.

각 함수의 리턴값을 살펴보면

  • greeting 함수는"Hello, "를 return 하는 함수
  • 중첩함수(wrapper함수)는 welcome_decorator의 변수로 들어온 값 뒤에 "welcome to WECODE!"를 리턴
  • 최종적으로 welcome_decorator가 중첩함수의 값을 리턴

위의 예시에서 중첩함수가 리턴하는 hello()는 아래에 쓰인 welcome_decorator라는 데코레이터와 관련된 함수 greeting()의 return 값을 의미한다.

(hello는 임의의 단어를 기입한 것이다. 중첩함수에서 입력해주어야 하므로 공백으로 둘 수 없었다.)





II. Scope

Scope 이란 범위를 뜻한다.
그리고 프로그래밍 언어에서 Scope이란 어떠한 객체 (변수, 함수 등)가 유효한 범위를 의미한다. ! 범위를 벗어나면 해당 객체는 사용되지 못한다 !

1. Python의 Scope

Python에서는 Scope을 그림과 같이 4개 범위로 나눌 수 있다.

  • Builtin Scope
  • Global Scope
  • Enclosing Scopes
  • Local Scope

어떤 범위가 가장 제한적이고, 가장 광범위한지는 그림을 통해서 충분히 이해 할 수 있다.!!
그리고 미리 말하지만 이러한 Scope은 해당 객체가 처음 정의된 Scope에 대해서 제한적이지 않고 상대적이다. (객체의 위치에 따라 Scope의 범위가 변할 수 있다는 의미)

1) Local Scope

가장 제한적인 범위(Scope)이다.

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

이 함수에서 변수 a가 유효한 범위는 func()안의 코드 두 줄이다.
함수 안에서 선언되었디 때문이다. 즉, local scope이다.
만약 위의 a 변수가 func()함수 밖에 print(a)로 존재한다면 제대로 출력이 될까?

def func():
    a = 1
print(a)
-> NameError: name 'a' is not defined

당연한 결과지만 a 를 정의할 수 없다는 에러가 뜬다.(NameError)

2) Enclosing Scope

중첩함수가 있을때 적용되는 Scope이다.
부모함수에서 선언된 변수를 중첩함수 안에서도 유효한 범위를 갖고 있다.

def func():
    a = 1
    print(a)
    
    def inner():
        b = 7
        print(a * b)
        
    inner()
  • 위 구조에서 변수 a는 a=1부터 inner()까지 유효하다.
    (변수 a는 enclosing scope으로 inner()함수 속에서도 유효하다!)

  • 그에비해 변수 b는 local scope으로써 inner()함수 속의 b=7부터 print(a * b)까지만 유효하다.

만약위의 구조에서 변수 b를 inner()함수 밖에서 사용하면 어떻게 될까?

def outer():
    a = 1
    print(a)
    
    def inner():
        b = 7
        print(a * b)
        
    inner()
    print(b)
    -> NameError: name 'b' is not defined

3) Global Scope

함수 "안"이 아닌 함수 밖에서 선언된 변수나 함수를 이야기 한다.
-> 해당 파일의 가장 바깥에서 선언되었으므로 선언된 지점 아래로는 다 유효한 scope를 갖고있다.

g = 8

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

위 구조와 같이 함수 밖에서 선언된 변수 g는 선언 지점 아래로 모두 유효함으로 함수 / 중첩함수 내에서도 모두 유효하다.

4) Builtin Scope

가장 광범위한 Scope이다. 우리가 작성하는 것이 아니라 Python 안에 내장되어 Python이 제공하는 함수 또는 속성들을 의미한다.
때문에 별다른 선언 없이 모든 python 파일에서 유효한 scope을 갖고 있다.


2. Shadowing

동일한 이름의 변수들이 서로 다른 scope에서 선언이 되면 더 좁은 범위에 있는 변수(혹은 함수)가 더 넓은 범위에 있는 변수를 가리는 (shadowing)효과

어떤 함수/변수의 값을 찾기 위해 python에서는 local ---> builtin 순으로 찾는다.
좁은 범위 ---> 광범위한 범위 임을 잊지말자!!





III. Class

동일한 범주에 속하는 대상들을 일정한 기준에 따라 나누어 놓은 갈래

과일 에는 사과, 바나나, 수박이 있다.
그렇다면 여기서 Class 는 ? 과일 이 된다.
그러면 과일 class에 속하는 사과, 바나나, 수박은 뭐라고 부르는가 ? 이것들은 실체(instance)들이다.! 이것들을 객체(object)라고 부른다.

그 다음 내용은 추가할꺼임 ~^*^

profile
🍎 🍊 🍋 🍏 🍇

0개의 댓글