복붙노트

[PYTHON] 사전 및 기본값

PYTHON

사전 및 기본값

connectionDetails가 파이썬 사전이라고 가정하면 이처럼 코드를 리팩토링하는 데 가장 훌륭하고 가장 우아하고 파이썬적인 방법은 무엇일까요?

if "host" in connectionDetails:
    host = connectionDetails["host"]
else:
    host = someDefaultValue

해결법

  1. ==============================

    1.이렇게 :

    이렇게 :

    host = connectionDetails.get('host','someDefault')
    
  2. ==============================

    2.다음과 같이 defaultdict를 사용할 수도 있습니다 :

    다음과 같이 defaultdict를 사용할 수도 있습니다 :

    from collections import defaultdict
    a = defaultdict(lambda: "default", key="some_value")
    a["blabla"] => "default"
    a["key"] => "some_value"
    

    람다 대신 일반 함수를 전달할 수 있습니다 :

    from collections import defaultdict
    def a():
      return 4
    
    b = defaultdict(a, key="some_value")
    b['absent'] => 4
    b['key'] => "some_value"
    
  3. ==============================

    3..get ()은 훌륭한 숙어이지만, if / else보다 속도가 느립니다. (사전에서 키의 존재가 대부분 예상 될 수있는 경우를 제외하고 try / except보다 느립니다) :

    .get ()은 훌륭한 숙어이지만, if / else보다 속도가 느립니다. (사전에서 키의 존재가 대부분 예상 될 수있는 경우를 제외하고 try / except보다 느립니다) :

    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
    0.07691968797894333
    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
    0.4583777282275605
    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="a=d.get(1, 10)")
    0.17784020746671558
    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="a=d.get(2, 10)")
    0.17952161730158878
    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
    0.10071221458065338
    >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
    ... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
    0.06966537335119938
    
  4. ==============================

    4.여러 다른 기본값의 경우 다음을 시도하십시오.

    여러 다른 기본값의 경우 다음을 시도하십시오.

    connectionDetails = { "host": "www.example.com" }
    defaults = { "host": "127.0.0.1", "port": 8080 }
    
    completeDetails = {}
    completeDetails.update(defaults)
    completeDetails.update(connectionDetails)
    completeDetails["host"]  # ==> "www.example.com"
    completeDetails["port"]  # ==> 8080
    
  5. ==============================

    5.파이썬 사전에 이렇게하는 방법이 있습니다 : dict.setdefault

    파이썬 사전에 이렇게하는 방법이 있습니다 : dict.setdefault

    connectionDetails.setdefault('host',someDefaultValue)
    host = connectionDetails['host']
    

    그러나이 메소드는 키 호스트가 아직 정의되지 않은 경우 connectionDetails [ 'host']의 값을 someDefaultValue로 설정합니다.

  6. ==============================

    6.(이것은 늦은 대답이다)

    (이것은 늦은 대답이다)

    대안은 dict 클래스를 서브 클래스 화하고 다음과 같이 __missing __ () 메소드를 구현하는 것입니다.

    class ConnectionDetails(dict):
        def __missing__(self, key):
            if key == 'host':
                return "localhost"
            raise KeyError(key)
    

    예 :

    >>> connection_details = ConnectionDetails(port=80)
    
    >>> connection_details['host']
    'localhost'
    
    >>> connection_details['port']
    80
    
    >>> connection_details['password']
    Traceback (most recent call last):
      File "python", line 1, in <module>
      File "python", line 6, in __missing__
    KeyError: 'password'
    
  7. ==============================

    7.Python 3.3.5에서 PyPy (5.2.0-alpha0)의 상황에 대한 @Tim Pietzcker의 의혹을 테스트 한 결과, .get ()과 if / else 방식이 비슷하게 작동한다는 것을 알았습니다. 사실 if / else의 경우에는 조건과 할당이 동일한 키를 포함하는 경우 (심지어 두 개의 조회가있는 마지막 사례와 비교) 단 하나의 조회 만있는 것으로 보입니다.

    Python 3.3.5에서 PyPy (5.2.0-alpha0)의 상황에 대한 @Tim Pietzcker의 의혹을 테스트 한 결과, .get ()과 if / else 방식이 비슷하게 작동한다는 것을 알았습니다. 사실 if / else의 경우에는 조건과 할당이 동일한 키를 포함하는 경우 (심지어 두 개의 조회가있는 마지막 사례와 비교) 단 하나의 조회 만있는 것으로 보입니다.

    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
    0.011889292989508249
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
    0.07310474599944428
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="a=d.get(1, 10)")
    0.010391917996457778
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="a=d.get(2, 10)")
    0.009348208011942916
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
    0.011475925013655797
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
    0.009605801998986863
    >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
    .... stmt="if 2 in d:\n a=d[2]\nelse:\n a=d[1]")
    0.017342638995614834
    
  8. ==============================

    8.한 줄짜리 람바 (lamba) 함수를 사용할 수 있습니다. 함수처럼 액세스되는 새로운 객체 connectionDetails2 만들기 ...

    한 줄짜리 람바 (lamba) 함수를 사용할 수 있습니다. 함수처럼 액세스되는 새로운 객체 connectionDetails2 만들기 ...

    connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
    

    지금 사용하십시오.

    connectionDetails2(k)
    

    대신에

    connectionDetails[k]
    

    k가 키에 있으면 사전 값을 반환하고, 그렇지 않으면 "DEFAULT"를 반환합니다.

  9. from https://stackoverflow.com/questions/9358983/dictionaries-and-default-values by cc-by-sa and MIT license