Corgi Dog Bark

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Efficient python Ch24. 동적인 디폴트 인자 관리법
    뜯고 또 뜯어보는 컴퓨터/파이썬 (Python) 2021. 7. 31. 13:30
    반응형
    • 우리는 종종 정적으로 정해지지 않은 타입의 값(동적 타입: list, dict 등등)을 함수의 인자의 값으로 써야할 때가 있다. 예를 들어 로그 메시지와 시간을 함께 출력하고 싶다고 하자.
    from time import sleep
    from datetime import datetime
    
    def log(message, when=datetime.now()):
        print(f'{when}: {message}')
    
    log("안녕")
    sleep(0.1)
    log("다시 안녕")
    더보기

    2021-07-31 13:06:21.846984: 안녕

    2021-07-31 13:06:21.846984: 다시 안녕

    • 하지만, sleep=0.1 이 호출되었는데도, 시간은 변하지 않고, 그대로 출력되었는데, 이유는 다음과 같다.
    • 파이썬에서는 default 인자는 함수가 호출될 때, 함수가 정의된 시점 딱 한번 정의된다. 따라서, 프로그램을 다시 시작하지 않는 한, defualt 인자는 변하지 않는다.
    • 따라서 일반적 관례는 default = None 을 지정하고, 실제 동작을 독스트링에 문서화 하는 것이다.
    def log(message, when = None):
        """메시지와 타임스탬프를 로그에 남긴다.
        
        Args : 
                message: 출력할 메세지
                when: 메시지가 발생한 시각
                      default 값은 현재 시간이다.
        """
        if when == None:
            when = datetime.now()
        print(f'{when}: {message}')
    
    log("안녕")
    sleep(0.1)
    log("다시 안녕")
    더보기

    2021-07-31 13:16:42.388444: 안녕

    2021-07-31 13:16:42.490728: 다시 안녕

     

    다음의 예시로 json 의 데이터를 받고, json 데이터를 load 했을 시, 잘못된 형식이면 비어있는 dict를 반환한다고 가정해보자

    import json
    
    def decode(data, default = {}):
        try:
            return json.loads(data)
        except ValueError:
            return default
            
    foo = decode("잘못된 데이터")
    foo["stuff"] = 5
    bar = decode("또 잘못된 데이터")
    bar["meep"] = 1
    print("foo",foo)
    print("bar",bar)
    더보기

    foo {'stuff': 5, 'meep': 1}

    bar {'stuff': 5, 'meep': 1}

    • 다음과 같이 심각한 오류를 야기할 수 있는데, 우리가 예상한 값은, foo {'stuff': 5} bar {'meep': 1}
    • 이런 값이었을 텐데, 값이 공유되었다. 어찌된 일일까??? 그 이유는 앞서 설명했듯이, 파이썬은 함수를 처음 정의 할때, 단 한번만 default값이 평가 되기 때문에, dict 값을 공유하게 되는 것이다. 따라서 이러한 일을 막기 위해서는 다음과 같이 함수인자의 default 값으로 None을 지정하고, 독스트링을 통해 문설화를 시켜주는 것이다.

     

    def decode(data, default = None):
        """ 문자열로부터 JSON. 데이터를 읽어온다.
        
        Args: 
            data: 디코딩할 JSON 데이터
            default: 디코딩 실패 시 반환할 값이다. 디폴트 값은 dict 값이다.
        
        """
        try:
            return json.loads(data)
        except ValueError:
            if default == None:
                default = {}
            return default 
        
    foo = decode("잘못된 데이터")
    foo["stuff"] = 5
    bar = decode("또 잘못된 데이터")
    bar["meep"] = 1
    print("foo",foo)
    print("bar",bar)
    더보기

    foo {'stuff': 5}

    bar {'meep': 1}

    • Ch 24. 기억해야 할 내용
    1. 디폴트 인자 값은 그 인자가 포함된 함수가 정의될때 딱 한번!!! 만 정의 된다. 그로 인해 동적인 값들({},[],/..) 는 이상한 동작을 할 수 있다.
    2. 동적인 값을 갖리 수 있는 키워드 인자의 디폴트 값을 표현할 때는 None 을 쓸 수 있도록 하자.
    반응형

    댓글

Designed by Tistory.