사전을 '구조화'하고 키 뒤에 값을 변수 이름과 연결하려고합니다. 같은 것
params = {'a':1,'b':2}
a,b = params.values()
사전 주문한되지 않기 때문에 그러나, 보장은 없습니다 params.values()
순으로 값을 반환은 (a, b)
. 이 작업을 수행하는 좋은 방법이 있습니까?
사전을 '구조화'하고 키 뒤에 값을 변수 이름과 연결하려고합니다. 같은 것
params = {'a':1,'b':2}
a,b = params.values()
사전 주문한되지 않기 때문에 그러나, 보장은 없습니다 params.values()
순으로 값을 반환은 (a, b)
. 이 작업을 수행하는 좋은 방법이 있습니까?
let {a, b} = params
. 가독성을 높이고 당신이 말하고 싶은 모든 Zen과 완전히 일치합니다.
let {a: waffles} = params
. 익숙하더라도 알아내는 데 몇 초가 걸립니다.
답변:
지역 사전 사용과 관련된 문제가 두렵고 원래 전략을 따르는 것을 선호하는 경우 python 2.7 및 3.1 컬렉션의 Ordered Dictionaries. OrderedDicts를 사용하면 처음 삽입 된 순서대로 사전 항목을 복구 할 수 있습니다.
from operator import itemgetter
params = {'a': 1, 'b': 2}
a, b = itemgetter('a', 'b')(params)
정교한 람다 함수 또는 사전 이해 대신 내장 라이브러리를 사용할 수 있습니다.
attrgetter
객체 속성 ( obj.a
)에 대해 작동하는 동일한 표준 라이브러리 모듈에서 사용하도록 답변을 확장 할 수도 있습니다 . 이것은 JavaScript와의 주요 차이점입니다 obj.a === obj["a"]
.
KeyError
예외가 발생합니다
a, b = [d[k] for k in ('a','b')]
대로 더 자연스럽고 가독성이 좋습니다 (형식이 훨씬 더 일반적입니다). 이것은 여전히 흥미로운 대답이지만 가장 간단한 해결책은 아닙니다.
get_id = itemgetter(KEYS)
나중에 사용하는 serial, code, ts = get_id(document)
것이 더 간단합니다. 물론 고차 함수에 익숙해야하지만 파이썬은 일반적으로 그것들에 매우 익숙합니다. 예를 들어, @contextmanager
.
Jochen의 제안보다 덜 반복하여이를 수행하는 한 가지 방법은 도우미 기능을 사용하는 것입니다. 이렇게하면 순서에 관계없이 변수 이름을 나열하고 dict에있는 항목의 하위 집합 만 구조화 할 수있는 유연성이 제공됩니다.
pluck = lambda dict, *args: (dict[arg] for arg in args)
things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')
또한 joaquin의 OrderedDict 대신 키를 정렬하고 값을 가져올 수 있습니다. 유일한 문제는 변수 이름을 알파벳 순서로 지정하고 dict의 모든 것을 구조화해야한다는 것입니다.
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items()))
things = {'foo': 'bar', 'blah': 'bleh'}
blah, foo = sorted_vals(things)
lambda
변수 에을 할당하려는 경우 def
. 와 함께 일반 함수 구문을 사용하는 것이 좋습니다.
itemgetter
했습니다 operator
. :)
파이썬은 딕셔너리가 아닌 시퀀스 만 "해체"할 수 있습니다. 따라서 원하는 것을 작성하려면 필요한 항목을 적절한 시퀀스에 매핑해야합니다. 나 자신이 찾을 수있는 가장 가까운 매치는 (그다지 섹시하지 않음) :
a,b = [d[k] for k in ('a','b')]
이것은 생성기에서도 작동합니다.
a,b = (d[k] for k in ('a','b'))
다음은 전체 예입니다.
>>> d = dict(a=1,b=2,c=3)
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> a, b = [d[k] for k in ('a','b')]
>>> a
1
>>> b
2
>>> a, b = (d[k] for k in ('a','b'))
>>> a
1
>>> b
2
다음 은 JS에서 구조 분해 할당이 작동 하는 방식과 유사하게 수행하는 또 다른 방법입니다 .
params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
우리가 한 일은 params 사전을 키 값으로 압축 해제하는 것이 었습니다 (** 사용) ( Jochen의 대답 과 같이 ), 그런 다음 람다 서명에서 해당 값을 가져와 키 이름에 따라 할당했습니다. 여기에 보너스가 있습니다. 또한 람다 서명에 없는 사전을 가져 오므로 다음과 같은 경우 :
params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
람다가 적용된 후 나머지 변수는 이제 다음을 포함합니다. { 'c': 3}
사전에서 불필요한 키를 생략하는 데 유용합니다.
도움이 되었기를 바랍니다.
경고 1 : 문서에 명시된대로 모든 Python 구현에서 작동한다고 보장되지는 않습니다.
CPython 구현 세부 정보 :이 함수는 인터프리터의 Python 스택 프레임 지원에 의존하며 모든 Python 구현에 존재한다고 보장되지는 않습니다. Python 스택 프레임 지원없이 구현에서 실행하는 경우이 함수는 None을 반환합니다.
경고 2 : 이 함수는 코드를 더 짧게 만들지 만 가능한 한 명시 적이라는 Python 철학과 모순 될 수 있습니다. 또한 John Christopher Jones가 주석에서 지적한 문제를 해결하지 못하지만 키 대신 속성으로 작동하는 유사한 기능을 만들 수 있습니다. 이것은 당신이 정말로 원한다면 그렇게 할 수 있는 데모 일뿐입니다 !
def destructure(dict_):
if not isinstance(dict_, dict):
raise TypeError(f"{dict_} is not a dict")
# the parent frame will contain the information about
# the current line
parent_frame = inspect.currentframe().f_back
# so we extract that line (by default the code context
# only contains the current line)
(line,) = inspect.getframeinfo(parent_frame).code_context
# "hello, key = destructure(my_dict)"
# -> ("hello, key ", "=", " destructure(my_dict)")
lvalues, _equals, _rvalue = line.strip().partition("=")
# -> ["hello", "key"]
keys = [s.strip() for s in lvalues.split(",") if s.strip()]
if missing := [key for key in keys if key not in dict_]:
raise KeyError(*missing)
for key in keys:
yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"}
In [6]: hello, key = destructure(my_dict)
In [7]: hello
Out[7]: 'world'
In [8]: key
Out[8]: 'value'
이 솔루션을 사용하면 JavaScript 에서처럼 전부가 아닌 일부 키를 선택할 수 있습니다. 사용자가 제공 한 사전에도 안전합니다.
글쎄, 수업에서 이것을 원한다면 항상 다음과 같이 할 수 있습니다.
class AttributeDict(dict):
def __init__(self, *args, **kwargs):
super(AttributeDict, self).__init__(*args, **kwargs)
self.__dict__.update(self)
d = AttributeDict(a=1, b=2)
딕셔너리는 Python> = 3.7에서 삽입 순서를 유지하도록 보장 되므로 요즘에는이 작업을 수행하는 것이 완전히 안전하고 관용적이라는 것을 의미합니다.
params = {'a': 1, 'b': 2}
a, b = params.values()
print(a)
print(b)
산출:
1 2
b, a = params.values()
이름이 아닌 순서를 사용하기 때문에 할 수 없다는 것 입니다.
itemgetter
이 작업을 수행하는 가장 비단뱀적인 방법입니다. 이것은 Python 3.6 이하에서는 작동하지 않으며 순서에 의존하기 때문에 처음에는 혼란 스러울 수 있습니다.
스타일이 좋은지는 모르겠지만
locals().update(params)
트릭을 할 것입니다. 그런 다음 a
, b
및 params
해당 지역 변수로 사용할 수있는 dict에 있던 모든 것이 있습니다.