답변:
이처럼 :
host = connectionDetails.get('host', someDefaultValue)
if/else훨씬 빠릅니다. 그것은 역할을 할 수도 있고하지 않을 수도 있습니다.
if/else더 빠른지에 대한 참조를 제공 할 수 있습니까 ?
다음 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"
get비슷한 방법에 적합하지 않습니다 .
하지만 .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
if/then 더 빠른지 여전히 알지 못한다 . 두 경우 모두 딕셔너리 조회가 필요하며 호출 get()이 너무 느리게 진행 되지 않으면 속도 저하를 설명하는 다른 요소는 무엇입니까?
O(1)사전 크기와 무관하므로 함수 호출 오버 헤드가 관련됩니다.
여러 다른 기본값의 경우 다음을 시도하십시오.
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
None되거나 키-값 쌍의 값 중 하나 인 emptyString 이 있으면 예기치 않은 결과가 발생할 수 있습니다 . defaults사전은 잠재적으로 그 값의 하나가 실수로 지워졌있을 수 있습니다. (또한 stackoverflow.com/questions/6354436 참조 )
파이썬 사전에는 다음과 같은 방법이 있습니다. dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
그러나이 방법의 값 설정 connectionDetails['host']에 someDefaultValue키가 경우 host이미 질문이 무엇을 요구 달리 정의되지 않습니다.
setdefault()값 을 반환하므로 다음과 같이 작동합니다 host = connectionDetails.setdefault('host', someDefaultValue). connectionDetails['host']이전에 키가 없었 으면 기본값으로 설정 됩니다.
(이것은 늦은 대답입니다)
대안은 클래스를 서브 클래 싱하고 다음 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'
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
이것을 위해 람바 함수를 하나의 라이너로 사용할 수 있습니다. connectionDetails2함수처럼 액세스되는 새 객체 를 만듭니다 .
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
이제 사용
connectionDetails2(k)
대신에
connectionDetails[k]
k키에 있으면 사전 값을 반환하고 , 그렇지 않으면 반환합니다"DEFAULT"