iBetter Books
수정

흔한 함정 _ 중복 정의와 순환 의존성

marimo를 처음 쓸 때, 특히 Jupyter에서 옮겨온 경우에 자주 마주치는 에러가 두 가지입니다. 변수 중복 정의(MB002)와 순환 의존성(MB003)입니다. 어떤 코드가 이 에러를 유발하고, 어떻게 수정하는지 구체적인 예시와 함께 살펴봅니다.

MB002: 변수 중복 정의

에러가 발생하는 코드

# Cell 1threshold = 0.5
# Cell 2threshold = 0.8  # MB002 에러

두 셀이 모두 threshold를 정의합니다. marimo는 이 상황을 허용하지 않습니다.

marimo 에디터는 두 셀을 모두 에러 상태로 표시하며, 규칙 코드 **MB002(multiple-definitions)**와 충돌하는 변수 이름(threshold)을 알려줍니다.

왜 이런 코드가 생기나

Jupyter에서 온 사용자가 가장 자주 저지르는 패턴입니다. 실험 중에 같은 변수에 다른 값을 할당해가며 결과를 비교하는 습관이 있기 때문입니다.

# Jupyter에서 흔한 실험 패턴 — marimo에서는 MB002# 모델 버전 Amodel = train_v1(data)# 모델 버전 B (별도 셀에서)model = train_v2(data)

해결법 1: 변수명 분리

두 값이 독립적으로 필요하다면 이름을 다르게 합니다.

# Cell 1model_v1 = "trained_v1_result"  # 실제 코드에서는 학습 결과# Cell 2model_v2 = "trained_v2_result"

나중에 두 모델을 비교하는 셀에서 model_v1model_v2를 모두 참조할 수 있습니다.

해결법 2: 하나의 셀에서 조건 분기

어느 하나를 선택해 사용해야 한다면 한 셀에서 처리합니다.

# Cell 1 — 버전 선택과 학습을 하나의 셀에서use_v2 = Truemodel_label = "v2" if use_v2 else "v1"

해결법 3: 언더스코어 접두사로 셀-로컬 처리

임시 변수라면 _ 접두사를 붙여 셀-로컬로 만듭니다.

# Cell 1_candidates = [0.3, 0.5, 0.7]threshold = max(_candidates)  # threshold만 공유, _candidates는 로컬
# Cell 2 — 다른 셀에서도 _candidates 이름을 자유롭게 쓸 수 있음_candidates = [0.8, 0.9]threshold_strict = max(_candidates)

두 셀의 _candidates는 서로에게 영향을 주지 않습니다.

MB002를 유발하는 안티패턴 모음

실전에서 자주 보이는 패턴들입니다.

패턴 1: 같은 설정 변수를 여러 셀에서 재선언

# Cell 1batch_size = 32epochs = 10# Cell 2 — 하이퍼파라미터 "업데이트" 시도 MB002 발생batch_size = 64  # 에러

수정: 설정 셀을 하나로 통합합니다.

# Cell 1 (통합)batch_size = 64epochs = 10

패턴 2: 임포트를 여러 셀에서 중복 선언

# Cell 1import numpy as npdata = np.array([1, 2, 3])# Cell 2import numpy as np  # np가 이미 위에서 정의됨 MB002 발생result = np.mean(data)

수정: 임포트는 한 셀에 모아두거나, 각 셀에서 별칭 없이 import numpy로 쓰는 방식은 피하고 임포트 전용 셀을 하나 만듭니다.

# Cell 1 — 임포트 전용import numpy as npimport pandas as pd
# Cell 2 — np는 Cell 1에서 왔음data = np.array([1, 2, 3])result = np.mean(data)

패턴 3: 루프 변수 이름 충돌

Python의 for 루프 변수는 루프가 끝난 뒤에도 남습니다. marimo에서 셀이 i를 루프 변수로 쓰면 그 셀은 i를 정의하는 것이 됩니다. 다른 셀에서도 i를 정의하면 MB002가 발생합니다.

# Cell 1 — i가 전역 변수로 노출됨for i in range(5):    pass# Cell 2 — i를 다시 정의 MB002 발생i = 10

루프 변수가 다른 셀에서 필요하지 않다면 _i처럼 로컬 이름을 씁니다.

# Cell 1 — _i는 셀-로컬, 전역 충돌 없음for _i in range(5):    pass# Cell 2 — i를 독립적으로 정의 가능i = 10

MB003: 순환 의존성

에러가 발생하는 코드

# Cell 1 — b를 읽고 a를 정의a = b + 1
# Cell 2 — a를 읽고 b를 정의b = a + 1

Cell 1은 b에 의존하고, Cell 2는 a에 의존합니다. a를 계산하려면 b가 필요하고, b를 계산하려면 a가 필요합니다. 끝없이 맞물리는 순환입니다. 위상정렬이 불가능한 상태입니다.

marimo 에디터는 순환에 포함된 셀들을 에러 상태로 표시하며, 규칙 코드 **MB003(cycle-dependencies)**와 순환을 이루는 변수 이름(a, b)을 알려줍니다.

왜 이런 코드가 생기나

계산 결과를 서로 참조하는 통계나 수치 해석 코드를 여러 셀에 나눠 작성할 때 자주 발생합니다. 또는 UI 위젯 값과 계산 결과를 서로 동기화하려 할 때도 이 패턴이 나타납니다.

해결법 1: 두 셀을 하나로 병합

가장 직접적인 해결책입니다.

# 두 셀을 하나로 합침a_init = 1b_init = 1# 반복 계산이 필요하면 함수로 처리def compute(a0, b0, steps=5):    a, b = a0, b0    for _ in range(steps):        a_new = b + 1        b_new = a + 1        a, b = a_new, b_new    return a, ba, b = compute(a_init, b_init)a, b

해결법 2: 의존 방향을 한쪽으로 정리

순환이 생기는 원인은 대부분 "두 값이 서로에게 의존한다"는 설계 문제입니다. 어느 값이 입력이고 어느 값이 결과인지를 명확히 하면 순환이 사라집니다.

# Cell 1 — a를 입력으로 정의a = 5
# Cell 2 — a를 받아 b를 계산 (a에만 의존, 순환 없음)b = a + 1
# Cell 3 — a와 b를 모두 받아 최종값 계산result = a * bresult

의존 방향이 Cell 1에서 Cell 2, Cell 3으로 이어지는 단방향입니다. 순환이 없습니다.

에러 확인과 디버깅

marimo 에디터는 MB002와 MB003가 발생한 셀을 시각적으로 표시합니다. 에러가 있는 셀의 상단에 에러 코드와 원인 변수 이름이 표시됩니다.

어떤 변수가 어느 셀에서 정의되는지 추적하기 어려울 때는 변수 이름을 에디터에서 클릭합니다. marimo는 그 변수가 정의된 셀과 참조하는 셀을 하이라이트해 보여줍니다.

안티패턴 요약표

안티패턴 에러 해결
같은 변수를 두 셀에서 정의 MB002 변수명 분리 또는 셀 병합
설정 변수를 여러 셀에서 재선언 MB002 설정 셀 하나로 통합
임포트를 여러 셀에서 중복 MB002 임포트 전용 셀 분리
두 셀이 서로의 변수에 의존 MB003 의존 방향 정리 또는 셀 병합
임시 변수 이름 충돌 우려 MB002 잠재 _ 접두사로 셀-로컬 처리

정리

  • MB002는 같은 변수를 두 개 이상의 셀에서 정의할 때 발생합니다. 변수명 분리, 셀 병합, 언더스코어 접두사가 해결책입니다.
  • MB003는 두 셀이 서로의 변수에 의존하는 순환이 만들어질 때 발생합니다. 의존 방향을 단방향으로 정리하거나 셀을 병합합니다.
  • 두 에러 모두 marimo 에디터가 즉시 감지하고 관련 셀을 표시합니다.
  • Jupyter에서 흔했던 "같은 변수 반복 재정의" 패턴이 이 에러의 주원인입니다. 설계를 명확히 하는 방향으로 코드를 재작성합니다.
Ch 05. 흔한 함정 _ 중복 정의와 순환 의존성 — 실전 marimo | iBetter Books