숫자만 복사하면 문장이 아니다
삼성전자 2026Q1 영업이익률은 약 42.75%다. 이 숫자만 복사해 “이익률이 좋다”라고 쓰면 글이 비어 보인다. 읽는 사람은 어디서 나온 숫자인지, 어떤 기간인지, 분모가 무엇인지, 그래서 무엇을 조심해야 하는지 알 수 없다.
이번 편은 숫자를 멋진 말로 포장하는 편이 아니다. 표에서 본 숫자를 근거가 보이는 문장으로 바꾸는 편이다. 좋은 문장은 길어서 좋은 문장이 아니라 다시 확인할 수 있어서 좋은 문장이다. “2026Q1 손익계산서 기준, 영업이익 57.233조원을 매출액 133.873조원으로 나누면 영업이익률은 약 42.75%다”처럼 쓰면 독자는 같은 표를 열어 같은 계산을 다시 해 볼 수 있다.
앞 편 재무제표 이익률, 코드 계산에서 매출액과 영업이익으로 영업이익률을 직접 계산했다. 이번 편은 그 다음 단계다. 재무제표를 처음 여는 법은 재무제표, 파이썬 한 줄, 기간 칸을 읽는 법은 재무제표 기간, Y와 Q 조회, 사업 본문과 연결하는 법은 사업의 내용, 표로 읽기에서 이어진다. DART와 EDGAR의 재무제표 경계를 섞지 않는 감각은 EDGAR 재무제표, 코드 실행에서 이어진다.
import dartlab
def valueText(value):
if value is None:
return "값 없음"
return f"{float(value) / 1_000_000_000_000:.3f}조원"
def rowByName(frame, account):
rows = frame[["항목", "2026Q1", "2025Q1"]].to_dicts()
for row in rows:
if row["항목"] == account:
return row
return None
def marginNumber(profit, sales):
if sales in (None, 0) or profit is None:
return None
return float(profit) / float(sales) * 100
def marginText(value):
if value is None:
return "계산 불가"
return f"{value:.2f}%"
def sentenceParts(period, salesRow, profitRow):
sales = salesRow.get(period)
profit = profitRow.get(period)
margin = marginNumber(profit, sales)
return {
"기간": period,
"표": "손익계산서",
"분자": f"영업이익 {valueText(profit)}",
"분모": f"매출액 {valueText(sales)}",
"영업이익률": marginText(margin),
"영업이익률_숫자": margin,
}
c = dartlab.Company("005930")
c.market 결과가 KR이면 DART 회사로 열렸다. 오늘 코드의 목표는 표 전체를 설명하는 것이 아니라 문장 재료를 잃어버리지 않는 것이다. sentenceParts는 기간, 표 이름, 분자, 분모, 계산 결과를 한 묶음으로 만든다. 문장을 쓰기 전에 이 다섯 칸이 먼저 차야 한다.
표 한 줄을 먼저 만든다
문장을 쓰기 전에는 표에서 가져온 재료를 한 줄로 묶는다. 42.75%라는 결과만 따로 두면 나중에 근거가 사라진다.
isPanel = c.panel("IS")
sales = rowByName(isPanel, "매출액")
operatingProfit = rowByName(isPanel, "영업이익")
sentenceInputs = [
sentenceParts("2026Q1", sales, operatingProfit),
sentenceParts("2025Q1", sales, operatingProfit),
]
sentenceInputs 결과에는 2026Q1 표 한 줄과 2025Q1 표 한 줄이 나온다. 2026Q1 줄에는 손익계산서, 영업이익 57.233조원, 매출액 133.873조원, 영업이익률 42.75%가 함께 있다. 2025Q1 줄에는 영업이익 6.685조원, 매출액 79.141조원, 영업이익률 8.45%가 함께 있다.
여기서 중요한 것은 순서다. 숫자를 먼저 외우는 것이 아니라 문장 재료를 먼저 만든다. 기간이 빠지면 전년 동기와 직전 분기가 섞인다. 표 이름이 빠지면 손익계산서인지 현금흐름표인지 흐려진다. 분자가 빠지면 영업이익인지 순이익인지 알 수 없다. 분모가 빠지면 매출액으로 나눈 것인지 자산으로 나눈 것인지 알 수 없다.

문장 재료를 다섯 칸으로 나눈다
초보자가 재무 문장을 쓸 때 가장 많이 빠뜨리는 것은 결과가 아니라 근거다. 그래서 이 편에서는 문장 하나를 다섯 칸으로 나눈다.
첫째, 기간이다. 2026Q1처럼 숫자가 나온 기간을 먼저 쓴다. 둘째, 표 이름이다. 여기서는 손익계산서다. 셋째, 분자다. 영업이익 57.233조원이다. 넷째, 분모다. 매출액 133.873조원이다. 다섯째, 계산 결과다. 영업이익률 42.75%다.
sentenceFields = [
{"칸": "기간", "값": sentenceInputs[0]["기간"], "문장에 필요한 이유": "언제 숫자인지 고정한다"},
{"칸": "표", "값": sentenceInputs[0]["표"], "문장에 필요한 이유": "어느 재무제표에서 왔는지 밝힌다"},
{"칸": "분자", "값": sentenceInputs[0]["분자"], "문장에 필요한 이유": "무엇을 위에 놓고 나눴는지 밝힌다"},
{"칸": "분모", "값": sentenceInputs[0]["분모"], "문장에 필요한 이유": "무엇으로 나눴는지 밝힌다"},
{"칸": "결과", "값": sentenceInputs[0]["영업이익률"], "문장에 필요한 이유": "계산 결과를 적는다"},
]
sentenceFields 이 출력이 문장 설계도다. 복잡한 말이 아니다. 다섯 칸 중 하나라도 빠지면 문장이 약해진다. “삼성전자는 이익률이 높다”에는 기간도 없고, 표도 없고, 분자도 없고, 분모도 없다. 그래서 숫자가 있어도 독자가 따라갈 수 없다.
이 다섯 칸은 문장을 쓰는 순서이기도 하다. 초보자는 보통 결과를 맨 앞에 놓는다. “영업이익률은 42.75%다”라고 시작한다. 그렇게 쓰면 독자가 바로 묻는다. 언제 숫자인가. 어느 표인가. 무엇을 무엇으로 나눴나. 그래서 처음에는 결과를 뒤로 보낸다. “2026Q1 손익계산서 기준”으로 시작하고, “영업이익 57.233조원을 매출액 133.873조원으로 나누면”을 붙인 뒤, 마지막에 “영업이익률은 약 42.75%다”라고 닫는다.
순서를 외우기 어렵다면 이렇게만 기억하면 된다. 언제, 어디서, 무엇을, 무엇으로, 얼마가 나왔다. 이 글의 예시로 바꾸면 언제는 2026Q1, 어디서는 손익계산서, 무엇을은 영업이익, 무엇으로는 매출액, 얼마는 42.75%다. 이 순서로 쓰면 어려운 재무 용어를 많이 쓰지 않아도 문장이 버틴다.
첫 문장은 이렇게 쓴다
이제 표 한 줄을 문장으로 바꾼다. 아래 셀은 방금 만든 다섯 칸을 그대로 이어 붙인다.
def evidenceSentence(part):
return (
f"{part['기간']} {part['표']} 기준, "
f"{part['분자']}을 {part['분모']}으로 나누면 "
f"영업이익률은 약 {part['영업이익률']}다."
)
sentenceDrafts = [
{"기간": row["기간"], "근거문장": evidenceSentence(row)}
for row in sentenceInputs
]
sentenceDrafts 2026Q1 문장은 이렇게 나온다. “2026Q1 손익계산서 기준, 영업이익 57.233조원을 매출액 133.873조원으로 나누면 영업이익률은 약 42.75%다.” 이 문장은 화려하지 않다. 대신 다시 확인할 수 있다.
글을 잘 쓰려고 어려운 말을 붙일 필요는 없다. 초보자에게 더 필요한 것은 “어느 칸을 봤고, 어떤 숫자를 나눴고, 결과가 얼마였는지”다. 이 문장을 먼저 만들고 나서야 설명을 붙일 수 있다. 설명이 먼저 나오고 근거가 뒤에 숨으면 독자는 숫자를 믿어야 할지 말아야 할지 판단하기 어렵다.
문장을 조금 더 짧게 줄여도 된다. 다만 다섯 칸은 남겨야 한다. “2026Q1 손익계산서에서 영업이익 57.233조원을 매출액 133.873조원으로 나눈 영업이익률은 42.75%다”도 괜찮다. 반대로 “삼성전자는 42.75%를 기록했다”는 좋지 않다. 42.75%가 매출총이익률인지 영업이익률인지, 분기인지 연간인지, 연결인지 별도인지 알 수 없기 때문이다.
또 하나, 회사 이름을 앞에 붙이는 것보다 기준을 앞에 붙이는 편이 낫다. “삼성전자는”으로 시작하면 독자는 회사 판단을 기대한다. “2026Q1 손익계산서 기준”으로 시작하면 독자는 숫자 확인을 기대한다. 이 편은 회사 판단이 아니라 숫자 문장 연습이므로 기준을 앞에 둔다.
비교 문장은 기준을 붙인다
한 기간만 쓰면 계산 문장이다. 두 기간을 나란히 쓰면 비교 문장이 된다. 비교 문장은 더 조심해야 한다. 42.75%와 8.45%의 차이는 34.30%p다. 그냥 “34.30% 증가”라고 쓰면 틀릴 수 있다.
def comparisonSentence(now, before):
diff = now["영업이익률_숫자"] - before["영업이익률_숫자"]
sentence = (
f"{before['기간']} 영업이익률 {before['영업이익률']}에서 "
f"{now['기간']} {now['영업이익률']}로 바뀌어 "
f"차이는 {diff:.2f}%p다."
)
return {"비교문장": sentence, "주의": "두 퍼센트 값의 차이는 퍼센트포인트로 쓴다"}
comparison = comparisonSentence(sentenceInputs[0], sentenceInputs[1])
comparison 비교 문장은 “2025Q1 영업이익률 8.45%에서 2026Q1 42.75%로 바뀌어 차이는 34.30%p다”가 된다. 여기에는 기준 기간, 비교 기간, 두 값, 차이의 단위가 모두 들어 있다.
이 문장을 쓰면 독자는 무엇이 좋아졌는지보다 먼저 무엇을 비교했는지 알 수 있다. 비교의 출발점이 빠진 문장은 위험하다. “이익률이 크게 개선됐다”는 말은 맞을 수도 있지만, 읽는 사람은 어느 기간과 비교했는지 모른다. 재무제표 문장에서는 멋있는 표현보다 비교 기준이 먼저다.
비교 문장은 세 가지를 꼭 남긴다. 첫째, 출발점이다. 여기서는 2025Q1 8.45%다. 둘째, 도착점이다. 여기서는 2026Q1 42.75%다. 셋째, 차이의 단위다. 여기서는 34.30%p다. 이 셋이 없으면 “개선됐다”는 말은 공중에 뜬다. 특히 %와 %p는 초보자가 가장 자주 섞는다. 이미 퍼센트인 두 값을 빼면 차이는 퍼센트포인트다.
이 비교 문장 뒤에는 바로 이유를 단정하지 않는다. “HBM 때문이다”, “반도체 업황 때문이다”, “원가가 좋아졌다” 같은 말은 손익계산서 두 줄만으로는 말할 수 없다. 그런 이유 문장은 사업 본문, 주석, 여러 기간 표를 더 본 뒤에 써야 한다. 오늘 문장은 “무슨 변화가 숫자로 보였는가”까지만 맡는다.
나쁜 문장을 바로 고친다
아래 표는 같은 숫자를 놓고 쓴 나쁜 문장과 고친 문장이다. 차이는 꾸밈말이 아니라 근거다.
badAndGood = [
{
"나쁜 문장": "삼성전자는 이익률이 좋다.",
"고친 문장": sentenceDrafts[0]["근거문장"],
"고친 이유": "기간, 표, 분자, 분모, 결과가 보인다",
},
{
"나쁜 문장": "영업이익률이 34.30% 올랐다.",
"고친 문장": comparison["비교문장"],
"고친 이유": "퍼센트 두 값의 차이를 %p로 썼다",
},
]
badAndGood 첫 번째 나쁜 문장은 판단만 있고 근거가 없다. 두 번째 나쁜 문장은 숫자는 있지만 단위가 흔들린다. 고친 문장은 덜 멋있어 보여도 읽는 사람이 다시 계산할 수 있다. 투자 글이든 공부 노트든 이 차이가 크다.
이 편의 목표는 문장을 예쁘게 만드는 것이 아니다. 틀리기 어렵게 만드는 것이다. 초보자는 짧고 강한 문장을 쓰고 싶어진다. 하지만 재무제표 문장은 조금 길어도 근거가 보이는 편이 낫다. 좋은 문장은 주장보다 확인 경로를 먼저 남긴다.
나쁜 문장을 고칠 때는 단어를 멋지게 바꾸지 않는다. 빠진 칸을 채운다. “좋다”가 문제라면 좋다는 말을 더 세게 바꾸는 것이 아니라 2026Q1, 손익계산서, 영업이익, 매출액, 42.75%를 채운다. “올랐다”가 문제라면 크게 올랐다고 바꾸는 것이 아니라 2025Q1 8.45%, 2026Q1 42.75%, 34.30%p를 채운다.
그래서 재무제표 문장을 고치는 순서는 단순하다. 먼저 결과값을 찾는다. 그다음 그 결과값을 만든 분자와 분모를 찾는다. 그다음 기간과 표 이름을 붙인다. 마지막으로 “이 숫자만으로는 무엇을 말할 수 없는가”를 한 문장 붙인다. 이 네 단계만 지켜도 글이 훨씬 덜 위험해진다.
한계를 마지막에 붙인다
근거 문장을 만들었다고 분석이 끝난 것은 아니다. 영업이익률 42.75%는 좋은 출발점이지만, 그 숫자 하나로 투자 판단을 쓰면 안 된다. 왜 좋아졌는지 보려면 사업 본문, 주석, 여러 기간의 흐름, 원가와 가격 변화를 더 봐야 한다.
브라우저에서는 이 글의 코드 셀이 그대로 돈다. 다만 브라우저에서 도는 코드는 공시 숫자를 읽기 쉽게 묶어 보는 연습이다. 회사가 좋은지 나쁜지 자동으로 판정해 주는 장치가 아니다. DART 원문은 DART 전자공시시스템과 DART 회사별 검색에서 확인할 수 있고, API와 원천 파일 흐름은 OpenDART 공시정보 개발가이드에서 확인한다. 미국 공시는 SEC Search Filings와 EDGAR Full Text Search에서 확인한다.
한계 문장은 겁주려고 붙이는 것이 아니다. 읽는 사람이 숫자의 사용 범위를 알게 하려고 붙인다. “이 문장은 2026Q1 손익계산서 두 계정으로 만든 영업이익률 설명이다. 투자 판단에는 사업 본문, 주석, 여러 기간 비교가 더 필요하다.” 이 정도면 충분하다. 초보자 글에서 가장 위험한 순간은 모르는 것을 모른다고 쓰지 않는 순간이다.
여기까지 붙이면 문장은 이렇게 읽힌다. “2026Q1 손익계산서 기준, 영업이익 57.233조원을 매출액 133.873조원으로 나누면 영업이익률은 약 42.75%다. 2025Q1 8.45%와 비교하면 차이는 34.30%p다. 다만 이 숫자만으로 투자 판단을 끝내면 안 되고, 사업 본문과 주석을 더 봐야 한다.” 길지만 길어서 어려운 문장이 아니다. 독자가 따라 확인할 수 있어서 안전한 문장이다.

문장 체크리스트를 코드로 확인한다
마지막으로 2026Q1 근거 문장에 꼭 들어가야 할 말이 실제로 들어 있는지 확인한다. 이 검사는 글쓰기 점수표가 아니라 빠뜨린 근거를 찾는 장치다.
requiredWords = ["2026Q1", "손익계산서", "영업이익", "매출액", "42.75%"]
targetSentence = sentenceDrafts[0]["근거문장"]
sentenceCheck = [
{"확인할 말": word, "문장에 있음": word in targetSentence}
for word in requiredWords
]
sentenceCheck 결과가 모두 True이면 최소한의 근거는 들어갔다. 여기에 “투자 매수”, “확실한 개선”, “구조적 성장” 같은 말을 붙이는 것은 다른 문제다. 그런 판단은 사업 본문과 여러 기간을 더 본 뒤에 해야 한다.
오늘 만든 문장을 다시 보자. “2026Q1 손익계산서 기준, 영업이익 57.233조원을 매출액 133.873조원으로 나누면 영업이익률은 약 42.75%다.” 이 문장은 기간, 표, 분자, 분모, 결과를 모두 가진다. 비교 문장에서는 “2025Q1 8.45%에서 2026Q1 42.75%로 바뀌어 차이는 34.30%p다”처럼 비교 기준과 단위를 붙인다.
다음 편에서 할 것
이번 편은 표 한 줄을 근거 문장으로 바꿨다. 다음 편부터는 “무엇을 물어볼 수 있나”로 넘어간다. 회사 하나의 표를 보는 단계에서, dartlab이 던질 수 있는 질문 목록을 확인하는 단계로 간다. 오늘 기억할 한 줄은 이것이다. 좋은 재무 문장은 숫자를 크게 말하는 문장이 아니라 다시 확인할 수 있게 쓰는 문장이다.