반복하는 동안 Python dict 수정
파이썬 사전이 있다고 치자.d
, 그리고 우리는 이 일을 이렇게 반복하고 있습니다.
for k, v in d.iteritems():
del d[f(k)] # remove some item
d[g(k)] = v # add a new item
(f
그리고.g
단지 몇 가지 블랙박스 변형일 뿐입니다.)
즉, 다음에 항목을 추가/제거하려고 합니다.d
를 반복하면서.iteritems
.
이것은 잘 규정되어 있습니까?답변을 뒷받침할 참고 자료를 제공해 주시겠습니까?
참고 항목 "RuntimeError: 반복 중 사전의 크기 변경" 오류를 방지하는 방법?문제를 피하는 방법에 대한 별개의 질문을 위해.
알렉스 마르텔리가 여기에 무게를 두고 있습니다.
컨테이너를 루프하는 동안 컨테이너를 변경하는 것은 안전하지 않을 수 있습니다(예: dict).del d[f(k)]
안전하지 않을 수도 있습니다.아시다시피, 해결책은 다음과 같은 방법을 사용하는 것입니다.d.copy().items()
(컨테이너의 독립적인 복사본을 루프하기 위해) 대신d.iteritems()
아니면d.items()
(같은 기본 컨테이너를 사용합니다.)
dict의 기존 인덱스에서 값을 수정하는 것은 괜찮지만, 새로운 인덱스에서 값을 삽입하는 것(예:d[g(k)] = v
가 작동하지 않을 수 이 작동하지 않을 수 있습니다.
Python 문서 페이지(Python 2.7의 경우)에 다음과 같이 명시적으로 언급되어 있습니다.
으로.
iteritems()
사전에 항목을 추가하거나 삭제하는 동안에RuntimeError
또는 모든 항목에 대해 반복하지 못합니다.
파이썬 3도 마찬가지.
동일한 의미합니다.iter(d)
,d.iterkeys()
그리고.d.itervalues()
, 그리고 나는 그것이 그들에게 필요한 것이라고 말하는 데까지 갈 것입니다.for k, v in d.items():
(정확하게는 기억이 나지 않습니다.for
하지만 구현이 다음과 같이 해도 놀라지 않을 것입니다.iter(d)
).
당신은 적어도 당신과 함께라면 그럴 수 없습니다.d.iteritems()
합니다. 시도해봤는데 파이썬이 실패합니다.
RuntimeError: dictionary changed size during iteration
대신 사용할 경우d.items()
, 그러면 됩니다.
파이썬 3에서는.d.items()
사전에 대한 보기 같은 것입니다.d.iteritems()
파이썬 2에서.Python 3에서 이 작업을 수행하려면 대신 다음을 사용합니다.d.copy().items()
할 수 이렇게 하면 반복하는 데이터 구조를 수정하지 않기 위해 사전의 복사본을 반복할 수 있습니다.
저는 Numpy 배열이 포함된 큰 사전을 가지고 있어서 @murgatroid99에서 제안한 dict.copy().keys()는 실행할 수 없었습니다.대신 keys_view를 목록으로 변환했는데(Python 3.4에서) 잘 작동했습니다.
for item in list(dict_d.keys()):
temp = dict_d.pop(item)
dict_d['some_key'] = 1 # Some value
나는 이것이 위의 답들처럼 파이썬의 내부 작업들의 철학적 영역으로 파고드는 것이 아니라는 것을 알지만, 그것은 언급된 문제에 대한 실질적인 해결책을 제공합니다.
다음 코드는 이 코드가 잘 정의되지 않았음을 보여줍니다.
def f(x):
return x
def g(x):
return x+1
def h(x):
return x+10
try:
d = {1:"a", 2:"b", 3:"c"}
for k, v in d.iteritems():
del d[f(k)]
d[g(k)] = v+"x"
print d
except Exception as e:
print "Exception:", e
try:
d = {1:"a", 2:"b", 3:"c"}
for k, v in d.iteritems():
del d[f(k)]
d[h(k)] = v+"x"
print d
except Exception as e:
print "Exception:", e
첫 번째 예제는 g(k)를 호출하고 예외(반복 중 사전 변경된 크기)를 던집니다.
두 번째 예제는 h(k)를 호출하고 예외를 두지 않고 출력합니다.
{21: 'axx', 22: 'bxx', 23: 'cxx'}
코드를 보면 잘못된 것 같아요 - 저는 아마 다음과 같은 것을 기대했을 겁니다.
{11: 'ax', 12: 'bx', 13: 'cx'}
Python 3은 다음과 같이 해야 합니다.
prefix = 'item_'
t = {'f1': 'ffw', 'f2': 'fca'}
t2 = dict()
for k,v in t.items():
t2[k] = prefix + v
또는 용도:
t2 = t1.copy()
원본 사전을 수정하면 혼란을 초래할 뿐만 아니라 잠재적인 버그나 RunTimeErrors가 발생할 수 있습니다.새 키 이름으로 사전에 추가하지 않는 한 말입니다.
이 질문은 항목을 삭제하거나 추가하기 위해 반복기를 사용하는 것에 대해 질문하며(그리고 재미있게도, Python 3에서는 Python 2 반복기가 더 이상 지원되지 않음), 승인된 답변에서 찾을 수 있듯이 유일한 정답으로 "아니오"를 가져야 합니다.그러나 대부분의 검색자들은 해결책을 찾으려고 시도하지만 반복 작업이든 재귀 작업이든 기술적으로 어떻게 수행되는지는 신경 쓰지 않을 것이며 문제에 대한 해결책이 있습니다.
추가(재귀) 함수를 사용하지 않고는 명령어를 루프 변경할 수 없습니다.
따라서 이 질문은 효과적인 해결책이 있는 질문과 연결되어야 합니다.
깊게 중첩된 사전에서 선택한 키가 발생하는 경우 키:값 쌍을 제거하려면 어떻게 해야 합니까? (= "삭제")
또한 실행 중에 dict의 항목을 변경하는 방법을 보여주기 때문에 유용합니다.깊게 중첩된 사전에서 선택한 키가 발생할 때마다 키:값 쌍을 해당 값으로 대체하려면 어떻게 해야 합니까? (= "replace")
동일한 재귀적 방법을 사용하여 질문이 요청하는 항목을 추가할 수도 있습니다.
이 질문을 링크해달라는 저의 요청이 거절되었기 때문에, 여기 dict에서 항목을 삭제할 수 있는 솔루션의 복사본이 있습니다.예제/크레딧/노트는 선택한 키가 깊게 중첩된 사전에서 발생하는 경우 키:값 쌍을 제거하려면 어떻게 해야 합니까?(= "삭제")를 참조하십시오.
import copy
def find_remove(this_dict, target_key, bln_overwrite_dict=False):
if not bln_overwrite_dict:
this_dict = copy.deepcopy(this_dict)
for key in this_dict:
# if the current value is a dict, dive into it
if isinstance(this_dict[key], dict):
if target_key in this_dict[key]:
this_dict[key].pop(target_key)
this_dict[key] = find_remove(this_dict[key], target_key)
return this_dict
dict_nested_new = find_remove(nested_dict, "sub_key2a")
요령
하위 레벨에 재귀적으로 도달하기 전에 target_key가 다음 하위 레벨에 속하는지 여부(= this_dict[key] = 현재 diction의 값)를 미리 확인하는 것이 요령입니다.그래야 사전을 반복하는 동안 하위 수준의 key:value pair를 삭제할 수 있습니다.삭제할 키와 동일한 수준에 도달한 후 해당 키를 삭제하려고 하면 다음 오류가 발생합니다.
RuntimeError: dictionary changed size during iteration
재귀적 솔루션은 다음 값의 하위 수준에서만 변경되므로 오류를 방지합니다.
저도 같은 문제가 발생했고 이 문제를 해결하기 위해 다음과 같은 절차를 밟았습니다.
파이썬 리스트는 반복하는 동안 수정하더라도 반복될 수 있으므로 코드를 따르는 경우 1의 것을 무한히 인쇄합니다.
for i in list:
list.append(1)
print 1
따라서 목록과 명령어를 함께 사용하면 이 문제를 해결할 수 있습니다.
d_list=[]
d_dict = {}
for k in d_list:
if d_dict[k] is not -1:
d_dict[f(k)] = -1 # rather than deleting it mark it with -1 or other value to specify that it will be not considered further(deleted)
d_dict[g(k)] = v # add a new item
d_list.append(g(k))
오늘 나는 비슷한 사용 사례를 가지고 있었지만, 단순히 루프 시작 부분에서 사전의 키를 구체화하는 대신, 명령어에 대한 변경이 명령어 명령어 반복에 영향을 미치기를 원했습니다.
jaraco.iter tools에서도 찾을 수 있는 다음 루틴을 만들었습니다.
def _mutable_iter(dict):
"""
Iterate over items in the dict, yielding the first one, but allowing
it to be mutated during the process.
>>> d = dict(a=1)
>>> it = _mutable_iter(d)
>>> next(it)
('a', 1)
>>> d
{}
>>> d.update(b=2)
>>> list(it)
[('b', 2)]
"""
while dict:
prev_key = next(iter(dict))
yield prev_key, dict.pop(prev_key)
문서 문자열은 사용 방법을 나타냅니다.이 함수는 다음을 대신하여 사용될 수 있습니다.d.iteritems()
원하는 효과를 얻을 수 있도록 하기.
언급URL : https://stackoverflow.com/questions/6777485/modifying-a-python-dict-while-iterating-over-it
'programing' 카테고리의 다른 글
SQL 쿼리를 통해 모든 제품, 카테고리 및 메타데이터 우커머스/워드프레스를 얻을 수 있습니다. (0) | 2023.10.20 |
---|---|
GCC의 __thread는 어떻게 구현됩니까? (0) | 2023.10.20 |
jQuery에 전역 값(반드시 전역 변수가 아님)을 저장하는 방법? (0) | 2023.10.20 |
구축 시 Swift 컴파일러 분할 오류 (0) | 2023.10.15 |
IHtpActionResult를 사용할 때 사용자 지정 헤더를 설정하는 방법은? (0) | 2023.10.15 |