nested dict+list, 재귀호출 관련

조회수 366회

맨 뒤에 질문 먼저 봐 주시면 감사하겠습니다.

from shapely.geometry import Point,LineString, Polygon
from shapely import affinity
from collections.abc import Iterable
from copy import deepcopy

ka={
    'draw': [
        {'deg': 225.0, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 222.2, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 228.0, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 225.2, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 90.0, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 44.0, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 314.9, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])},
        {'deg': 225.1, 'layer': 'C1T1', 'obj': Polygon([[1,1],[2,2],[1,3]])}
    ],
    'txt': [
        {'deg': 90.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 566.0, 'type': 'num'},
        {'deg': 90.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 102.0, 'type': 'num'},
        {'deg': 90.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 668.0, 'type': 'num'},
        {'deg': 0.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 672.0, 'type': 'num'},
        {'deg': 0.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 566.0, 'type': 'num'},
        {'deg': 0.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 1238.0, 'type': 'num'},
        {'deg': 0.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 1140.0, 'type': 'num'},
        {'deg': 0.0, 'layer': 'num', 'obj': LineString([[1,1],[2,2]]), 'txt': 98.0, 'type': 'num'},
        {'deg': 18.5, 'layer': 'size-x', 'obj': LineString([[1,1],[2,2]]), 'txt': 1238.0, 'type': 'size-x'},
        {'deg': 18.5, 'layer': 'size-y', 'obj': LineString([[1,1],[2,2]]), 'txt': 668.0, 'type': 'size-y'},
        {'deg': 0.0, 'layer': 'no', 'obj': LineString([[1,1],[2,2]]), 'txt': '-01', 'type': 'no'}
    ],
    'fence': LineString([[1,1],[2,2],[1,3]]),
    'figure': LineString([[1,1],[2,2],[1,3]]),
    'no': '-01',
    'size-x': 1238.0,
    'size-y': 668.0
}

def zoom_to_real(data):
    r = deepcopy(data)
    for ga, ka in data.items():
        sx, sy = 5,5  # scale x,y 배율

        for gb, kb in ka.items():
            #r[ga][gb]=zoomall(ka,sx,sy)

            if type(kb) in [Point,LineString, Polygon]:
                r[ga][gb] = affinity.scale(kb, xfact=sx, yfact=sy, origin=(0, 0))
            elif type(kb) == list:
                _tmp = []
                for kc in kb:
                    _dict = deepcopy(kc)
                    _dict['obj'] = affinity.scale(kc['obj'], xfact=sx, yfact=sy, origin=(0, 0))
                    _tmp.append(_dict)
                r[ga][gb] = _tmp
    return r

def zoomall(adata,sx,sy):
    if isinstance(adata,dict):
        return {g:zoomall(k,sx,sy) for g,k in adata.items()}
    if isinstance(adata, Iterable):
        return [zoomall(x,sx,sy) for x in adata]
    if isinstance(adata, (Point,LineString,Polygon)):
        _zoomed= affinity.scale(adata, xfact=sx, yfact=sy, origin=(0, 0))
        return _zoomed
    return adata

dict와 list가 중첩된 data dict가 있습니다.
첫번째 key의 value가 글 첫 머리에 있는 ka입니다.

코딩을 하면서 계속 고민인 것은 사용하는 dict는
지금의 구조(dict in dict+list)가 최대?깊이?이고요.
처리하는데에 매번 하드코딩?이라는 느낌이 들어서 이상해요.

중간에 zoom_to_real 함수에 있는 if-elif로 구현은 했지만
affinity.scale이 반복되는 것이 부담스러워서
스택오버플로우에서 발견한 재귀호출 예제를 조금 고쳐서
같은 기능을 하라고 r[ga][gb]=zoomall(ka,sx,sy)를 만들었습니다.

이 zoomall재귀호출 함수가 매우 작은 dict+list(둘 다 중첩된)에서 잘
작동하는데, 이번에는 dict가 깊고 커서 그런지
RecursionError: maximum recursion depth exceeded in comparison 에러가 나옵니다.
찾아보니 재귀호출 제한 횟수를 늘리는 방법이 있던데 위험한거 같아서 안하기로 하고 잊었구요.

질문을 정리하면,

dict가 2~3차원 dict이고. list도 있고 복잡한데, 그 구조를 유지하면서 내부를 돌아서

value가 type이 Point, LineString, Polygon일 경우 affinity.scale를 적용하고 싶습니다.

zoomall을 새로 만들어야 할 거 같은데 무엇을 알아야 하는지

재귀호출이 아닌 다른 것을 써야 하는지

키워드라도 좋으니 한마디 해주시면 정말 감사하겠습니다.

  • (•́ ✖ •̀)
    알 수 없는 사용자
  • return [zoomall(x,sx,sy) for x in adata.items()} 여기 오타죠? nowp 2022.10.20 15:12
  • 네 다시 보니 adata]로 바뀌어야 하네요. 알 수 없는 사용자 2022.10.20 15:13
  • https://stackoverflow.com/questions/51690130/tracking-recursion-depth-with-python-decorators 이런 거 써서 실제 recursive level 이 얼마나 커지는지 한번 로깅해 보시는 건 어떨까요? // 저런 구조체가 복잡복잡해도 maximun recursion exceeded 가 걸리는 건... 좀 이상해 보여요. nowp 2022.10.20 15:20
  • 말씀 덕분에 로깅을 볼 수 있게 적용은 성공 했는데 봐도 모르겠어서 계속 보고있습니다. 알 수 없는 사용자 2022.10.20 15:20
  • Visualize class의 print를 args 출력하게 했더니 "deg": 225.0, "layer": "C1T1"를 처리 못하고 300여회 반복하네요 알 수 없는 사용자 2022.10.20 15:51
  • 'C1T1'도 글자 하나씩 각각 재귀하길래 Iterable을 list로 변경하니 제대로 되네요. daewon님 대단히 감사합니다. 알 수 없는 사용자 2022.10.20 16:00
  • 아... 그렇군요. 스트링이 이터러블이고, 그 각 원소도 다시 스트링이고 이터러블이고... 재미있는 케이스 알아갑니다. nowp 2022.10.20 16:14

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)