ast.NodeTransformer
ast.NodeTransformer
ast.NodeTransformer는 Python의 표준 라이브러리 ast(Abstract Syntax Tree, 추상 구문 트리) 모듈에 포함된 클래스로, 파이썬 코드를 파싱한 후 그 구조를 분석하고 수정하거나 변환하는 데 사용되는 강력한 도구입니다. 이 클래스는 코드 변환(code transformation), 정적 분석, 코드 생성, 코드 난독화, DSL(Domain-Specific Language) 구현 등 다양한 소프트웨어 개발 자동화 작업에 활용됩니다.
개요
파이썬 소스 코드는 문자열 형태로 존재하지만, ast 모듈을 사용하면 이를 구문 트리(Syntax Tree) 형태로 변환할 수 있습니다. 이 트리는 각 코드 요소(예: 변수, 함수, 조건문, 반복문 등)를 노드 객체로 표현하며, ast.NodeTransformer는 이러한 노드를 방문(visit)하고 필요 시 수정 또는 교체할 수 있게 해줍니다.
NodeTransformer는 ast.NodeVisitor를 상속받아 기본적인 노드 탐색 기능을 제공하지만, 수정 기능을 추가로 지원합니다. 즉, 각 노드를 방문할 때 원본 노드를 그대로 반환할 수도 있고, 새로운 노드로 교체하거나 삭제할 수도 있습니다.
주요 기능과 동작 원리
1. 노드 변환의 기본 흐름
ast.NodeTransformer는 다음과 같은 방식으로 동작합니다:
- 파이썬 코드를 문자열로 입력받아
[ast.parse](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%ED%8C%8C%EC%9D%B4%EC%8D%AC%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/ast.parse)()로 구문 트리 생성. - 생성된 트리를 순회하며 각 노드에 대해
visit_XXX메서드 호출. - 사용자가 정의한
visit_XXX메서드에서 노드를 수정하거나 교체. - 수정된 트리를 다시 파이썬 코드로 출력하거나, 다른 처리를 수행.
2. 주요 메서드: [generic_visit](/doc/%EA%B8%B0%EC%88%A0/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EA%B0%9C%EB%B0%9C/%ED%8A%B8%EB%A6%AC%20%EC%88%9C%ED%9A%8C/generic_visit)()와 visit_XXX()
generic_visit(node): 기본적으로 모든 자식 노드를 재귀적으로 방문.visit_FunctionDef(self, node): 함수 정의 노드를 방문할 때 호출.visit_Call(self, node): 함수 호출 노드를 방문할 때 호출.visit_BinOp(self, node): 이항 연산(예:+,*) 노드를 방문할 때 호출.
이러한 메서드를 오버라이드하여 원하는 방식으로 노드를 수정할 수 있습니다. 반환값이 None이면 해당 노드가 삭제되며, 새로운 노드를 반환하면 교체됩니다.
사용 예시
다음은 ast.NodeTransformer를 사용하여 특정 기능을 수행하는 예제입니다.
예제 1: 모든 덧셈을 곱셈으로 바꾸기
import ast
class AddToMultiply(ast.NodeTransformer):
def visit_BinOp(self, node):
if isinstance(node.op, ast.Add):
node.op = ast.Mult() # + 연산자를 *로 변경
return self.generic_visit(node)
# 원본 코드
source_code = "result = 2 + 3 + 4"
tree = ast.parse(source_code)
# 변환 적용
transformer = AddToMultiply()
transformed_tree = transformer.visit(tree)
# 수정된 코드 출력
print(ast.unparse(transformed_tree)) # 출력: result = 2 * 3 * 4
예제 2: 함수 호출 로깅 자동 삽입
class LogFunctionCalls(ast.NodeTransformer):
def visit_Call(self, node):
# 함수 호출 주변에 print 추가
log_call = ast.Expr(
value=ast.Call(
func=ast.Name(id='print', ctx=ast.Load()),
args=[ast.Constant(value=f"Calling function: {node.func.id}")],
keywords=[]
)
)
# 원래 호출과 로그를 순차적으로 실행
return [log_call, node]
# 원본 코드
source = "def greet(): pass\ngreet()"
tree = ast.parse(source)
# 트리 변환
transformer = LogFunctionCalls()
new_body = []
for node in tree.body:
if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call):
new_body.extend(transformer.visit(node))
else:
new_body.append(node)
tree.body = new_body
print(ast.unparse(tree))
출력 예시:
> def greet(): > pass > print('Calling function: greet') > greet() >
주의사항 및 한계
- 문법 오류 주의: 잘못된 노드 구조를 생성하면
[ast.unparse](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%ED%8C%8C%EC%9D%B4%EC%8D%AC%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/ast.unparse)()또는compile()시 오류 발생. - 문맥 유지:
ctx필드(예:Load,Store,Del)를 올바르게 설정해야 함. - 성능: 대규모 코드 기반에 적용 시 성능 저하 가능성 있음.
- 동적 코드 비대응:
eval()이나exec()로 실행되는 동적 코드는 분석 불가.
활용 분야
| 분야 | 설명 |
|---|---|
| 정적 분석 도구 | 코드 스타일 검사, 버그 탐지 (예: pylint, flake8) |
| 코드 난독화 | 변수 이름 변경, 로직 변형 등 보안 강화 |
| DSL 구현 | 도메인 특화 언어를 파이썬 문법 위에 구현 |
| 자동 리팩터링 | IDE의 리팩터링 기능 (예: 변수 이름 일괄 변경) |
| 테스트 자동화 | 함수 호출 로깅, 실행 경로 추적 등 |
참고 자료
ast.NodeTransformer는 파이썬의 동적 특성과 메타프로그래밍 능력을 극대화할 수 있는 핵심 도구입니다. 코드를 데이터처럼 다룰 수 있는 능력은 고급 자동화와 도메인 특화 언어 개발에 있어 매우 중요한 자산이 됩니다.
이 문서는 AI 모델(qwen-3-235b-a22b-instruct-2507)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.