02 클래스의 추가적인 구문 | ✅저자: 이유정(박사)
🔹 어떤 클래스의 인스턴스인지 확인하기
isinstance() 함수는 어떤 객체가 특정 클래스(또는 자료형)의
인스턴스인지 확인할 때 사용합니다.
isinstance(객체, 클래스)
- 반환값은
True
또는False
입니다. - 주로
if
조건문과 함께 사용하여 객체의 타입에 따라 다른 동작을 하도록 처리합니다.
◽ 왜 사용할까요?
- 다양한 자료형을 다루는 상황에서 예외를 예방하고 안정적인 처리를 위해
- 객체지향 프로그래밍(OOP)에서 다형성 처리를 명확히 하기 위해
</> 예시코드: 기본 자료형 검사
class Animal:
pass
class Dog(Animal):
pass
dog = Dog()
print(isinstance(dog, Dog)) # Dog 클래스 인스턴스인지
print(isinstance(dog, Animal)) # 상속받은 Animal 클래스 인스턴스인지
print(isinstance(dog, object)) # 모든 클래스는 object의 자식
x = 10
y = "hello"
# 출력결과
True
True
True
print("-------------------------------------------")
print(isinstance(x, int)) # 정수형인지 확인
print(isinstance(y, str)) # 문자열인지 확인
print(isinstance(y, int)) # 문자열을 정수형으로 착각한 경우
# 출력결과
True
True
False
🔍 코드 해설:
dog
는Dog
클래스의 인스턴스이므로True
Dog
는Animal
을 상속했기 때문에Animal
타입으로도 인정됨 (True
)- 파이썬의 모든 객체는
object
클래스를 기반으로 하므로True
isinstance(x, int)
는x
가 정수형이므로True
반환isinstance(y, str)
도 마찬가지로 문자열이므로True
- 하지만
isinstance(y, int)
는 문자열은 정수가 아니므로False
📝 문제1] 다음 중 isinstance(obj, Class)
함수의 설명으로 가장 올바른 것은?
A. 클래스가 해당 객체를 포함하는지 여부를 검사한다.
B. 객체가 특정 클래스의 인스턴스인지 확인하는 함수이며, True/False를 반환한다.
C. 객체가 클래스 내부에서 선언된 속성인지 확인한다.
D. 객체의 메모리 주소가 클래스와 일치하는지 비교한다.
✅ 정답: B
- A와 C는 클래스의 구조 개념과 혼동
- D는 실제 메모리 주소 비교는 아님
📝 문제2] 다음 코드 실행 결과로 옳은 것은?
class Vehicle:
pass
class Car(Vehicle):
pass
my_car = Car()
print(isinstance(my_car, Vehicle))
A. False – my_car는 Car의 인스턴스이므로 Vehicle과는 무관하다.
B. True – Car는 Vehicle을 상속받았기 때문에 Vehicle의 인스턴스처럼 간주된다.
C. 에러 발생 – isinstance에는 상속 클래스는 사용할 수 없다.
D. False – Vehicle은 Car보다 상위 클래스이므로 비교 불가하다.
✅ 정답: B
- 상속 관계에서도
isinstance()
가 부모 클래스까지 인식한다는 점
📝 문제3] 다음 중 isinstance()
사용법으로 잘못된 것은?
A. isinstance(123, int)
B. isinstance("hello", str)
C. isinstance([1, 2, 3], list)
D. isinstance(int, 123)
✅ 정답: D
isinstance()
는 첫 번째 인자가 객체, 두 번째 인자가 클래스여야 하는데
D는 순서가 바뀜 (int
는 클래스,123
은 객체 → 역순 오류)
</> 예시코드: 학생인지 확인하기
class Student:
def __init__(self, name):
self.name = name
class Teacher:
def __init__(self, subject):
self.subject = subject
# 객체 생성
person1 = Student("은성")
person2 = Teacher("수학")
# isinstance() 사용
print(isinstance(person1, Student)) # True
print(isinstance(person2, Student)) # False
🖨️ 출력 결과:
True
False
🔍 설명:
person1
은Student
클래스로 만든 인스턴스이므로True
person2
는Teacher
클래스로 만든 인스턴스이므로Student
가 아니라서False
</> 이렇게 분기 처리 가능:
if isinstance(person1, Student):
print("학생입니다.")
else:
print("학생이 아닙니다.")
</> 숫자인지 확인하고 합계 구하기:
def safe_add(a, b):
if isinstance(a,(int,float)) and isinstance(b,(int,float)):
return a + b
else:
return "숫자만 더할 수 있습니다."
print(safe_add(10, 5)) # 15
print(safe_add(10, "five")) # 문자열이므로 오류 대신 안내 메시지
🖨️ 출력 결과:
15
숫자만 더할 수 있습니다.
🔍 설명:
isinstance(a, (int, float))
로 숫자 타입만 허용- 문자열이나 다른 타입이 오면 예외 없이 안내 메시지 반환
- 실무에서 예외 방지 및 안정성 확보에 유용
🔹 상속
상속(inheritance)은 기존에 정의된 부모 클래스(기반 클래스)의
속성과 메서드를 새로운 클래스(자식 클래스)가 물려받아 사용하는
객체지향(OOP)의 핵심 개념입니다.
- 자식 클래스는 부모 클래스의 기능을 그대로 사용할 수도 있고,
- 필요한 부분만 오버라이딩(재정의)하여 수정하거나 확장할 수도 있습니다.
◽ 왜 사용할까요?
- 중복 코드 제거 → 유지보수가 쉬움
- 기능 재사용 → 이미 검증된 기능을 다시 사용 가능
- 공통 기능은 부모에, 특화 기능은 자식에 분리 → 설계가 깔끔하고 유연함
- 다형성(polymorphism)을 쉽게 구현할 수 있음
</>예시코드: 기본 상속 (단일 상속)
# 부모 클래스
class Animal:
def speak(self):
print("동물이 소리를 냅니다.")
# 자식 클래스
class Dog(Animal):
def bark(self):
print("멍멍!")
# 사용 예
d = Dog() # 객체생성
d.speak() # 부모 클래스 메서드
d.bark() # 자식 클래스 메서드
🖨️ 출력 결과:
동물이 소리를 냅니다.
멍멍!
🔍 해설:
Dog
는Animal
을 상속받아speak()
를 사용할 수 있음.Dog
만의 기능bark()
도 추가로 정의됨.- 코드 재사용과 기능 확장이 핵심입니다.
</> 예시코드: 오버라이딩 (부모 메서드 재정의)
class Animal:
def speak(self):
print("동물이 소리를 냅니다.")
class Cat(Animal):
def speak(self): # 오버라이딩
print("야옹~")
c = Cat()
c.speak()
🖨️ 출력 결과:
야옹~
🔍 해설:
Cat
클래스는Animal
의speak()
를 재정의(override) 했습니다.- 부모의 기본 기능은 필요 없고, 자식만의 방식으로 다형성 구현 가능.
</>예시코드: 다중상속 (multiple inheritance)
class Flyer:
def fly(self):
print("하늘을 납니다.")
class Swimmer:
def swim(self):
print("물에서 수영합니다.")
# 두 부모를 상속
class Duck(Flyer, Swimmer):
def quack(self):
print("꽥꽥!")
d = Duck()
d.fly() # Flyer의 기능
d.swim() # Swimmer의 기능
d.quack() # Duck의 고유 기능
🖨️ 출력 결과:
하늘을 납니다.
물에서 수영합니다.
꽥꽥!
🔍 해설
Duck
클래스는Flyer
와Swimmer
두 클래스를 모두 상속.- 각 클래스의 메서드를 모두 사용할 수 있습니다.
- 이것이 다중 상속(multiple inheritance)입니다.
◽ 상속은 공통된 기능은 상위 클래스에 두고, 차별화된 기능만 하위 클래스에서 다르게 정의 할 수 있게 해줍니다.
- 모든 사용자는 로그인 기능을 갖는다. (공통 기능)
- 일반 회원은 무료 콘텐츠만 볼 수 있다.
- VIP 회원은 유료 콘텐츠도 볼 수 있다.
- 관리자 회원은 모든 콘텐츠와 관리 기능까지 사용 가능하다.
</>예시코드:
# 상위 클래스 (공통 기능)
class User:
def __init__(self, username):
self.username = username
def login(self):
print(f"{self.username}님 로그인 완료!")
# 하위 클래스 1 - 일반 회원
class RegularUser(User):
def view_content(self):
print("무료 콘텐츠를 열람합니다.")
# 하위 클래스 2 - VIP 회원
class VIPUser(User):
def view_content(self):
print("무료 콘텐츠를 열람합니다.")
print("유료 콘텐츠도 열람합니다.")
# 하위 클래스 3 - 관리자
class AdminUser(User):
def view_content(self):
print("모든 콘텐츠를 열람합니다.")
def manage_site(self):
print("사이트 설정을 관리합니다.")
# 객체생성 + 리스트 저장
users = [
RegularUser("홍길동"),
VIPUser("김영희"),
AdminUser("관리자")
]
for user in users:
user.login() # print(f"{self.username}님 로그인 완료!")
user.view_content() # 무료 콘텐츠를 열람합니다
if isinstance(user, AdminUser):
user.manage_site() # 사이트 설정을 관리합니다.
print("-" * 30)
🖨️ 출력 결과:
홍길동님 로그인 완료!
무료 콘텐츠를 열람합니다.
------------------------------
김영희님 로그인 완료!
무료 콘텐츠를 열람합니다.
유료 콘텐츠도 열람합니다.
------------------------------
관리자님 로그인 완료!
모든 콘텐츠를 열람합니다.
사이트 설정을 관리합니다.
------------------------------
1️⃣ RegularUser("홍길동")
등은 객체 생성 코드입니다.
RegularUser
,VIPUser
,AdminUser
는 각각 클래스 이름입니다."홍길동"
,"김영희"
,"관리자"
는 생성자에 전달되는 인자입니다.RegularUser("홍길동")
을 실행하면 해당 클래스의__init__()
이 호출되고 객체가 생성됩니다.
user1 = RegularUser("홍길동") # 객체 생성
2️⃣ 이 객체들을 리스트에 담아 변수 users
에 저장한 것입니다.
users = [user1, user2, user3]
을 한 줄로 축약해서 쓴 것과 동일한 효과입니다.
📝 문제1] 다음 중 파이썬에서 상속을 선언하는 올바른 문법은?
A. class Child inherits Parent:
B. class Child < Parent:
C. class Parent(Child):
D. class Child(Parent):
✅ 정답: D
- 파이썬에서 상속은
class 자식이름(부모이름):
형태로 선언합니다.
📝 문제2] 다음 코드 실행 결과로 올바른 것은?
class Animal:
def sound(self):
print("동물 소리")
class Dog(Animal):
pass
d = Dog()
d.sound()
A. 오류 발생: Dog 클래스에 sound()가 없음
B. "동물 소리" 출력
C. 아무것도 출력되지 않음
D. Dog 클래스만 호출되므로 출력 없음
✅ 정답: B
Dog
클래스는Animal
을 상속받았기 때문에 부모의sound()
메서드를 사용할 수 있습니다.
📝 문제3] 다음 중 다중 상속에 대한 설명으로 가장 올바른 것은?
A. 파이썬에서는 하나의 클래스만 상속받을 수 있다.
B. 다중 상속 시 부모 클래스의 메서드가 충돌하면 에러가 발생한다.
C. 파이썬에서는 다중 상속이 가능하며, MRO(Method Resolution Order)로 충돌을 해결한다.
D. 다중 상속은 자식 클래스가 자동으로 모든 부모 메서드를 오버라이딩한다.
✅ 정답: C
- 파이썬은 다중 상속을 지원하며, 이름 충돌 시 MRO에 따라 우선순위를 결정합니다.
📝 문제4] 다음 코드에서 자식 클래스에서 부모 메서드를 호출하려면 어떤 코드를 사용해야 할까?
class Parent:
def hello(self):
print("안녕, 부모야!")
class Child(Parent):
def hello(self):
# 부모의 hello도 같이 호출하려면?
print("안녕, 자식이야!")
✅ 정답: A
Parent.hello(self)
또는super().hello()
를 사용하면 부모의 메서드를 명시적으로 호출할 수 있습니다.- 보기 중에는
A
가 문법적으로 맞는 표현입니다.
🔹 상속과 컴포지션
컴포지션은 객체 지향에서 “클래스 안에 다른 객체를 포함해서 사용하는 것”입니다.
상속이라는 개념은 강한 결합(Tight Coupling)을 만들수 있습니다.
- 자식 클래스는 부모 클래스의 구현까지도 상속받기 때문에,
부모의 내부 구조가 바뀌면 자식까지 영향을 받습니다. - 예: 부모가
A → B
로 수정되면 자식도 강제로 따라가야 합니다.
불필요한 오버라이딩이 많아질 수 있습니다.
- 일부 기능만 바꾸고 싶어도 부모 전체를 상속받으니,
super()
+ 오버라이딩 + 복잡한 MRO 구조가 생깁니다.
다중 상속은 충돌 위험이 큽니다.
- Python은 다중 상속을 허용하지만, MRO(Method Resolution Order)가 복잡해지고 메서드 충돌 시 디버깅이 어렵습니다.
그래서 컴포지션(구성)이 대안
으로 떠오릅니다.
"상속보다는 구성(Composition)을 선호하라"
– 객체지향 설계의 대표 원칙 중 하나
◽ 컴포지션의 장점:
느슨한 결합
클래스끼리 직접 연결되지 않고, 객체를 속성으로 주입해 사용함유연성
여러 객체를 조합해서 새로운 기능을 만들 수 있음유지보수성
바꿔야 할 부분만 수정하면 되므로 코드 파급력이 작음테스트 용이성
부분 객체만 교체하거나 mock으로 테스트 가능
❌ </> [상속만 사용한 설계 – 단단하고 위험한 구조]
class Animal:
def make_sound(self):
print("동물 소리")
class Dog(Animal):
def make_sound(self):
print("멍멍")
class RobotDog(Dog): # Dog의 모든 구현을 그대로 상속
pass
RobotDog
는 꼭Dog
일 필요가 없음 → 상속 남용Animal → Dog → RobotDog
까지 변화가 이어지면 유지보수가 어려움
⭕ </> [컴포지션을 사용한 설계 – 조합 가능한 구조]
class SoundBehavior:
def make_sound(self):
print("멍멍")
class RobotDog:
def __init__(self, sound_behavior): # 여기에 다른 객체가 들어옴
self.sound_behavior = sound_behavior
def bark(self):
self.sound_behavior.make_sound()
sound = SoundBehavior() # SoundBehavior 클래스의 객체 생성
robot = RobotDog(sound) # RobotDog에 소리 객체 주입 (컴포지션)
robot.bark() # 로봇개가 짖음 (소리 객체가 실제 동작 수행)
SoundBehavior는 클래스
sound = SoundBehavior() # 객체(인스턴스)를 만든 것
SoundBehavior
는 설계도SoundBehavior()
는 설계도로 객체를 만든 것입니다. (→ 인스턴스)
만든 객체를 다른 클래스의 매개변수로 전달
robot = RobotDog(sound) # SoundBehavior 객체를 RobotDog에게 전달
이제 RobotDog는 다음과 같이 생성됩니다:
def __init__(self, sound_behavior):
self.sound_behavior = sound_behavior
# 전달받은 객체를 속성으로 저장
- 다른 객체(SoundBehavior의 인스턴스)를 속성으로 포함한 것
사람이 연필과 칼을 사용할 수 있는 구조 (도구를 조립해서 쓰는 컴포지션)
</> 예시 코드:
# 도구 클래스 1 - 연필
class Pencil:
def use(self):
print("연필로 글을 씁니다.")
# 도구 클래스 2 - 칼
class Knife:
def use(self):
print("칼로 요리를 합니다.")
# 사람 클래스 - 도구를 포함(=컴포지션)
class Person:
def __init__(self, tool):
self.tool = tool # 다른 클래스의 객체를 속성으로 가짐
def work(self):
print("사람이 작업을 시작합니다.")
self.tool.use() # 도구의 use 메서드 실행
# 객체 생성 및 실행
pencil = Pencil()
knife = Knife()
writer = Person(pencil)
chef = Person(knife)
writer.work() # 연필로 글쓰기
chef.work() # 칼로 요리
1️⃣ __init__(self, tool)
에서 tool
은 무엇인가?
이건 생성자 메서드의 매개변수(Parameter)입니다.
즉, 객체를 만들 때 외부에서 전달받을 값을 담는 변수입니다.
2️⃣ 그럼 인자는 어디에 들어가나요? 객체를 생성할 때 인자를 전달합니다:
pencil = Pencil() # Pencil 객체 생성
writer = Person(pencil) # 여기에서 pencil이 tool로 전달됨!
이제
Person
클래스 안에 self.tool
이라는 속성이 생기고,
그 안에는 외부에서 전달한 도구 객체가 들어있는 것입니다.
전체 코드와 연결해서 다시 보기
class Pencil:
def use(self):
print("연필로 씁니다.")
class Person:
def __init__(self, tool): # tool = pencil
self.tool = tool # self.tool에 pencil 객체 저장
def work(self):
self.tool.use() # pencil.use() 실행됨
pencil = Pencil()
writer = Person(pencil) # 객체 생성 → tool에 pencil 전달됨
writer.work()
🖨️ 출력결과:
연필로 씁니다.
📝 문제1] 다음 중 컴포지션(Composition)을 가장 잘 설명한 것은?
A. 한 클래스가 다른 클래스를 상속받아 기능을 재사용하는 관계
B. 클래스 내부에서 직접 객체를 생성하지 않고 외부 객체를 속성으로 받는 구조
C. 부모 클래스의 기능을 오버라이딩하여 재정의하는 방법
D. 클래스 내에서 super()
함수를 호출하는 방식
✅ 정답: B
📝 문제2] 아래 코드에서 self.tool = tool
의 역할로 가장 적절한 것은?
class Person:
def __init__(self, tool):
self.tool = tool
A. tool이라는 전역 변수를 참조하는 구문이다.
B. Person 클래스에서 직접 Pencil을 생성하는 코드다.
C. 외부에서 받은 객체(tool)를 Person 내부 속성(self.tool)으로 저장하는 코드다.
D. tool이라는 클래스 이름을 self.tool로 바꾸는 구문이다.
✅ 정답: C
📝 문제3] 아래 코드에서 컴포지션이 적용된 부분은?
class Pencil:
def use(self):
print("글을 씁니다.")
class Person:
def __init__(self, tool):
self.tool = tool
def work(self):
self.tool.use()
A. Person 클래스가 Pencil을 상속받고 있다.
B. Person 클래스가 Pencil을 함수로 호출하고 있다.
C. Pencil 객체를 Person 클래스 내부에 직접 생성하고 있다.
D. Pencil 객체를 외부에서 받아와 Person 클래스의 속성으로 저장하고 있다.
✅ 정답: D
📝 문제4] 아래 코드에서 Person(pencil)
이 실행될 때 발생하는 일로 옳은 것은?
pencil = Pencil()
writer = Person(pencil)
A. Pencil 클래스가 Person 클래스를 상속받는다.
B. pencil이라는 클래스가 새로 정의된다.
C. pencil이라는 객체가 Person 클래스의 생성자 매개변수(tool)로 전달된다.
D. Person 클래스 안에서 pencil이 자동으로 삭제된다.
✅ 정답: C
📝 문제5] 컴포지션과 가장 관련 있는 객체 지향 원칙은 무엇인가?
A. "상속보다 구성을 선호하라"
B. "모든 클래스는 단일 책임만 가져야 한다"
C. "인터페이스는 명확히 나누어야 한다"
D. "모든 객체는 반드시 상속받아야 한다"
✅ 정답: A
🔹 프라이빗 변수와 게터/세터
캡슐화(encapsulation)는 클래스 내부 데이터를 외부에서 직접 접근하지
못하게 보호하는 객체지향 프로그래밍(OOP)의 원칙입니다.
- 파이썬에서는 변수 이름 앞에 밑줄 두 개(
__
)를 붙이면 프라이빗(private) 변수로 취급되어 클래스 외부에서 직접 접근이 어렵습니다. - 변수 값을 안전하게 다루기 위해 게터(getter)와 세터(setter) 메서드를 사용합니다.
@property
데코레이터를 이용하면 더 자연스럽고 파이썬다운 방식으로 접근할 수 있습니다.
◽ 왜 사용할까요?
- 중요한 데이터를 외부에서 마음대로 수정하거나 노출되지 않도록 보호
- 값을 설정하거나 가져올 때 검사 및 로직 추가 가능
- 코드의 신뢰성과 안정성 향상
</>예시코드: 프라이빗 변수와 게터/세터 사용하기
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.__balance = balance # 프라이빗 변수
# 게터 (조회용 메서드)
@property
def balance(self):
print("잔액 조회 중...")
return self.__balance
# 세터 (수정용 메서드)
@balance.setter
def balance(self, amount):
if amount < 0:
print("음수는 설정할 수 없습니다.")
else:
print("잔액 수정 중...")
self.__balance = amount
# 객체 생성
acc = BankAccount("홍길동", 1000)
# 잔액 조회 (게터 호출)
print(acc.balance)
# 잔액 수정 (세터 호출)
acc.balance = 5000
# 잔액 재확인
print(acc.balance)
# 잘못된 값 입력
acc.balance = -3000
🖨️ 출력 결과:
잔액 조회 중...
1000
잔액 수정 중...
잔액 조회 중...
5000
음수는 설정할 수 없습니다.
◽ 게터와 세터 (메서드 방식)
class Student:
def __init__(self):
self.__score = 0
def get_score(self):
return self.__score
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
print("점수는 0~100 사이여야 합니다.")
s = Student()
s.set_score(85)
print(s.get_score()) # 출력: 85
◽@property
를 이용한 파이썬 방식의 게터/세터
class Student:
def __init__(self):
self.__score = 0
@property
def score(self):
return self.__score
@score.setter
def score(self, value):
if 0 <= value <= 100:
self.__score = value
else:
print("점수는 0~100 사이여야 합니다.")
s = Student()
s.score = 90 # 세터 호출
print(s.score) # 게터 호출, 출력: 90
◽ 다중 상속과 프라이빗 변수
class Base:
def __init__(self):
self.__secret = "비밀입니다"
def show_secret(self):
print(self.__secret)
class Child(Base):
def access_secret(self):
# print(self.__secret) 오류 발생!
print(self._Base__secret) # 우회 접근
c = Child()
c.show_secret() # "비밀입니다"
c.access_secret() # "비밀입니다"
📝 문제1] 파이썬에서 프라이빗(private) 변수로 처리되기 위해 변수 이름을 어떻게 작성해야 하는가?
A. 변수 이름 앞에 #
을 붙인다.
B. 변수 이름 앞에 _
한 개를 붙인다.
C. 변수 이름 앞에 __
두 개를 붙인다.
D. 변수 이름 끝에 _private
을 붙인다.
✅ 정답: C
__변수명
으로 선언하면 내부적으로 이름이 변경되어 외부 접근이 어렵게 된다. (Name Mangling)
📝 문제2] 다음 코드에서 @property
의 역할로 가장 적절한 설명은?
class Person:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
A. name을 메서드가 아닌 변수처럼 접근할 수 있게 만든다.
B. name 속성을 읽기 전용으로 막아버린다.
C. name이라는 새로운 클래스 변수를 만든다.
D. name이라는 변수에 직접 접근하지 못하게 숨긴다.
✅ 정답: A
📝 문제3] 다음 중 파이썬에서 게터/세터를 @property로 정의할 때 올바른 구조는?
A. get_name()
과 set_name()
으로 함수만 만들면 된다.
B. @property
로 게터를 만들고, @setter
로 같은 이름의 세터를 만든다.
C. @getter
와 @setter
는 클래스 외부에 정의한다.
D. property.get()
과 property.set()
을 사용한다.
✅ 정답: B
파이썬은 Java처럼 get/set 함수를 별도로 만들지 않고, @property
와 @속성명.setter
를 통해 직접 접근 방식으로 게터/세터를 정의한다.
📝 문제4] 다중 상속에서 두 클래스가 모두 __value
라는 프라이빗 변수를 가질 경우 어떤 일이 발생할 수 있는가?
A. 변수명이 같으므로 하나로 병합되어 공유된다.
B. 프라이빗 변수는 충돌하지 않고 클래스별로 별도로 존재한다.
C. 에러가 발생하며 다중 상속이 불가능해진다.
D. 파이썬은 프라이빗 변수를 상속하지 않는다.
✅ 정답: B
__value
는 클래스별로 이름이 mangling되기 때문에 실제로는 _ClassName__value
로 다르게 관리된다 → 충돌 없음
📝 문제5] 다음 중 @property와 관련된 코드에서 잘못된 것은?
class Account:
def __init__(self, balance):
self.__balance = balance
@property
def balance(self):
return self.__balance
@balance.setter
def balance(self, value):
if value >= 0:
self.__balance = value
A. balance 속성은 직접 접근이 아닌 함수로 제어된다.
B. balance 속성은 읽기와 쓰기가 모두 가능하다.
C. balance 속성은 __balance
와 동일하게 외부에서 바로 수정할 수 있다.
D. setter는 @balance.setter로 연결되어 있어야 한다.
✅ 정답: C
외부에서 __balance
에 직접 접근은 불가능하고, balance
속성을 통해 간접적으로 제어한다.
🔹 가비지 컬렉터
가비지 컬렉터(GC)는 더 이상 사용되지 않는 불필요한 객체를 자동으로
메모리에서 제거해주는 시스템입니다.
- 파이썬은 메모리를 자동으로 관리하는 내장 가비지 컬렉션 기능을 제공
- 프로그래머가 C/C++처럼
delete
를 명시적으로 호출하지 않아도 됨 - 주로 참조 카운트(reference count)와 순환 참조 탐지 방식으로 작동
◽ 왜 사용할까요?
- 개발자가 메모리 해제를 일일이 관리하지 않아도 돼서 생산성이 향상됩니다
- 불필요한 객체를 자동으로 제거해 메모리 누수(memory leak)를 예방합니다
- 프로그램 성능과 안정성을 높여줍니다
✨ 활용사례
대용량 데이터 분석
처리 중 임시로 생성된 수많은 객체를 자동으로 정리이미지/영상 처리
메모리를 많이 사용하는 중간 객체들을 자동으로 제거API 서버 운영
서버가 오래 실행되어도 메모리가 자동 정리되어 안정적 운영 가능머신러닝 학습
학습 중 생성되는 중간 텐서나 배열의 자동 소멸을 통해 GPU/메모리 효율화
</>예시코드:
import gc
class Person:
def __init__(self, name):
self.name = name
print(f"{self.name} 객체 생성됨")
def __del__(self):
print(f"{self.name}객체 소멸됨(가비지 컬렉터에 의해 정리됨)")
# 인스턴스 생성
p1 = Person("홍길동")
# 참조 제거
p1 = None
# 가비지 컬렉터 강제 실행
gc.collect()
🖨️ 출력 결과:
홍길동 객체 생성됨
홍길동 객체 소멸됨 (가비지 컬렉터에 의해 정리됨)
⚠️ 출력 순서는 환경에 따라 다를 수 있습니다. __del__
메시지는 gc.collect()
이후 나타날 수 있습니다.
</>예시코드: 두 개의 객체 생성 → 참조 해제 → 가비지 컬렉터 실행
import gc
class Animal:
def __init__(self, name):
self.name = name
print(f"{self.name} 생성됨")
def __del__(self):
print(f"{self.name} 제거됨 (메모리에서 정리됨)")
# 두 개의 객체 생성
a1 = Animal("호랑이")
a2 = Animal("사자")
# 하나는 참조 유지, 하나는 참조 제거
a2 = None # 사자 객체는 더 이상 참조되지 않음
print("가비지 컬렉션 실행 전")
gc.collect() # 가비지 컬렉터 강제 실행
print("가비지 컬렉션 실행 후")
🖨️ 예상 출력:
호랑이 생성됨
사자 생성됨
가비지 컬렉션 실행 전
사자 제거됨 (메모리에서 정리됨)
가비지 컬렉션 실행 후
🔍 해설:
- 가비지 컬렉터는 "더 이상 참조되지 않는 객체"만 제거합니다.
- 위 예제에서는
a2 = None
을 통해 "사자" 객체의 참조를 해제함으로써 가비지 대상이 되었습니다. 호랑이
는 여전히a1
이 참조하고 있기 때문에 메모리에서 제거되지 않습니다.
</>예시코드: 순환 참조로 인해 GC가 즉시 수거하지 못하는 상황
import gc
class Node:
def __init__(self, name):
self.name = name
self.partner = None
def __del__(self):
print(f"{self.name} 객체가 메모리에서 삭제되었습니다.")
def create_cycle():
a = Node("A")
b = Node("B")
a.partner = b # A가 B를 참조
b.partner = a # B도 A를 참조
# 이 시점에서 함수 종료 → a, b는 지역 변수로 사라지지만...
# 서로가 서로를 참조하고 있기 때문에 참조 카운트는 0이 아님
create_cycle()
# 수동으로 가비지 컬렉션 강제 수행
print("gc.collect() 실행")
gc.collect()
print("프로그램 종료")
🖨️ 출력 결과 (예상)
gc.collect() 실행
B 객체가 메모리에서 삭제되었습니다.
A 객체가 메모리에서 삭제되었습니다.
프로그램 종료
※ 하지만 gc.collect()
를 실행하지 않으면 __del__()
이 호출되지 않을 수 있음 → 객체가 메모리에서 회수되지 않은 상태로 남아있음.
🔍 코드 설명
a.partner = b, b.partner = a
서로가 서로를 참조하는 순환 참조 구조
create_cycle()
함수 종료 시 지역 변수 a, b는 소멸하지만, 서로가 참조하므로 참조 카운트는 0이 아님
gc.collect()
순환 참조 같은 복잡한 구조도 강제로 검사해서 메모리 회수
- 파이썬은 참조 카운트 기반으로 객체를 삭제함
- 하지만 서로 참조하는 경우엔 카운트가 0이 되지 않으므로 자동 수거가 어려움
- 이런 상황에서 파이썬의 가비지 컬렉터(GC)는 그래프 탐색을 통해 메모리 누수를 방지함
📝 문제1] 다음 중 가비지 컬렉터(Garbage Collector)의 주된 역할은 무엇인가?
A. 객체의 속성을 자동으로 업데이트한다.
B. 사용자가 정의한 클래스를 등록한다.
C. 더 이상 사용되지 않는 메모리를 자동으로 회수한다.
D. 무한 루프를 방지한다.
✅ 정답: C
📝 문제2] 파이썬의 가비지 컬렉션이 객체를 삭제하는 기준은?
A. 객체의 이름이 길 경우
B. 객체의 메서드가 정의되어 있지 않을 경우
C. 객체를 참조하는 변수가 하나도 없을 경우
D. 객체가 함수 내부에서 생성된 경우
✅ 정답: C
📝 문제3] 다음 중 파이썬에서 가비지 컬렉션이 발생하지 않을 수 있는 상황은?
A. 함수 내에서 생성한 리스트를 반환하지 않을 때
B. 두 객체가 서로를 참조하고 외부에서 접근하지 않을 때
C. 전역 변수로 선언된 객체가 삭제될 때
D. 사용자가 del
키워드로 변수를 삭제했을 때
✅ 정답: B
- 순환 참조(Circular Reference)는 참조 카운트가 0이 아니므로 일반적인 방식으로 수거되지 않음.
- 이를 위해 파이썬의 GC는 참조 그래프 순환 탐지 알고리즘을 사용함.
📝 문제4] 다음 코드 실행 후 obj
는 어떻게 처리되는가?
class Sample:
pass
obj = Sample()
del obj
A. del
은 객체를 완전히 삭제하지 못한다.
B. del
은 객체 이름만 지우고 메모리는 남아 있다.
C. 참조가 0이 되므로 GC가 자동으로 메모리를 회수한다.
D. 객체는 반드시 수동으로 gc.collect()
를 호출해야 제거된다.
✅ 정답: C
📝 문제5] 다음 중 파이썬에서 가비지 컬렉션을 수동으로 실행하는 코드로 올바른 것은?
A. gc.clear()
B. collect.garbage()
C. gc.garbage()
D. gc.collect()
✅ 정답: D
gc.collect()
는import gc
후 사용할 수 있으며, 수동으로 가비지 컬렉션을 강제 수행할 때 사용됩니다.
🔹데코레이터(Decorator)
Django에서는 뷰 함수나 클래스의 동작을 제어하기 위해 사용됩니다.
데코레이터 | 설명 | 적용 대상 |
---|---|---|
@login_required |
로그인된 사용자만 접근 허용 | 함수형 뷰 |
@permission_required('app.permission') |
특정 권한을 가진 사용자만 접근 허용 | 함수형 뷰 |
@user_passes_test(func) |
조건을 만족하는 사용자만 접근 허용 | 함수형 뷰 |
@staff_member_required |
is_staff=True 인 사용자만 접근 가능 |
함수형 뷰 |
@csrf_exempt |
CSRF 보호 기능 제외 | 함수형 뷰 (주의 요망) |
@require_http_methods(["GET", "POST"]) |
HTTP 메서드 제한 (보안 강화) | 함수형 뷰 |
@require_GET , @require_POST |
GET 또는 POST만 허용 | 함수형 뷰 |
@cache_page(60 * 15) |
페이지 전체를 15분간 캐시 | 함수형 뷰 |
◽ 로그인 필수: @login_required
로그인하지 않은 사용자는 접근할 수 없도록 제한하는 데코레이터입니다.
미로그인 시 자동으로 로그인 페이지로 리디렉션됩니다.
</> 예시코드:
# views.py
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
@login_required
def my_page(request):
return HttpResponse("로그인한 사용자만 볼 수 있는 페이지입니다.")
✨ 적용범위:
views.py
에서 함수형 뷰에 적용- 주로 마이페이지, 게시글 작성, 설정 페이지 등 인증이 필요한 곳에 사용
📝 문제1] @login_required
데코레이터의 주된 목적은 무엇인가?
A. 사용자의 아이디와 비밀번호를 자동으로 저장한다.
B. 로그인하지 않은 사용자의 요청도 모두 허용한다.
C. 로그인한 사용자만 특정 뷰에 접근할 수 있도록 제한한다.
D. 관리자만 접근 가능한 뷰를 정의한다.
✅ 정답: C
@login_required
는 사용자가 로그인하지 않은 상태에서 해당 뷰에 접근하면 로그인 페이지로 리다이렉트시킵니다.
📝 문제2] @login_required
를 함수형 뷰에 사용할 때 올바른 위치는?
A. 함수 내부에 if문으로 감싼다.
B. settings.py에 등록한다.
C. 해당 뷰 함수의 바로 위에 작성한다.
D. urls.py에 경로 등록할 때 함께 작성한다.
✅ 정답: C 데코레이터는 함수나 클래스 "정의 바로 위"에 작성해야 적용됩니다.
📝 문제3] 다음 중 @login_required
사용을 위해 반드시 필요한 설정은?
A. INSTALLED_APPS
에 'django.contrib.auth'
를 추가해야 한다.
B. LOGIN_URL
을 설정하지 않으면 오류가 발생한다.
C. settings.py에 ALLOWED_HOSTS
를 비워둬야 한다.
D. @login_required
는 인증 없이도 작동하므로 별도 설정이 필요 없다.
✅ 정답: B
@login_required
는 로그인하지 않은 사용자를 LOGIN_URL
로 리다이렉트하기 때문에 settings.py
에 LOGIN_URL
설정이 없으면 오류가 날 수 있습니다.
◽ 권한 검사: @permission_required('app.permission')
지정된 권한을 가진 사용자만 접근을 허용하는 데코레이터입니다.
권한이 없으면 403 Forbidden 오류 반환 또는 로그인 유도 가능.
</> 예시코드:
# views.py
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse
@permission_required('polls.change_question')
def edit_question(request):
return HttpResponse("질문 수정 페이지입니다.")
✨ 적용범위:
views.py
의 함수형 뷰- 권한이 필요한 기능(예: 수정/삭제)에 제한을 둘 때 사용
📝 문제1] @permission_required('app.permission')
데코레이터의 기본 동작은 무엇인가?
A. 사용자의 로그인 여부만 확인한다.
B. 사용자가 슈퍼유저인지 확인한다.
C. 특정 앱의 특정 권한을 가진 사용자만 해당 뷰에 접근할 수 있게 한다.
D. 로그인하지 않은 사용자에게 무조건 접근 권한을 부여한다.
✅ 정답: C
@permission_required('앱이름.권한코드')
는 지정된 권한을 가진 사용자만 뷰에 접근할 수 있게 합니다.
권한이 없으면 기본적으로 403 Forbidden 오류가 반환됩니다.
📝 문제2] 다음 중 @permission_required()
데코레이터의 권한 체크 실패 시 기본 반응으로 올바른 것은?
A. 아무런 오류 없이 페이지가 로딩된다.
B. 404 Not Found 오류를 반환한다.
C. 403 Forbidden 오류를 반환하거나 로그인 페이지로 리다이렉트할 수 있다.
D. 해당 권한을 자동으로 부여하고 실행된다.
✅ 정답: C
기본적으로는 403 오류가 발생하지만, login_url
과 raise_exception
옵션을 설정하여 리다이렉트 또는 예외 처리 방식을 조정할 수 있습니다.
📝 문제3] 아래 코드에서 @permission_required
가 제대로 작동하기 위해 필요한 전제 조건은?
@permission_required('blog.change_post')
def edit_post(request):
...
A. 사용자가 인증되어 있고, blog.change_post
권한을 가져야 한다.
B. settings.py에 DEBUG=False여야 한다.
C. edit_post
함수 내부에 login_required를 함께 작성해야 한다.
D. 권한이 없어도 뷰는 실행되지만 경고 메시지를 띄운다.
✅ 정답: A
@permission_required
는 해당 권한을 갖고 있고 로그인한 사용자만 허용합니다.
권한이 없으면 접근이 막히며, 보통 403 오류나 로그인 리다이렉트가 발생합니다.
◽ 조건 검사: @user_passes_test(func)
사용자가 특정 조건을 만족하는지 검사하는 데코레이터입니다.
조건은 사용자 객체를 인자로 받는 함수로 정의됩니다.
</> 예시코드:
# views.py
from django.contrib.auth.decorators import user_passes_test
from django.http import HttpResponse
def is_superuser(user):
return user.is_superuser
@user_passes_test(is_superuser)
def super_admin_page(request):
return HttpResponse("슈퍼관리자만 접근 가능합니다.")
✨ 적용범위:
- 사용자 그룹별 접근 제한, 나이 제한 등 다양한 조건 검사
views.py
의 함수형 뷰에서 사용
📝 문제1] @user_passes_test(func)
의 주된 목적은 무엇인가?
A. 사용자의 패스워드를 검사하여 인증 여부를 판단한다.
B. 사용자가 슈퍼유저인지 확인하고 자동 로그아웃시킨다.
C. 특정 조건을 만족하는 사용자만 뷰에 접근할 수 있게 제한한다.
D. 모든 사용자가 동일한 테스트를 통과하도록 강제한다.
✅ 정답: C
@user_passes_test
는 사용자 객체를 인자로 받아 True/False를 반환하는 함수를 통해 해당 조건을 만족하는 사용자만 접근하도록 제한합니다.
📝 문제2] 다음 중 @user_passes_test()
사용 예로 올바른 것은?
A.
@user_passes_test(lambda u: u.is_superuser)
def dashboard(request):
...
B.
@user_passes_test(request.user.is_authenticated)
def dashboard(request):
...
C.
@user_passes_test("user.is_staff")
def dashboard(request):
...
D.
@user_passes_test(42)
def dashboard(request):
...
✅ 정답: A
람다(lambda) 함수나 일반 함수를 사용해서 user
객체를 받아 검사하는 방식이 올바른 사용 예입니다.
B는 즉시 실행이라서 안 되고, C와 D는 함수가 아니므로 오류 발생.
📝 문제3] @user_passes_test()
에서 조건에 통과하지 못한 사용자가 접근했을 때 기본 동작은?
A. 아무 일도 일어나지 않고 통과시킨다.
B. 사용자를 자동으로 삭제한다.
C. 로그인 페이지로 리다이렉트된다.
D. HTTP 500 서버 오류가 발생한다.
✅ 정답: C
기본적으로 조건을 만족하지 못한 사용자는 settings.LOGIN_URL
로 리다이렉트됩니다.
필요하다면 login_url
또는 redirect_field_name
등의 옵션으로 동작을 조정할 수 있습니다.
◽ 스태프만 접근: @staff_member_required
is_staff=True 속성을 가진 스태프 계정만 접근할 수 있도록
제한합니다.
</> 예시코드:
# views.py
from django.contrib.admin.views.decorators import staff_member_required
from django.http import HttpResponse
@staff_member_required
def admin_dashboard(request):
return HttpResponse("스태프 전용 관리자 페이지입니다.")
✨ 적용범위:
- 관리자 페이지, 내부 운영 기능 등 스태프만 접근 가능한 뷰에서 사용
📝 문제1] @staff_member_required
데코레이터의 주된 목적은 무엇인가?
A. 로그인한 모든 사용자에게 접근 권한을 부여한다.
B. 관리자 페이지가 아닌 모든 페이지에 접근을 제한한다.
C. is_staff=True
속성을 가진 사용자만 뷰에 접근할 수 있도록 제한한다.
D. 사용자에게 자동으로 is_staff 권한을 부여한다.
✅ 정답: C
@staff_member_required
는 관리자 사이트 접근 권한이 있는 사용자(즉, is_staff=True
)에게만 뷰 접근을 허용합니다.
📝 문제2] 다음 중 @staff_member_required
가 적용된 뷰 함수에 대해 올바른 설명은?
A. 로그인하지 않은 사용자도 접근할 수 있다.
B. is_staff=False
인 사용자는 403 Forbidden 오류를 받는다.
C. is_staff=False
인 사용자는 로그인 페이지로 리다이렉트된다.
D. is_superuser=True
이면 staff 권한 없이도 접근 가능하다.
✅ 정답: C
로그인하지 않았거나 is_staff=False
인 경우에는 기본적으로 LOGIN_URL
로 리다이렉트됩니다.
403 오류가 아니라 로그인 유도가 기본 동작입니다.
📝 문제3] 다음 중 @staff_member_required
를 사용하기 위해 필수로 필요한 설정은?
A. is_superuser
속성을 True로 설정해야 한다.
B. settings.py
에 반드시 DEBUG = False
여야 한다.
C. 접근할 사용자 객체의 is_staff
속성이 True여야 한다.
D. 관리자 페이지를 사용할 수 없도록 설정해야 한다.
✅ 정답: C
@staff_member_required
는 Django에서 is_staff=True인 계정만 통과할 수 있게 제한합니다.
이는 보통 Django 관리자(admin) 사이트 접근 권한과도 연결됩니다.
◽ CSRF 보호 예외: @csrf_exempt
CSRF 보호를 비활성화합니다. 외부 API 호출 등 일부 특별한
상황에서 사용되며, 보안상 주의가 필요합니다.
</> 예시코드:
# views.py
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
@csrf_exempt
def webhook(request):
return HttpResponse("외부 서비스에서 호출된 Webhook입니다.")
✨ 적용범위:
- 외부 서비스(Postman, Webhook 등)와 통신할 때 CSRF 검사를 건너뛰기 위해 사용
views.py
의 함수형 뷰에서만 사용 (주의 요망)
📝 문제1] @csrf_exempt
데코레이터의 주된 역할은 무엇인가?
A. 모든 뷰를 관리자 전용으로 만든다.
B. 로그인하지 않은 사용자의 접근을 차단한다.
C. CSRF 토큰 검사를 생략하여 요청을 허용한다.
D. 데이터베이스 접근을 제한한다.
✅ 정답: C
@csrf_exempt
는 Django의 CSRF 보호(요청 위조 방지) 기능을 비활성화시킵니다. 외부에서 들어오는 POST 요청 등에 대해 CSRF 토큰 없이도 처리할 수 있도록 허용합니다.
📝 문제2] 다음 중 @csrf_exempt
를 사용하는 데에 적절한 상황은?
A. Django 템플릿을 사용하는 내부 폼 처리
B. 외부 시스템이 Django API에 POST 요청을 보내는 경우
C. 관리자 페이지 접근 권한 제어
D. CSRF 공격을 방지하고 싶을 때
✅ 정답: B
외부 시스템(API 클라이언트, 타 서버 등)은 Django의 CSRF 토큰을 생성할 수 없기 때문에,
외부 POST 요청을 받을 때 @csrf_exempt
를 적용하는 경우가 있습니다.
단, 보안상 주의 필요!
📝 문제3] @csrf_exempt
를 사용한 뷰의 보안상 가장 큰 위험은?
A. 뷰가 너무 느리게 실행된다.
B. 클라이언트의 브라우저 쿠키가 삭제된다.
C. CSRF 공격(사이트 간 요청 위조)에 취약해진다.
D. GET 요청이 모두 막혀버린다.
✅ 정답: C
CSRF 보호를 비활성화하면 악의적인 사이트가 사용자의 인증 정보를 도용해 요청을 보낼 수 있어 CSRF 공격에 취약해집니다.
따라서 반드시 필요한 경우에만 사용해야 합니다.
◽ 메서드 제한: @require_http_methods(["GET", "POST"])
요청 메서드가 GET 또는 POST 등 특정 메서드일 때만 요청을
허용합니다.
그 외의 메서드로 접근 시 405 Method Not Allowed 반환.
</> 예시코드:
# views.py
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse
@require_http_methods(["GET", "POST"])
def submit_form(request):
return HttpResponse("GET 또는 POST 요청만 허용됩니다.")
✨ 적용범위:
views.py
에서 보안을 강화하고, 잘못된 HTTP 요청을 방지할 때 사용
📝 문제1] @require_http_methods(["GET", "POST"])
의 주된 목적은 무엇인가?
A. 요청한 사용자가 로그인했는지 확인한다.
B. 요청 메서드가 GET 또는 POST일 때만 뷰 함수가 실행되도록 제한한다.
C. URL 경로를 자동으로 생성한다.
D. GET 요청을 POST로 자동 변환한다.
✅ 정답: B 이 데코레이터는 요청의 HTTP 메서드가 명시된 메서드(GET, POST 등)일 때만 뷰 함수 실행을 허용하며, 나머지 메서드는 405 오류를 반환합니다.
📝 문제2] 다음 중 @require_http_methods(["POST"])
가 적용된 뷰에 GET
요청을 보내면 어떤 응답이 돌아오는가?
A. 200 OK
B. 302 Redirect
C. 403 Forbidden
D. 405 Method Not Allowed
✅ 정답: D
허용되지 않은 HTTP 메서드로 요청하면 Django는 405 Method Not Allowed
응답을 자동으로 반환합니다.
📝 문제3] @require_http_methods
데코레이터를 사용하는 가장 실용적인 이유는?
A. 데이터베이스 쿼리 속도를 향상시키기 위해
B. 함수 내부의 코드를 더 짧게 만들기 위해
C. 허용되지 않은 HTTP 요청을 사전에 차단하여 보안을 강화하고 명확한 API 동작을 정의하기 위해
D. 사용자 입력을 자동으로 필터링하기 위해
✅ 정답: C HTTP 메서드를 명확히 제한하면 잘못된 요청을 방지하고 API 명세를 명확하게 유지할 수 있습니다. 또한 불필요한 보안 위협도 줄일 수 있습니다.
◽ GET/POST 전용: @require_GET
, @require_POST
GET 또는 POST 요청만 허용하도록 제한합니다.
보다 명확하고 간단한 문법으로 메서드를 제한할 수 있습니다.
</> 예시코드:
# views.py
from django.views.decorators.http import require_GET, require_POST
from django.http import HttpResponse
@require_GET
def show_page(request):
return HttpResponse("GET 요청만 가능합니다.")
@require_POST
def process_data(request):
return HttpResponse("POST 요청만 가능합니다.")
✨ 적용범위:
- API 또는 단일 기능 뷰에서 요청 메서드를 명확하게 제한하고자 할 때
📝 문제1] @require_GET
데코레이터의 주요 기능은 무엇인가?
A. GET 요청을 POST로 자동 변환한다.
B. GET과 POST 요청을 모두 허용한다.
C. GET 요청만 허용하고, 다른 요청은 차단한다.
D. 모든 요청을 200 OK로 처리한다.
✅ 정답: C
@require_GET
은 오직 GET 요청만 허용하고, 그 외의 메서드(PUT, POST, DELETE 등)는 자동으로 405 Method Not Allowed를 반환합니다.
📝 문제2] 다음 중 @require_POST
데코레이터가 올바르게 적용된 경우는?
A. 파일 다운로드 링크를 처리하는 뷰
B. 게시물 상세 조회 페이지
C. 사용자 등록 폼을 제출 처리하는 뷰
D. 페이지 이동을 위한 GET 요청 링크 처리
✅ 정답: C
@require_POST
는 POST 요청만 허용하므로,
회원가입, 로그인, 댓글 등록 등 폼 전송 처리 뷰에 적합합니다.
📝 문제3] @require_GET
또는 @require_POST
로 허용되지 않은 요청이 들어오면 어떤 일이 발생하는가?
A. 302 리다이렉트 응답
B. 403 Forbidden 오류
C. 404 Not Found 오류
D. 405 Method Not Allowed 오류
✅ 정답: D
명시된 HTTP 메서드 외의 요청이 오면 Django는 자동으로 405 Method Not Allowed를 반환합니다.
이는 잘못된 접근임을 명확히 알리는 표준 HTTP 응답입니다.
◽ 페이지 캐시: @cache_page(60 * 15)
해당 뷰의 응답을 15분간 캐시하여 반복 요청에 대한 응답 속도를
향상시킵니다.
</> 예시코드:
# views.py
from django.views.decorators.cache import cache_page
from django.http import HttpResponse
@cache_page(60 * 15)
def cached_news(request):
return HttpResponse("이 뉴스는 15분 동안 캐시됩니다.")
✨ 적용범위:
- 데이터 변화가 적은 페이지(뉴스, 공지사항 등)의 성능 개선을 위해
views.py
에서 사용
📝 문제1] @cache_page(60 * 15)
의 주된 역할은 무엇인가?
A. 뷰 함수 실행 시간을 제한한다.
B. 해당 뷰의 응답 결과를 15초 동안 저장한다.
C. 해당 뷰의 응답 결과를 15분간 캐시에 저장하여 재사용한다.
D. 캐시된 응답을 무조건 삭제한다.
✅ 정답: C
@cache_page(60 * 15)
은 뷰의 응답을 15분 동안 메모리에 저장해두고, 같은 요청이 들어오면 빠르게 캐시된 응답을 반환합니다.
📝 문제2] @cache_page()
를 사용할 때 주의해야 할 점으로 가장 적절한 것은?
A. 캐시를 사용하면 뷰 함수가 두 번 실행된다.
B. 캐시된 데이터는 매 요청마다 무조건 새로 저장된다.
C. 사용자별로 다른 콘텐츠를 반환해야 하는 경우 캐싱은 주의해서 사용해야 한다.
D. 캐시를 사용하면 데이터베이스 연결이 필요 없어지므로 models.py는 필요 없다.
✅ 정답: C
캐시는 고정된 응답을 재사용하기 때문에,
로그인 사용자별, 동적으로 다른 데이터를 반환하는 뷰에는 부적절할 수 있음.
📝 문제3] 다음 중 @cache_page(60)
이 적용된 뷰를 호출했을 때의 효과로 옳은 것은?
A. 60초 동안 뷰 코드가 실행되지 않고 캐시된 응답이 반환된다.
B. 매 요청마다 무조건 새로운 결과를 계산한다.
C. 60초 후에 서버가 자동으로 종료된다.
D. 60초 동안 데이터베이스에 접근할 수 없다.
✅ 정답: A 캐시가 유지되는 동안은 뷰 함수가 실행되지 않고, 미리 저장된 응답이 반환되어 속도가 빨라지고 서버 부하도 줄어듭니다.