LangGraph 상태에서 state["messages"]로 꺼내기도 하고 state.messages로 꺼내기도 한다. DeepEval의 metric.score와 크롤링한 JSON의 data["price"]가 같은 자리에서 섞여 나온다. “언제 점이고 언제 대괄호야?”가 헷갈리는 이유 한 번에 정리. 관련: [[파이썬에서 () 소괄호와 [] 대괄호]], isinstance랑 getattr

1. 공통 원리 : 내부에 있는 무언가를 지칭한다

.[] 는 겉보기엔 다르지만 “어떤 컨테이너 안의 하위 요소를 가리킨다” 는 점에서 같은 역할이다. 차이는 “어떤 컨테이너냐”“어떻게 꺼내느냐” 뿐.

문법쓰는 대상꺼내는 키내부 훅 메서드
obj.attr객체(클래스 인스턴스, 모듈, 패키지)코드에 고정된 이름__getattr__, __getattribute__
obj["key"]리스트, 튜플, 딕셔너리, Series, DataFrame 등 subscriptable 객체문자열/숫자/슬라이스(동적)__getitem__

2. 점 . 의 두 얼굴

2-1. 패키지/모듈에서의 점

“커다란 상자 안에서 특정 도구를 꺼낼 때” 사용.

import os.path            # os 상자 안의 path 도구
from deepeval import metrics   # deepeval 안의 metrics

관련 모듈과 객체 참고.

2-2. 객체(Object)에서의 점

객체란 데이터와 기능을 한데 묶어놓은 덩어리. 그 덩어리 안의 상세 정보를 꺼낼 때 점을 씀.

metric = PersonaConsistency()
metric.name       # "PersonaConsistency"
metric.score      # 0.85
metric.measure()  # 메서드 호출 (점 + 소괄호)

비유

학생 객체가 하나 있다고 치면:

person = Student(name="홍길동", age=20)
print(person.name)   # "홍길동"
print(person.age)    # 20

학생이라는 객체는 당연히 가지고 있어야 할 특징(name, age) 이 코드 안에 고정돼 있다. 그래서 점으로 꺼냄.


3. 대괄호 [] : 주소나 라벨로 찾기

“여러 개가 모여 있는 주머니에서 순서나 이름표로 찾을 때” 쓴다. 머신러닝/데이터 다룰 때 많이 보이는 이유는 데이터가 보통 수천, 수만 개 목록(List)이나 표(Dictionary)로 되어 있기 때문.

대상키 종류예시
리스트(List)정수 인덱스apartment[101]
튜플(Tuple)정수 인덱스pair[0], pair[-1]
딕셔너리(Dict)문자열/기타 해시 가능 키locker["내신발"]
문자열(Str)정수 인덱스, 슬라이스s[0:5]
DataFrame컬럼명, 행 조건df["price"], df[df["age"] > 20]

객체에 대괄호 썼을 때 에러

TypeError: 'LLMTestCase' object is not subscriptable

의미: “LLMTestCase 객체는 대괄호([])로 값을 꺼낼 수 없는 형식입니다”

반대로 딕셔너리에 점 쓰면:

>>> d = {"name": "John"}
>>> d.name
AttributeError: 'dict' object has no attribute 'name'

4. 점 vs 대괄호 정면 비교

구분.대괄호 []
주요 용도미리 정해진 특징(속성) 꺼내기목록에서 순서나 이름표로 찾기
키가 코드에 고정O (런타임 변경 불가)X (변수로 넘길 수 있음)
키에 공백/한글 가능X (obj.my name 안 됨)O (d["my name"], d["이름"])
사용 예metric.name, metric.scorecase_list[0], q_info["id"]
느낌”그 녀석의 이름이 뭐야?""그 주머니의 몇 번째 혹은 어떤 이름표를 꺼낼까?“

5. 실제 코드 분석 : 섞여 있는 경우

q_info = case_list[case_index][1]

단계 분해

1단계 → case_list : 여러 테스트 결과가 줄 서 있는 리스트(목록) 2단계 → [case_index] : “그 목록 중 case_index번째 상자 꺼내줘” 3단계 → 꺼내온 게 (test_case, question_info) 형태의 튜플 4단계 → [1] : 파이썬은 0부터 세므로, 두 번째 요소(question_info) 를 꺼내라


6. Agent 코드에서 자주 보이는 혼합 패턴

6-1. LangGraph 상태 접근

# state는 TypedDict 또는 dict
messages = state["messages"]              # 대괄호 (딕셔너리 키)
last_msg = messages[-1]                   # 대괄호 (리스트 인덱스)
content = last_msg.content                # 점 (AIMessage 속성)
tool_name = getattr(last_msg, "name", "") # getattr (안전한 점)

한 줄에 세 가지가 다 나온다. 각 객체 종류가 뭐냐에 따라 문법이 바뀜.

6-2. LLM 응답 파싱

# OpenAI 응답
text = response.choices[0].message.content
#       └── 객체 ─┘ 리스트 └ 객체 ─┘ 객체
 
# API raw JSON(dict)으로 받으면
text = response["choices"][0]["message"]["content"]

같은 구조인데 점이 전부 대괄호로 바뀐 걸 볼 수 있다. Pydantic 객체는 점, dict는 대괄호.

6-3. Pydantic 모델 & dict 왕복

from pydantic import BaseModel
 
class User(BaseModel):
    name: str
    age: int
 
u = User(name="Kim", age=30)
u.name              # 객체 속성 접근 → "Kim"
d = u.model_dump()  # dict로 변환 → {"name": "Kim", "age": 30}
d["name"]           # dict 접근 → "Kim"

같은 데이터지만 형태가 객체냐 dict냐에 따라 접근 문법이 갈림.


7. 안전한 접근 : getattr , .get()

직접 꺼내면 키/속성 없을 때 에러가 뜬다. 방어적으로 접근하려면:

대상직접 접근안전 접근
객체obj.attr → AttributeErrorgetattr(obj, "attr", default)
딕셔너리d["key"] → KeyErrord.get("key", default)
리스트lst[10] → IndexErrorlst[10] if len(lst) > 10 else default

자세한 getattr 설명은 isinstance랑 getattr 참고.


8. 동적 키로 꺼내야 할 때

사용자 입력이나 반복문 변수로 키가 바뀌는 경우.

fields = ["name", "age", "email"]
 
# 딕셔너리는 대괄호로 자연스럽게 동적 키
for f in fields:
    print(user_dict[f])
 
# 객체는 getattr로
for f in fields:
    print(getattr(user_obj, f, None))

반대로 user_obj.f라고 쓰면 글자 그대로 f라는 속성을 찾아 감. 동적 키 접근은 점 문법이 불가능하다.


9. 직접 확인

>>> class Student:
...     def __init__(self, name):
...         self.name = name
>>> s = Student("홍길동")
>>> s.name
'홍길동'
>>> s["name"]
TypeError: 'Student' object is not subscriptable
 
>>> d = {"name": "홍길동"}
>>> d["name"]
'홍길동'
>>> d.name
AttributeError: 'dict' object has no attribute 'name'

10. 왜 이렇게 나뉘어 있는가

  • 은 인터프리터가 컴파일 시점에 어떤 속성일지 알 수 있어 빠름. 키는 코드에 박혀 있음
  • 대괄호런타임에 키를 결정. 변수로 넘길 수 있어 유연하지만 실행해봐야 존재 여부를 알 수 있음
  • 두 체계가 나뉘어 있어야 정적 분석 도구(mypy, pylint) 가 객체 속성의 오타를 잡아낼 수 있음. 딕셔너리는 어차피 동적이라 정적으로 못 잡음

트레이드오프

Pydantic, dataclass처럼 구조를 확정짓는 도구를 쓰면 점 접근의 안전성을 얻고, raw JSON을 다룰 땐 대괄호의 유연성을 취함. Agent 코드에선 외부 경계(API 응답, 파일)는 dict로 받아 Pydantic으로 변환 → 내부 로직은 점 접근 패턴이 관례.


11. 한마디 요약

점은 “객체의 고정된 특징”, 대괄호는 “컨테이너 속 요소를 주소/라벨로 지목”이다. 같은 ‘꺼낸다’이지만 대상 종류가 다르다.