IsaacLab의 configclass decorator 역할
nvidia
isaaclab
robotics
rl
python
TL;DR
@configclass는 Python @dataclass의 부족한 부분을 채워주는 IsaacLab의 decorator다.
- 타입 annotation 없이도 필드 선언 가능
- mutable default 값을
field(default_factory=...)없이 자동 처리 to_dict,from_dict,copy,replace등 유틸리티 메서드 자동 추가
Introduction
IsaacLab의 IsaacLabExtensionTemplate을 분석하다가 @configclass decorator를 발견했다.

@dataclass를 확장한 것이라는 설명을 보고, 두 decorator를 직접 비교해보기로 했다.
Decorator란?
Note
어떤 함수를 받아 특정 역할을 수행하고, 이를 다시 함수의 형태로 반환하는 함수
Python decorator는 다른 함수를 입력으로 받아, 원래 코드를 수정하지 않고 동작을 확장하거나 변경한다.
기본 구조
def my_decorator(func):
def wrapper(*args, **kwargs):
# 함수 호출 전 처리
result = func(*args, **kwargs)
# 함수 호출 후 처리
return result
return wrapper
@my_decorator
def my_function():
print("Hello, World!")예시 — 로깅 decorator
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(3, 4)
# Calling add
# add returned 7예시 — 실행 시간 측정
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time() - start:.4f}s")
return result
return wrapper
@timing_decorator
def compute_square(n):
return n * n
compute_square(10)
# compute_square took 0.0000s@dataclass 기능
Python 3.7에서 도입된 @dataclass는 __init__, __repr__, __eq__ 등의 메서드를 자동으로 생성해 보일러플레이트 코드를 줄여준다.
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
job: str = "Unknown"
p = Person(name="Alice", age=30)
print(p) # Person(name='Alice', age=30, job='Unknown')
print(p == Person(name="Alice", age=30)) # Trueorder=True, frozen=True 옵션으로 정렬 비교와 불변성도 지원한다.
from dataclasses import dataclass, field
@dataclass(order=True, frozen=True)
class Product:
name: str = field(compare=False)
price: float
quantity: int = field(default=0, compare=False)
p1 = Product(name="Laptop", price=999.99)
p2 = Product(name="Tablet", price=499.99)
print(p1 > p2) # Truedataclass의 한계
- 모든 필드에 타입 annotation이 필수
- mutable 기본값(list, dict 등) 사용 시
field(default_factory=...)를 명시적으로 써야 함
@configclass 분석
IsaacLab 소스코드의 configclass 구현을 보면 다음과 같다.
def configclass(cls, **kwargs):
# 타입 annotation 자동 추가
_add_annotation_types(cls)
# mutable 기본값 자동 처리
_process_mutable_types(cls)
# __post_init__ 확장
if hasattr(cls, "__post_init__"):
setattr(cls, "__post_init__", _combined_function(cls.__post_init__, _custom_post_init))
else:
setattr(cls, "__post_init__", _custom_post_init)
# 유틸리티 메서드 추가
setattr(cls, "to_dict", _class_to_dict)
setattr(cls, "from_dict", _update_class_from_dict)
setattr(cls, "replace", _replace_class_with_kwargs)
setattr(cls, "copy", _copy_class)
# dataclass로 래핑
cls = dataclass(cls, **kwargs)
return cls사용 예시
from dataclasses import MISSING
from omni.isaac.lab.utils.configclass import configclass
@configclass
class ViewerCfg:
eye: list = [7.5, 7.5, 7.5] # annotation 없어도 OK
lookat: list = [0.0, 0.0, 0.0] # mutable default 자동 처리
@configclass
class EnvCfg:
num_envs: int = MISSING
episode_length: int = 2000
viewer: ViewerCfg = ViewerCfg()
env_cfg = EnvCfg(num_envs=24)
print(env_cfg.to_dict())
env_cfg_copy = env_cfg.copy()
env_cfg_copy = env_cfg_copy.replace(num_envs=32)to_dict / from_dict로 dictionary 변환, copy로 깊은 복사, replace로 값을 바꾼 복사본 생성이 가능하다.
dataclass vs configclass 비교
| Feature | @dataclass |
@configclass |
|---|---|---|
| 목적 | 범용 데이터 저장 | 설정 관리 특화 |
| 타입 annotation | 필수 | 자동 처리 |
| Mutable default | field(default_factory=...) 필요 |
자동 처리 |
| 유틸리티 메서드 | __init__, __repr__, __eq__ |
+ to_dict, from_dict, copy, replace |