반응형
Java 개발자를 위한 Python 문법 정리
AI Agent 프로젝트에서 실제로 사용한 문법 중심으로 정리
1. 변수와 타입
# Java: String name = "홍길동";
name = "홍길동" # 타입 선언 없음, 그냥 대입
# Java: int age = 30;
age = 30
# Java: boolean isActive = true;
is_active = True # True/False (대문자 시작)
# Java: String text = null;
text = None # null → None
# 타입 힌트 (선택사항, Java처럼 명시 가능)
# Java: String name = "홍길동";
name: str = "홍길동"
age: int = 30
is_active: bool = True
2. 문자열 (f-string)
# Java: String msg = "안녕 " + name + ", 나이는 " + age + "살";
msg = f"안녕 {name}, 나이는 {age}살" # f-string: {} 안에 변수 바로 사용
# 계산도 가능
msg = f"10 + 20 = {10 + 20}" # "10 + 20 = 30"
# Java: String.format("%.2f", 3.14159)
msg = f"{3.14159:.2f}" # "3.14"
# 여러 줄 문자열 (Java의 """ """)
prompt = """
당신은 AI 어시스턴트입니다.
한국어로 답변하세요.
"""
3. 리스트 (List)
# Java: List<String> items = new ArrayList<>();
items = []
items = ["사과", "바나나", "포도"]
# 추가
items.append("딸기") # Java: items.add("딸기")
# 인덱싱
first = items[0] # "사과"
last = items[-1] # 마지막 요소 "딸기" (Python만의 기능)
# 슬라이싱
part = items[0:2] # ["사과", "바나나"] (0번~2번 미만)
# 길이
length = len(items) # Java: items.size()
# 반복
for item in items: # Java: for (String item : items)
print(item)
# 리스트 컴프리헨션 (Java Stream과 유사)
# Java: items.stream().map(s -> s.toUpperCase()).collect(Collectors.toList())
upper = [item.upper() for item in items]
# 조건 필터링
# Java: items.stream().filter(s -> s.length() > 2).collect(...)
long_items = [item for item in items if len(item) > 2]
4. 딕셔너리 (Map)
# Java: Map<String, Object> map = new HashMap<>();
data = {}
data = {"name": "홍길동", "age": 30}
# 값 조회
name = data["name"] # Java: map.get("name")
name = data.get("name", "기본값") # 없으면 기본값 반환
# 추가/수정
data["email"] = "hong@test.com" # Java: map.put("email", "...")
# 키 존재 확인
if "name" in data: # Java: map.containsKey("name")
print("있음")
# 반복
for key, value in data.items(): # Java: for (Map.Entry<> entry : map.entrySet())
print(f"{key}: {value}")
# 자주 쓰는 패턴: 딕셔너리로 결과 반환 (LangGraph Node에서 많이 씀)
def my_node(state):
return {"messages": [...], "next": "research"} # 딕셔너리 반환
5. 함수 (def)
# Java: public String greet(String name) { return "안녕 " + name; }
def greet(name: str) -> str:
return f"안녕 {name}"
# 기본값 파라미터
# Java: public void connect(String host, int port = 8080) → 지원 안 됨
def connect(host: str, port: int = 8080): # port 기본값 8080
print(f"{host}:{port}")
connect("localhost") # port = 8080 자동 적용
connect("localhost", 9090) # port = 9090
# 키워드 인수 (호출 시 파라미터명 명시)
connect(host="localhost", port=9090)
connect(port=9090, host="localhost") # 순서 바꿔도 됨
# 여러 값 반환 (Java는 객체 반환해야 함)
def get_range():
return 10, 20 # 튜플로 반환
start, end = get_range() # 언패킹
6. 클래스
# Java:
# public class Person {
# private String name;
# private int age;
# public Person(String name, int age) { ... }
# }
class Person:
def __init__(self, name: str, age: int): # 생성자 (__init__)
self.name = name # self = Java의 this
self.age = age
def greet(self) -> str: # 메서드 첫 파라미터는 항상 self
return f"안녕, 나는 {self.name}"
# 사용
p = Person("홍길동", 30) # Java: new Person("홍길동", 30)
print(p.greet())
7. TypedDict (LangGraph State에서 사용)
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
# Java의 DTO/Record와 유사
# public record AgentState(List<Message> messages, String next) {}
class AgentState(TypedDict):
messages: Annotated[list, add_messages] # 메시지 자동 누적
next: str # 다음 노드 이름
result: str # 처리 결과
# TypedDict는 딕셔너리처럼 사용
state: AgentState = {
"messages": [],
"next": "research",
"result": ""
}
# 값 접근
print(state["next"]) # "research"
8. Optional, Annotated (타입 힌트 고급)
from typing import Optional, Annotated
# Optional: null 가능한 값
# Java: @Nullable String name
def greet(name: Optional[str] = None):
if name is None:
return "안녕 손님"
return f"안녕 {name}"
# Optional[str] = str | None 과 동일
name: Optional[str] = None # None 가능
# Annotated: 타입 + 메타데이터 추가
# LangGraph에서 add_messages 동작 방식을 지정할 때 사용
messages: Annotated[list, add_messages]
# = "list 타입인데, 값이 추가될 때 add_messages 함수로 처리해"
9. 데코레이터 (@)
# Java의 어노테이션(@)과 유사하지만 더 강력
# 함수를 감싸서 기능을 추가하는 패턴
# LangChain @tool
from langchain_core.tools import tool
@tool
def get_stock_price(ticker: str) -> str:
"""주식 현재가를 조회합니다."""
return f"{ticker} 주가: $100"
# FastAPI @app.post
from fastapi import FastAPI
app = FastAPI()
@app.post("/chat")
def chat(request):
return {"answer": "안녕"}
# 데코레이터 원리 (참고)
# @tool 은 아래와 동일
# get_stock_price = tool(get_stock_price)
10. import (모듈 시스템)
# Java: import com.example.service.UserService;
from langchain_core.tools import tool # 특정 클래스/함수만
from langchain_core.messages import HumanMessage, AIMessage # 여러 개
import os # 모듈 전체
import json
# 사용
os.getenv("API_KEY") # Java: System.getenv("API_KEY")
json.dumps({"key": "value"}) # JSON 직렬화
# 같은 프로젝트 내 파일 임포트
from tools.search_tools import search_news # tools/search_tools.py 의 search_news
from agents.multi_agent import build_multi_agent
11. 환경변수 (.env)
import os
from dotenv import load_dotenv
load_dotenv() # .env 파일 로드
# Java: System.getenv("GOOGLE_API_KEY")
api_key = os.getenv("GOOGLE_API_KEY")
api_key = os.getenv("GOOGLE_API_KEY", "기본값") # 없으면 기본값
# .env 파일
GOOGLE_API_KEY=AIza...
DB_HOST=localhost
12. HTTP 요청 (requests)
import requests
# GET 요청
# Java: restTemplate.getForObject(url, Map.class)
response = requests.get("http://api.example.com/logs", params={
"date": "2025-05-23",
"type": "swift"
})
data = response.json() # JSON 파싱 (Java: objectMapper.readValue)
status = response.status_code # 200, 404 등
# POST 요청
# Java: restTemplate.postForEntity(url, body, Map.class)
response = requests.post("http://api.example.com/search",
json={"keyword": "error", "date": "2025-05-23"}, # body
headers={"Authorization": f"Bearer {token}"} # 헤더
)
# 에러 처리
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API 오류: {response.status_code}")
13. 예외 처리
# Java:
# try {
# ...
# } catch (Exception e) {
# ...
# } finally {
# ...
# }
try:
result = api_call()
except ValueError as e: # 특정 예외
print(f"값 오류: {e}")
except Exception as e: # 모든 예외
print(f"오류 발생: {e}")
finally:
print("항상 실행")
# 예외 발생
raise ValueError("잘못된 입력입니다") # Java: throw new IllegalArgumentException(...)
14. async / await
import asyncio
# Java의 CompletableFuture와 유사
# 동기 (블로킹)
def sync_call():
result = requests.get(url) # 여기서 대기
return result
# 비동기 (논블로킹)
async def async_call():
result = await some_async_function() # await: 완료될 때까지 대기하되 다른 작업 가능
return result
# FastAPI에서 스트리밍할 때 사용
@app.post("/chat/stream")
async def chat_stream(request):
async def generate():
async for chunk in agent.astream(...): # 비동기 반복
yield chunk
return StreamingResponse(generate())
15. 자주 쓰는 패턴 모음
# ── 딕셔너리 병합 ─────────────────────────────────────────
base = {"a": 1, "b": 2}
extra = {"c": 3}
merged = {**base, **extra} # {"a": 1, "b": 2, "c": 3}
# Java: Map.putAll()
# ── 조건부 표현식 (삼항 연산자) ───────────────────────────
# Java: String result = condition ? "yes" : "no";
result = "yes" if condition else "no"
# ── 리스트에서 조건 확인 ──────────────────────────────────
messages = [HumanMessage("안녕"), AIMessage("반가워")]
# 특정 타입 메시지가 있는지 확인
has_system = any(isinstance(m, SystemMessage) for m in messages)
# Java: messages.stream().anyMatch(m -> m instanceof SystemMessage)
# ── 문자열 포함 확인 ──────────────────────────────────────
text = "오늘 15시 스위프트 로그"
if "스위프트" in text: # Java: text.contains("스위프트")
print("스위프트 관련 질문")
# ── 역방향 반복 ───────────────────────────────────────────
for msg in reversed(messages): # 뒤에서부터 순회
if isinstance(msg, HumanMessage):
last_user_msg = msg.content
break
프로젝트에서 쓴 라이브러리 요약
| 라이브러리 | 역할 | Java 유사 |
|---|---|---|
langchain_core |
LLM/Tool/Message 기본 타입 | Spring Core |
langchain_google_genai |
Gemini LLM 연동 | Spring AI |
langgraph |
Agent 그래프 실행 엔진 | Spring Batch |
fastapi |
REST API 서버 | Spring MVC |
uvicorn |
ASGI 서버 | Tomcat |
pydantic |
데이터 검증/직렬화 | Jackson + Bean Validation |
python-dotenv |
.env 파일 로드 | Spring @Value |
requests |
HTTP 클라이언트 | RestTemplate |
chromadb |
벡터 DB | H2/PostgreSQL |
반응형
'Back-End' 카테고리의 다른 글
| 헷갈려서 남기는 JWT 서명 (0) | 2026.06.14 |
|---|---|
| tmux 완전 정복 — 개발자를 위한 명령어 치트시트 (0) | 2026.06.14 |
| SSHJ란 무엇인가 (0) | 2026.03.19 |
| AES-256-GCM 암호화 방식 정리 (0) | 2026.03.17 |
| 금융기관 API에서 사용하는 Signed JWT + RFC8785 메시지 서명 구조 정리 (0) | 2026.02.25 |