Python 윤년(Leap Year) 계산 코드 분석

분석 대상 코드

len([y for y in range(2000, 2100) if ((y%4==0)and(y%100!=0))or(y%400==0)])

코드의 목적: 2000년부터 2099년까지의 기간 동안 윤년(Leap Year)이 몇 번 있는지 계산합니다.


[1] 상세 개념 5가지

1. 윤년 (Leap Year)의 규칙

그레고리력에서 윤년은 다음과 같은 규칙으로 정해집니다. 이 규칙은 지구의 공전 주기와 달력의 오차를 보정하기 위해 만들어졌습니다.

코드의 if ((y%4==0)and(y%100!=0))or(y%400==0) 부분이 바로 이 3가지 규칙을 논리적으로 구현한 것입니다.

2. 리스트 컴프리헨션 (List Comprehension)

리스트 컴프리헨션은 기존의 리스트나 다른 반복 가능한(iterable) 객체를 기반으로 새로운 리스트를 간결하게 만들 수 있는 Python의 강력한 기능입니다.
기본적인 구조는 [표현식 for 항목 in 반복가능객체 if 조건문] 입니다. 이 코드는 range(2000, 2100)의 각 숫자(연도 `y`)에 대해 `if` 조건(윤년 규칙)을 검사하여, 조건이 참인 `y` 값들만 모아 새로운 리스트를 생성합니다.

3. range() 함수

range(start, stop) 함수는 start 숫자부터 stop 숫자 바로 앞까지의 정수 시퀀스를 생성합니다. 즉, stop 값은 포함되지 않습니다. 코드의 range(2000, 2100)은 2000, 2001, 2002, ..., 2099까지의 숫자를 생성하여 21세기의 100년 동안의 연도를 나타냅니다.

4. 논리 연산자 (and, or)

논리 연산자는 여러 조건을 조합하여 복잡한 논리를 만들 때 사용됩니다.

코드에서는 '4의 배수이면서(&) 100의 배수는 아닌' 경우, 또는(∣) '400의 배수'인 경우를 표현하기 위해 이 연산자들이 사용되었습니다. 괄호 `()`는 연산의 우선순위를 명확히 합니다.

5. len() 함수

len() 함수는 문자열, 리스트, 튜플 등과 같은 컨테이너(container)나 시퀀스(sequence)의 길이를 반환합니다. 즉, 내부에 포함된 요소의 개수를 알려줍니다. 이 코드에서는 리스트 컴프리헨션을 통해 생성된 '윤년 리스트'를 len() 함수에 전달하여, 리스트에 포함된 요소의 총 개수(즉, 윤년의 총 횟수)를 최종 결과로 얻습니다.


[2] OX 퀴즈 5개

문제 1

range(2000, 2100)은 2100년을 검사 대상에 포함한다.

정답: X
상세 풀이: range(start, stop) 함수는 `stop` 값을 포함하지 않습니다. 따라서 2000년부터 2099년까지만을 대상으로 합니다.

문제 2

코드의 조건문에 따르면 2100년은 윤년이다.

정답: X
상세 풀이: 2100년은 4로 나누어떨어지고, 100으로도 나누어떨어집니다. 하지만 400으로는 나누어떨어지지 않습니다. 따라서 윤년 규칙 2에 의해 평년으로 취급됩니다. (2100%4==0 and 2100%100!=0)는 `False`이고, (2100%400==0)도 `False`이므로 최종 결과는 `False`가 됩니다.

문제 3

이 코드가 생성하는 리스트에는 연도(예: 2000, 2004)가 아닌 불리언 값(True/False)이 저장된다.

정답: X
상세 풀이: 리스트 컴프리헨션 [y for y in ... if ...]에서 리스트에 추가되는 값은 `if` 앞의 표현식인 `y`입니다. `if` 조건은 필터링 역할만 할 뿐, `True`/`False` 값이 리스트에 저장되지 않습니다. 따라서 윤년인 연도들의 리스트가 생성됩니다.

문제 4

코드의 괄호를 모두 제거하여 y%4==0 and y%100!=0 or y%400==0으로 변경해도 결과는 동일하다.

정답: O
상세 풀이: Python에서 논리 연산자는 `and`가 `or`보다 우선순위가 높습니다. 따라서 괄호가 없어도 (y%4==0 and y%100!=0) 부분이 먼저 계산된 후, 그 결과가 or y%400==0과 계산됩니다. 원래 코드의 괄호는 가독성을 높여주지만, 연산 우선순위 규칙에 따라 결과는 동일합니다.

문제 5

이 코드는 21세기에 윤년이 총 24번 있다는 것을 계산한다.

정답: X
상세 풀이: 2000년부터 2099년까지 100년 동안, 4의 배수는 25개(2000, 2004, ..., 2096) 있습니다. 이 중에서 100의 배수이지만 400의 배수는 아닌 연도는 없습니다(2100년은 범위 밖). 100의 배수이면서 400의 배수인 2000년은 윤년입니다. 따라서 윤년은 총 25번입니다. (2000, 2004, ... 2096). 코드의 실행 결과는 25입니다.

[3] 5지선다형 문제 5개

문제 1. 다음 중 코드의 조건문에 의해 윤년으로 판단되는 연도는?

정답: 3번
상세 풀이:

문제 2. 코드에서 range(2000, 2100)range(2099, 2104)로 변경하면 len()의 최종 결과는 무엇인가?

정답: 1번
상세 풀이: range(2099, 2104)는 2099, 2100, 2101, 2102, 2103을 검사합니다. 이 중 윤년은 하나도 없으므로, 빈 리스트 []가 생성되고 len()의 결과는 0이 됩니다.

문제 3. 이 코드에서 리스트 컴프리헨션을 사용했을 때의 주된 이점은 무엇인가?

정답: 3번
상세 풀이: 리스트 컴프리헨션의 가장 큰 장점은 여러 줄의 `for` 루프와 `if`문을 한 줄로 표현하여 코드를 훨씬 간결하고 직관적으로 만들 수 있다는 점입니다. 성능상의 이점도 있을 수 있지만, 가독성과 간결성이 주된 사용 이유입니다.

문제 4. 코드의 가장 바깥쪽 len() 함수를 제거하면 어떤 결과가 출력되는가?

정답: 5번
상세 풀이: len() 함수는 리스트의 길이를 계산하는 역할을 합니다. 만약 이 함수를 제거하면, 리스트 컴프리헨션이 생성한 리스트 그 자체가 최종 결과가 됩니다. 이 리스트에는 2000, 2004, 2008, ..., 2096과 같이 조건에 맞는 윤년들이 모두 포함되어 있습니다.

문제 5. 다음 윤년 규칙에 대한 설명 중 잘못된 것을 고르시오.

정답: 2번
상세 풀이: "100으로 나누어 떨어지는 해는 절대 윤년이 될 수 없다"는 설명은 잘못되었습니다. 100으로 나누어 떨어지더라도, 동시에 400으로 나누어 떨어지면 예외적으로 윤년이 되기 때문입니다. (예: 1600년, 2000년)