포스트

구문과 표현식

코드를 작성하다보면 코드 다발을 구문(statement)라고 표현하기도 하고 표현식(expression)이라고 표현하기도 합니다. 저 역시 영문으로 검색할 때 “Ruby for loop statement”와 “Ruby for loop expression” 이 두 표현을 혼재해서 사용한 적이 있습니다.

하지만 엄밀히 말해 두 단어는 확실히 구분되어야 합니다. 결론부터 말하자면 “Ruby for loop expression”은 틀린 표현입니다.

파이썬 코드를 예로 들어봅시다. 아래 코드는 구문입니다.

1
2
for i in range(5):
  continue

아래 코드는 표현식입니다.

1
len(input())

표현식과 구문의 가장 큰 차이는 “작동 방식”과 “값”에 있습니다. 구문은 어떤 처리가 어떻게 작동되어야 하는지 정의할 수 있고 반환값이 없습니다. 표현식보다 더 문법적이라고 표현할 수 있을겁니다. 어쩌면 사실상 문법을 의미할지도 모릅니다. 실제로 아래 코드는 오류를 반환합니다.

1
2
>>> len(for i in range)
SyntaxError: invalid syntax

당연히 말도 안되는 코드이지만, for문이 표현식이었다면 이 코드는 최소한 컴파일 단계는 통과해야합니다. 즉, 표현식은 말 그대로 결과값이 존재하는 식입니다.
식의 결과값을 도출하는 과정에서 분명 어떤 처리를 할 수는 있겠지만, 결과를 얻어내기 위한 부수적인 단계일 뿐입니다. 1+3 수식이 4True == False 비교식이 False를 한번에 정리해서 나타낼 수 있듯, 표현식은 단일한 반환값으로 처리될 수 있습니다.

다른 값으로 바꿔 생각할 수 있는 표현식

표현식은 코드를 읽는 과정에서 임의의 상황을 가정하여 코드를 다른 값으로 대체할 수 있습니다.

1
print('/'.join(sys.stdin.readline().split()))

위 코드는 일련의 표현식으로, print함수는 따로 지정된 반환값이 없으므로 None을 의미합니다.

1
2
3
4
5
6
7
>>> a = print(1)

>>> b = 0
>>> a + b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

일단 타입이 맞지않아 런타임 오류가 발생하더라도 연산 수행을 시도할 수는 있습니다. 이 코드는 위의 문법 오류는 발생하지 않았습니다.

print를 벗겨내고 다시 문제의 표현식을 살펴보겠습니다.

1
'/'.join(sys.stdin.readline().split())

print가 없어도 여전히 위 식은 표현식이고, “값”의 기능을 잘 수행할 수 있습니다.

그리고 sys.stdin.readline()input()으로 대체해 생각하더라도 *대부분의* 상황에서는 이상이 없을겁니다.

  • sys.stdin.readline() => input()
    => '/'.join(input().split())

또, 다음과 같이 표준 입력을 가정하면 좀 더 대담하게 표현식을 동치할 수 있을겁니다.

예시 입력

1
박종현 정준희 김광재 안주현
  1. input() => 박종현 정준희 김광재 안주현
    => '/'.join('박종현 정준희 김광재 안주현'.split())
  2. '박종현 정준희 김광재 안주현'.split() => ['박종현', '정준희', '김광재', '안주현']
    => '/'.join(['박종현', '정준희', '김광재', '안주현'])
  3. '/'.join(['박종현', '정준희', '김광재', '안주현']) => '박종현/정준희/김광재/안주현'
1
2
3
4
>>> '/'.join(sys.stdin.readline().split())
'박종현/정준희/김광재/안주현'
>>> '박종현/정준희/김광재/안주현'
'박종현/정준희/김광재/안주현'

print()None으로 동치될 수 있다 하더라도, 콘솔에 문자열을 출력하는 역할은 여전히 잘 수행할 수 있을 것이므로 다시 원래대로 print로 감싸겠습니다.

1
2
>>> print('/'.join(sys.stdin.readline().split()))
박종현/정준희/김광재/안주현

초심자에게 표현식에 대한 직관 키워주기

프로그래밍을 처음 손댔을 때를 생각하면 다들 그렇게 수월하게 코드를 짜진 못했을 겁니다. 저 역시 프로그래밍 언어가 기본적으로 가지고 있는 일련의 규칙들을 이해하지 못해 오직 직관과 감각에 의존하는 코드들을 만들어냈었습니다.

아래는 저번 1학기 중에 새내기들을 가르치며 접한 코드입니다.

1
input() = '무엇을 원하시나요?'

대부분 표현식에 대해 약간의 직관이라도 생기면 해결될법한 문제입니다. 그래서 저는 후배들에게 “괄호 단위로 끊어서 동치어로 대체해보라”고 제안했습니다. 그리고 대체로 이 제안은 개선을 이끌어낼 수 있었습니다.

마무리

표현식과 구문이라는 용어가 가지는 의미적 차이에서 시작해서 초심자에게 표현식에 대해 이해시키는 전략으로 마무리되었습니다. 두 사항 모두 아무도 제게 가르쳐주지 않았던 내용이고, 오랜 시간 몸소 부딪혀가며 익힌 것입니다.
하지만 직관과 감각으로만 프로그래밍을 공부하기엔 무엇을 모르는지 말로 설명하지 못하는 것이 많습니다. 이번 글에서는 그것이 표현식과 구문이었습니다.