Programming

파이썬 dict.update ()가 객체를 반환하지 않는 이유는 무엇입니까?

procodes 2020. 7. 19. 17:19
반응형

파이썬 dict.update ()가 객체를 반환하지 않는 이유는 무엇입니까?


나는 노력하고있다 :

award_dict = {
    "url" : "http://facebook.com",
    "imageurl" : "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png",
    "count" : 1,
}

def award(name, count, points, desc_string, my_size, parent) :
    if my_size > count :
        a = {
            "name" : name,
            "description" : desc_string % count,
            "points" : points,
            "parent_award" : parent,
        }
        a.update(award_dict)
        return self.add_award(a, siteAlias, alias).award

그러나 기능이 정말 번거 롭다면 오히려했을 것입니다.

        return self.add_award({
            "name" : name,
            "description" : desc_string % count,
            "points" : points,
            "parent_award" : parent,
        }.update(award_dict), siteAlias, alias).award

체인을 연결할 수 있도록 업데이트가 객체를 반환하지 않는 이유는 무엇입니까?

JQuery는이를 수행하여 체인을 수행합니다. 파이썬에서는 왜 허용되지 않습니까?


파이썬은 주로 명령 쿼리 분리 의 실용적인 풍미를 구현합니다 : 뮤 테이터 Nonepop;- 와 같은 실용적으로 예외를 반환 하므로 접근 자와 혼동 될 수 없습니다 (같은 맥락에서 할당은 표현이 아닙니다. -표현 분리 등이 있습니다).

즉 당신이 정말로 원하는 경우 병합 것들까지 많은 방법이 예는,이없는 것은 아닙니다 dict(a, **award_dict)많이 원하는 것으로 보인다 것과 같은 새로운 딕셔너리하게 .update왜 당신이 정말로 느끼는 경우가 중요하다는 것을 사용하지 - 반환 ?

편집 : btw, 특정 경우에 a따라 길을 따라 만들 필요가 없습니다 .

dict(name=name, description=desc % count, points=points, parent_award=parent,
     **award_dict)

정확히 같은 의미로 하나의 딕셔너리를 생성하여 a.update(award_dict)(충돌의 경우, 항목 사실을 포함하여 award_dict명시 적으로 제공하고 그 재정의, 즉, 다른 의미를 얻기 위해이 같은 충돌을 "승리"명시 적 항목을 가지고, 키워드 위치 앞에award_dict 유일한 위치 인수 전달 하고 형식 등의 구부러짐 등).**dict(award_dict, name=name


파이썬의 API는 관례에 따라 프로 시저와 함수를 구분합니다. 함수는 매개 변수에서 새 값을 계산합니다 (대상 객체 포함). 프로 시저는 객체를 수정하고 아무것도 반환하지 않습니다 (즉, None을 반환합니다). 따라서 절차에는 부작용이 있지만 기능에는 없습니다. 업데이트는 절차이므로 값을 반환하지 않습니다.

그렇게하는 동기는 그렇지 않으면 바람직하지 않은 부작용이 생길 수 있다는 것입니다. 치다

bar = foo.reverse()

reverse (제자리에서 목록을 뒤집는)가 목록을 반환 할 경우 사용자는 reverse가 bar에 할당 된 새 목록을 반환한다고 생각할 수 있으며 foo도 수정된다는 사실을 절대 알 수 없습니다. 리버스 리턴 없음을 설정하면 바가 반전의 결과가 아니라는 것을 즉시 인식하고 리버스의 효과가 더 가깝게 보입니다.


>>> dict_merge = lambda a,b: a.update(b) or a
>>> dict_merge({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}

병합 된 dict를 반환 할뿐만 아니라 첫 번째 매개 변수를 그 자리에서 수정합니다. 따라서 dict_merge (a, b)는 a를 수정합니다.

또는 물론 인라인으로 모두 할 수 있습니다.

>>> (lambda a,b: a.update(b) or a)({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}

다음과 같이 쉽습니다.

(lambda d: d.update(dict2) or d)(d1)

댓글에 대한 평판이 충분하지 않습니다.

@ beardc 이것은 CPython이 아닌 것 같습니다. PyPy에서 "TypeError : 키워드는 문자열이어야합니다"

**kwargs병합 할 사전에 string 유형의 키만 있기 때문에 솔루션 만 작동 합니다 .

>>> dict({1:2}, **{3:4})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

vs

>>> dict({1:2}, **{'3':4})
{1: 2, '3': 4}

허용되지 않는 것이 아니라 dicts그 방식으로 구현되지 않았습니다.

Django의 ORM을 보면 체인을 광범위하게 사용합니다. 권장하지 않으며 업데이트를 수행하기 위해 상속 dict하고 재정의 updatereturn self수도 있습니다.

class myDict(dict):
    def update(self, *args):
        dict.update(self, *args)
        return self

as close to your proposed solution as I could get

from collections import ChainMap

return self.add_award(ChainMap(award_dict, {
    "name" : name,
    "description" : desc_string % count,
    "points" : points,
    "parent_award" : parent,
}), siteAlias, alias).award

import itertools
dict_merge = lambda *args: dict(itertools.chain(*[d.iteritems() for d in args]))

Just been trying this myself in Python 3.4 (so wasn't able to use the fancy {**dict_1, **dict_2} syntax).

I wanted to be able to have non-string keys in dictionaries as well as provide an arbitrary amount of dictionaries.

Also, I wanted to make a new dictionary so I opted to not use collections.ChainMap (kinda the reason I didn't want to use dict.update initially.

Here's what I ended up writing:

def merge_dicts(*dicts):
    all_keys  = set(k for d in dicts for k in d.keys())
    chain_map = ChainMap(*reversed(dicts))
    return {k: chain_map[k] for k in all_keys}

merge_maps({'1': 1}, {'2': 2, '3': 3}, {'1': 4, '3': 5})
# {'1': 4, '3': 5, '2': 2}

For those coming late to the party, I had put some timing together (Py 3.7), showing that .update() based methods look a bit (~5%) faster when inputs are preserved and noticeably (~30%) faster when just updating in-place.

As usual, all the benchmarks should be taken with a grain of salt.

def join2(dict1, dict2, inplace=False):
    result = dict1 if inplace else dict1.copy()
    result.update(dict2)
    return result


def join(*items):
    iter_items = iter(items)
    result = next(iter_items).copy()
    for item in iter_items:
        result.update(item)
    return result


def update_or(dict1, dict2):
    return dict1.update(dict2) or dict1


d1 = {i: str(i) for i in range(1000000)}
d2 = {str(i): i for i in range(1000000)}

%timeit join2(d1, d2)
# 258 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit join(d1, d2)
# 262 ms ± 2.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dict(d1, **d2)
# 267 ms ± 2.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit {**d1, **d2}
# 267 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

The timings for the in-place operations are a bit trickier, so it would need to be modified along an extra copy operation (the first timing is just for reference):

%timeit dd = d1.copy()
# 44.9 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit dd = d1.copy(); join2(dd, d2)
# 296 ms ± 2.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); join2(dd, d2, True)
# 234 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); update_or(dd, d2)
# 235 ms ± 1.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

참고URL : https://stackoverflow.com/questions/1452995/why-doesnt-a-python-dict-update-return-the-object

반응형