[TIL] Python - Function (2)

Hailee·2020년 11월 22일
0

[ TIL ]

목록 보기
13/40
post-thumbnail

정확히 필요한 parameter 수와 그 구조를 알 수 없는 경우?

def buy_A_car(options):
    print(f"다음 사양의 자동차를 구입하십니다:")


    for option in options:
        print(f"{option} : {options[option]}")


options = {"seat" : "가죽", "blackbox" : "최신"}


buy_A_car(options)


> 다음 사양의 자동차를 구입하십니다:
seat : 가죽
blackbox : 최신

👉🏻 dictionary를 parameter로 받아서 사용한다!

하지만 parameter로 무조건 dictionary만 받아야한다는 제약조건이 생긴다.
아무값도 안넘겨주거나 String을 넘기면 오류 날 가능성이 높다
(아무 값이 없을 때에도 빈 배열로 넘겨줘야 할 판!)

이럴 때 사용할 수 있는게 keyworded variable length of arguments!
: 수가 정해지지 않고 유동적으로 변할 수 있는 keyword arguments
: parameter 앞에 별표 두개 붙이기 **

**kwargs

  • argument 수를 유동적으로 (0~N) 넘겨줄 수 있다
  • 미리 정해져있지 않기 때문에 원하는 keyword를 유동적으로 사용할 수 있다
  • dictionary형태로 지정된다.
def buy_A_car(**kwargs):
    print(f"다음 사양의 자동차를 구입하십니다:")
-
    for option in kwargs:
        print(f"{option} : {kwargs[option]}")

이렇게 선언된 함수는 다음과 같이 호출할 수 있다

buy_A_car(seat="가죽", blackbox="최신", tint="yes")

kwargs 파라미터는 dictionary형태로 함수에 전달되기 때문에

{'seat': '가죽', 'blackbox': '최신', 'tint': 'yes'}


함수의 body 내에서는 dictionary처럼 kwargs를 사용하면 된다.

keyword를 사용하지 않고 순서대로 값을 전달하는 방식은?

*args

  • tuple로 변환되어 함수에 전달된다

둘 다를 섞을 수도 있는데,
이는 어떠한 형태와 수의 argument도 허용하기 위해서!
(parameter에 있어서 엄청 유동적인 함수가 되는 것!)

👇🏻👇🏻 내가 푼 코드

def sum_of_numbers(*args, **kwargs):
  result = 0
  if len(args) == 0:
    return result
  else:
    for i in args:
      result += i
    return result

def what_is_my_full_name(**kwargs):
  temp = dict(reversed(list((kwargs).items())))
  print(temp)

  name = ""

  for arg in temp:
    if "last_name" in temp or "first_name" in temp:
      if "last_name" in temp and "first_name" in temp:
        if arg == "last_name":
          name += temp[arg]
        if arg == "first_name":
          name += " " + temp[arg]
      elif "last_name" in temp and "first_name" not in temp:
          if arg == "last_name":
            name += temp[arg]
      elif "last_name" not in temp and "first_name" in temp:
          if arg == "first_name":
            name += temp[arg]
    else:
      name = "Nobody"

  if len(temp) == 0:
    name = "Nobody"
    
  return name

정말 지저분 + 이리저리 막기만 한 코드..ㅎㅎ

👇🏻👇🏻 다른 분 코드

def sum_of_numbers(*args):
  return sum(args)

def what_is_my_full_name(**kwargs):
  if "first_name" in kwargs.keys():
    if "last_name" in kwargs.keys():
     return kwargs["last_name"] + " " + kwargs["first_name"]
    else:
      return kwargs["first_name"]
  else:
    if "last_name" in kwargs.keys():
      return kwargs["last_name"]
    else:
      return "Nobody"

*kwargs, args를 잘 활용해서 다시한번 공부해보자!

이미 전에 Function(2) 게시글에 정리했지만,
wecode notion 보고 다시한번 정리하기!


중첩 함수 (Nested Function)


👆🏻 decorator에 대한 개념이 없어
하나도 이해하지 못한 채 풀던 나자신..(애잔)

nested function

  • 중첩 함수
    : 함수 안에 함수가 선언된 것!
    : 상위 부모 함수 내에서만 호출될 수 있다
    : 가독성, Closure 때문에 사용

가독성

def print_all_elements(list_of_things):
    ## 중첩함수 선언
    def print_each_element(things):
        for thing in things:
            print(thing)

    if len(list_of_things) > 0:
        print_each_element(list_of_things)
    else:
        print("There is nothing!")

함수 내에 반복되는 코드가 있다면 중첩함수로 선언하여 가독성 높여주어야 한다
all_elements 함수 내에 each_elements 함수를 선언해두고,
필요에 따라서 내부 함수만 반복하도록 한 상황!

closure

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


    child_function()


parent_function()
> "this is a child function"

부모함수의 변수, 정보를 가두어 사용하기 위해 중첩함수를 사용하기도 한다

  • 부모 함수의 변수를 외부로부터 직접적인 접근은 격리하지만
  • 격리된 부모함수의 변수를 중첩 함수를 통해 연산한다
  1. 중첩 함수가 부모 함수의 변수나 정보를 중첩 함수 내에서 사용한다.
  2. 부모 함수는 리턴값으로 중첩 함수를 리턴한다.
  3. 부모 함수에서 리턴 했으므로 부모 함수의 변수는 직접적인 접근이 불가능 하지만 부모 함수가 리턴한 중첩 함수를 통해서 사용될 수 있다.
    : factory 패턴 구현 시, 함수나 오브젝트 생성해 낼 때
    설정값을 노출하지 않아서 수정이 불가능하도록 만들 때 사용!
def generate_power(base_number):
    def nth_power(power):
        return base_number ** power


    return nth_power
 
calculate_power_of_two = generate_power(2)
calculate_power_of_two(7)
> 128
calculate_power_of_two(10)
> 1024


calculate_power_of_seven = generate_power(7)
calculate_power_of_seven(3)
> 343
calculate_power_of_seven(5)
> 16907

특정 숫자의 승을 구하는 함수인데
그때그때 설정되는 수의 승을 구하는 함수이다!

def calculate_power_of_two(power):
    return 2 ** power


calculate_power_of_two(7)
> 128
calculate_power_of_two(10)
> 1024

혹은

def calculate_power(number, power):
    return number ** power


calculate_power(2, 7)
> 128

를 사용하면 2의 승을 구하는 함수이지만
위와같이 중첩함수를 사용하면
매번 들어오는 parameter 숫자의 승을 구할 수 있다!


Decorator (1)

데코레이터 강의
데코레이터 라는 개념이 정말 이해가 잘 되지 않았는데, 해당 강의를 듣고 많이 도움이 되었다.

데코레이터란,

  • 함수를 parameter로 받아서 작동하는 것!
  • 클래스에서 메서드 만들 때 @로 시작하는 decorator들을 많이 사용한다고..
  • @decorator를 붙여서 선언된 함수는
    그 함수가 실행되기 전에 decorator역할의 함수가 먼저 실행되고, 그 후에 기존 함수가 실행되는 것!
    : 함수를 수정하지 않은 상태에서 추가기능 구현할 때 사용된다고 한다!


👆🏻 함수 안에서 함수 만들고 return하기

도대체 decorator가 어떤 순서로 왜 진행이 되는지 궁금했는데
👇🏻👇🏻 아래 그림을 보고 좀 이해가 되었다

decorator를 붙여서 선언된 함수를 실행하면 해당 함수가 실행되기 전에
decorator로서 선언된 함수로 이동해서, 매개변수로 받은 호출할 함수를 돌리는 것!

그래서 decorator로서 선언된 함수 내부가 먼저 실행되고, (trace - wrapper)
그 뒤에 decorator를 선언한 함수가 호출되는 것!! (hello)


Decorator (2)

매개변수와 반환값 처리하는 데코레이터

profile
웹 개발 🐷😎👊🏻🔥

0개의 댓글