문제: 두 자연수 A와 B가 주어진다. 이때, A+B, A-B, A*B, A/B(몫), A%B(나머지)를 출력하는 프로그램을 작성하시오.
a, b = map(int, input().split())
text = ["+", "-", "*", "/", "%"]
result = [eval(f"{a}{operator}{b}") for operator in text]
print(*result)
먼저 eval()함수는 문자열로 된 파이썬 표현식을 실행하여 그 결과를 반환합니다. 즉, eval 함수는 문자열을 파이썬 코드로 처리해서 계산한 결과를 돌려줍니다. 예시:
x = 5
expr = "x + 3"
result = eval(expr) # x + 3을 계산하여 8을 반환print(result) # 출력: 8
*result에서 *은 언팩(unpack) 연산자입니다. 리스트나 튜플과 같은 시퀀스 자료형을 함수에 인자로 전달할 때, 그 시퀀스의 각 요소를 개별 인자로 풀어서 전달하는 기능을 합니다.
result = [1, 2, 3]
print(*result) # 출력: 1 2 3
위 코드에서 print(*result)는 result 리스트의 각 요소를 개별 인자로 풀어서 print 함수에 전달합니다. 즉, print(1, 2, 3)과 동일하게 작동합니다.
따라서, *result를 사용하면 리스트나 튜플의 각 요소가 공백으로 구분되어 출력됩니다. 즉, print(*result)는 print(result[0], result[1], result[2], ...)와 같은 효과를 냅니다.
문제: 오븐 시계
KOI 전자에서는 건강에 좋고 맛있는 훈제오리구이 요리를 간편하게 만드는 인공지능 오븐을 개발하려고 한다. 인공지능 오븐을 사용하는 방법은 적당한 양의 오리 훈제 재료를 인공지능 오븐에 넣으면 된다. 그러면 인공지능 오븐은 오븐구이가 끝나는 시간을 분 단위로 자동적으로 계산한다.
또한, KOI 전자의 인공지능 오븐 앞면에는 사용자에게 훈제오리구이 요리가 끝나는 시각을 알려 주는 디지털 시계가 있다.
훈제오리구이를 시작하는 시각과 오븐구이를 하는 데 필요한 시간이 분단위로 주어졌을 때, 오븐구이가 끝나는 시각을 계산하는 프로그램을 작성하시오.
아무리 해도 안되길래 GPT의 도움을 받았다 힌트는 바로 그냥 h, m으로 계산하는게 아니라, h*60 + m + 조리 시간 이렇게 다 더한 다음 24시간도 분으로 계산해서(24*60), 그냥 나누면 되는 것이다.
h, m = map(int, input().split())
cm = int(input())
total = h * 60 + m + cm
total %= 1440print(total // 60, total % 60)
코드도 짜보니 정말 간단했다. 알고보니 나는 1440이 아니라, 59분으로 착각해 1439로 적어 놓았고, 알고보니, total = total % 1440에서 total이 1440보다 작을경우, 그 값을 그대로 반환하는것을 까먹은.... 만약 1440보다 작으면 그 값을 그대로 반환해(예를 들어: 880), total // 60을 통해(나머지는 빼고) 값만 받은것을 h로 나머지를 m으로 하는것이 빠르고 좋았다.
문제: 주사위 세개
1에서부터 6까지의 눈을 가진 3개의 주사위를 던져서 다음과 같은 규칙에 따라 상금을 받는 게임이 있다. 같은 눈이 3개가 나오면 10,000원+(같은 눈)×1,000원의 상금을 받게 된다. 같은 눈이 2개만 나오는 경우에는 1,000원+(같은 눈)×100원의 상금을 받게 된다. 모두 다른 눈이 나오는 경우에는 (그 중 가장 큰 눈)×100원의 상금을 받게 된다. 예를 들어, 3개의 눈 3, 3, 6이 주어지면 상금은 1,000+3×100으로 계산되어 1,300원을 받게 된다. 또 3개의 눈이 2, 2, 2로 주어지면 10,000+2×1,000 으로 계산되어 12,000원을 받게 된다. 3개의 눈이 6, 2, 5로 주어지면 그중 가장 큰 값이 6이므로 6×100으로 계산되어 600원을 상금으로 받게 된다. 3개 주사위의 나온 눈이 주어질 때, 상금을 계산하는 프로그램을 작성 하시오.
이것도 10분 동안 고민해도 어떻게 할지 몰랐는데.. 특히 큰 숫자만을 골라 *100을 한다? 알고보니 max가 있었다. 그냥 a, b, c를 받아서 그것을 리스트에 넣고 max로 큰 수를 찾아서 100을 곱하면 되는 것이였다. 그리고 두개만 맞을 경우에도 보니까 저렇게 경우의 수가 3개 밖에 없어서(사실 내가 착각한...) 저렇게 적어주니 잘 작동..했ㄷ....
a,b,c = map(int, input().split())
list = [a,b,c]
if a == b == c:
print(a*1000 + 10000)
elif a == b or a == c or c == b:
if a == b:
print(a*100 + 1000)
elif b == c:
print(b*100 + 1000)
else:
print(a*100 + 1000)
else:
print(max(list)*100)
CS
계속해서 해보겠습니다 전략 패턴(strategy pattern) 혹은 정책 패턴(policy pattern)은 객체의 행위를 바꾸고 싶은 경우, '직접' 수정하지 않고 전략이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴입니다. 쉽게 말해서 알고리즘을 캡슐화하여 독립적으로 변경할 수 있도록 만드는 디자인 패턴입니다. 이 패턴은 클래스 내에서 어떤 알고리즘을 실행할 때, 여러 알고리즘을 서로 바꿔가며 사용할 수 있도록 하며, 이를 통해 알고리즘의 변경이 클라이언트 코드에 영향을 주지 않도록 합니다. 더 쉽게 말하면, 여러 알고리즘을 객체로 만들어 필요에 따라 바꿔서 사용할 수 있도록 하는 패턴입니다. 예시:
여기서 캡슐화, 알고리즘이란? 캡슐화(encapsulation)란 객체 지향 프로그래밍에서 데이터(속성)와 그 데이터를 처리하는 메서드(함수)를 하나의 단위로 묶는 개념입니다. 즉, 객체 내부의 구현 세부 사항을 외부에서 숨기고, 필요한 부분만 외부에 공개하여 사용하도록 하는 원칙입니다. 이를 통해 객체의 상태나 행동이 외부에서 직접적으로 변경되지 않도록 보호할 수 있습니다. 알고리즘(algorithm)은 문제를 해결하기 위한 일련의 단계적 절차나 규칙을 말합니다. 쉽게 말해서, 주어진 문제를 해결하는 방법을 구체적으로 정리한 "방법론"입니다. 컴퓨터 프로그래밍에서는 알고리즘이란 컴퓨터가 어떤 작업을 수행할 수 있도록 하는 명확한 단계들을 뜻합니다. 예를 들어, "두 수를 더하는 방법"을 알고리즘으로 표현한다면: 두 수를 입력받는다. 두 수를 더한다. 결과를 출력한다. 이러한 단계들이 알고리즘이 됩니다. 중요한 점은 알고리즘이 구체적이고 명확한 절차로 되어 있다는 점입니다.
예시를 보겠습니다. 1. 알고리즘 (Algorithm) 햄버거를 만드는 "순서"를 생각해봅시다. 빵을 준비한다. 패티를 굽는다. 빵 위에 패티를 올린다. 야채와 소스를 추가한다. 빵을 덮는다. 손님에게 제공한다. 이 순서가 햄버거를 만드는 알고리즘입니다.
2. 캡슐화 손님 입장에서 보면 햄버거 만드는 과정(알고리즘)은 숨겨져 있으며, 손님은 그냥 "햄버거 주세요"라고 하면 햄버거를 받습니다.
classBurgerShop:def__make_burger(self):# __ (언더스코어 2개) → 외부에서 접근 불가능 (캡슐화)print("1. 빵을 준비한다")
print("2. 패티를 굽는다")
print("3. 빵 위에 패티를 올린다")
print("4. 야채와 소스를 추가한다")
print("5. 빵을 덮는다")
print("6. 손님에게 제공한다")
deforder_burger(self):# 손님이 햄버거를 주문하는 함수print("손님: 햄버거 하나 주세요!")
self.__make_burger() # 내부적으로 햄버거를 만듦 (손님은 내부 로직을 모름)print("햄버거가 준비되었습니다!")
# 가게 객체 생성
shop = BurgerShop()
# 손님이 햄버거 주문
shop.order_burger()
# shop.__make_burger() # 에러: 이렇게 직접 호출하려 하면 에러가 남 (캡슐화 됨!)
출력:
손님: 햄버거 하나 주세요!
1. 빵을 준비한다
2. 패티를 굽는다
3. 빵 위에 패티를 올린다
4. 야채와 소스를 추가한다
5. 빵을 덮는다
6. 손님에게 제공한다
햄버거가 준비되었습니다!
이렇게 보면 팩토리 패터하고 비슷하지 않나요? 공통점 둘 다 내부 구현을 숨긴다. 사용자(클라이언트)는 세부적인 과정(로직)을 몰라도 쉽게 사용할 수 있다. 코드의 유지보수성을 높이고, 변경에 유연하게 대처할 수 있다.
보시는 바와 같이, 캡슐화는 내부 구현을 감추고, 팩토리는 객체 생성 방식을 감추는것이 큰 차이입니다.
즉, 클래스에서 햄버거 만드는 알고리즘이 있지만, self.__make_burger()처럼 내부에서 자동으로 만들어주는(내부 로직은 숨기는) 방법을 캡슐화라고 합니다.
만약에 여기서 팩토리 패턴으로 바꾼다고 한다면,
# 햄버거 클래스classBurger:defprepare(self):passclassCheeseBurger(Burger):defprepare(self):print("치즈버거를 준비합니다!")
classChickenBurger(Burger):defprepare(self):print("치킨버거를 준비합니다!")
# 햄버거 공장 (팩토리)classBurgerFactory: @staticmethoddefcreate_burger(burger_type):if burger_type == "cheese":
return CheeseBurger()
elif burger_type == "chicken":
return ChickenBurger()
else:
raise ValueError("알 수 없는 버거 타입!")
# 손님이 버거 주문
burger = BurgerFactory.create_burger("cheese") # 치즈버거 자동 생성
burger.prepare()
burger2 = BurgerFactory.create_burger("chicken") # 치킨버거 자동 생성
burger2.prepare()
여기서 staticmethod란 개념이 나옵니다. @staticmethod는 클래스 내부에서 정의하지만, 인스턴스(self)나 클래스(cls)를 사용하지 않는 메서드를 만들 때 사용하는 데코레이터입니다. 즉, 객체(인스턴스)를 만들지 않고도 호출할 수 있는 메서드를 만들고 싶을 때 사용합니다. 클래스를 만들면 크게 두 가지를 가질 수 있습니다: 클래스 속성 (Class Attribute) 클래스 자체가 가지는 변수 모든 인스턴스가 공유함
인스턴스 속성 (Instance Attribute) __init__()에서 self를 통해 개별 인스턴스가 가지는 변수 즉, @staticmethod는 클래스 속성도, 인스턴스 속성도 사용하지 않음 @staticmethod의 특징 인스턴스(self) 필요 없음 클래스(cls) 필요 없음 클래스 안에서 함수처럼 동작함
classExample:
class_attr = "나는 클래스 속성!"def__init__(self, value):
self.instance_attr = value # 인스턴스 속성 @staticmethoddefstatic_method():print("나는 클래스 속성도, 인스턴스 속성도 사용하지 않아!")
static_method()는 self(인스턴스)도, cls(클래스)도 안 받습니다. 즉, 클래스 속성(class_attr)도 인스턴스 속성(instance_attr)도 안 씁니다. 그냥 클래스 내부에 있지만, 일반 함수처럼 동작합니다.
즉, 팩토리 패턴(Factory Pattern) 인스턴스를 생성하는 과정을 함수(팩토리)에서 처리해서, 객체 생성 로직을 감추고 클라이언트 코드에서는 어떤 클래스의 인스턴스인지 신경 쓰지 않도록 함.
캡슐화(Encapsulation) 데이터(속성)와 기능(메서드)을 감추고, 외부에서는 제한된 방법으로만 접근 가능하게 함. 즉, 내부 구현을 숨기고 인터페이스만 제공함.
자, 그러면 다시 돌아와서 전략 패턴에 대해 말해봅시다.
classStrategy:defexecute(self):pass
목적: 다양한 알고리즘(전략)들이 반드시 구현해야 하는 메서드(execute())를 정의합니다. 이 인터페이스를 통해 구체적인 전략(ConcreteStrategy)들이 일관된 방법으로 동작하게 됩니다.
목적: Strategy 인터페이스를 상속받아 각기 다른 알고리즘을 구현합니다. ConcreteStrategyA는 "Strategy A"를, ConcreteStrategyB는 "Strategy B"를 반환합니다. 즉, 실행하는 알고리즘이 다릅니다. 나중에 새로운 전략을 추가할 때, Strategy 인터페이스만 준수하면 쉽게 확장할 수 있습니다.
목적: 전략(알고리즘)을 사용하는 환경(또는 상황)을 캡슐화합니다. 주요 역할: 전략의 보관: 생성자에서 전달받은 전략 객체를 인스턴스 변수 strategy에 저장합니다. 전략의 교체: set_strategy() 메서드를 통해 실행 중에도 전략을 동적으로 바꿀 수 있습니다. 전략 실행: execute_strategy() 메서드는 현재 설정된 전략 객체의 execute() 메서드를 호출하여, 실제 알고리즘을 실행합니다. 클라이언트(사용자)는 Context 클래스에 의존하게 되며, 구체적인 전략이 무엇인지는 신경 쓰지 않아도 됩니다.
정말 쉽게 설명하자면, 맨 위에 있는 클래스는 한 마디로 붕어빵 틀이라고 생각하시면 됩니다. 그리고 다른 클래스에서 상속을 받아, 그 틀을 기반으로 오버라잇이나 다른 방법을 기반으로 하여 각자 원하는 스타일의 붕어빵을 만든다고 생각하시면 됩니다. 즉, 기반이 되는 클래스를 기반으로 그 클래스를 마음대로 커스터마이즈 하신다고 생각하시면 됩니다.
어떻게 보면 set_strategy(): 이 메서드는 Context 클래스 안에서 현재 전략을 동적으로 교체할 수 있게 해주는 역할을 합니다. 게임 예시로 말하자면, 캐릭터가 어떤 행동 방식을 사용할지 결정하는 순간입니다.
execute_strategy(): 이 메서드는 현재 설정된 전략을 실행하는 메서드입니다. 예를 들어, 캐릭터가 실제 전투에서 이동하고 공격하는 행동을 하게 되는 시점입니다. 라고 할 수 있습니다.