[sesac LLM] day9-240112 Git, Class
Git
git 에서 branch를 만드는 명령어는?
git branch branch이름
Branch란?
- 나무의 가지(branch)
- 독립된 작업 공간
- 지금 작업하던 내용을 그대로 유지한채로 새로운 개발이 가능
- Branch한 스냅샷(commit)을 베이스(base)라고 부른다.
- git branch -a 명령어로 현재 브랜치 확인 가능
git merge 자세히 보기
- git merge 는 두 개의 브랜치를 하나로 합치는 과정입니다.
- 병합하려는 브랜치로 이동합니다.
- git checkout main
- git checkout main
- 병합할_브랜치 를 현재 브랜치에 합칩니다.
- git merge 병합할_브랜치명
Fast-word merge
- main 브랜치에 commit이 없다면, 가능한 시나리오
- 현재 브랜치의 끝이 병합할_브랜치 의 시작점에 연결되는 경우, 단순히 포인터만 이동
- 마치 브랜치가 한 줄기로 계속 이어진 것처럼 처리
1. 새로운 브랜치 fix 를 만들어 봐요.
git branch fix
git checkout fix
git checkout -b fix : 위에 2 명령어를 한 번에 처리
2. ff.py 수정하기
1. print 함수에서 flush=True 넣어주기
3. 변경사항 commit
1. git commit -am "fix:ff.py"
4. 변경사항 main 브랜치에 반영하기
1. git checkout main
2. git merge fix
5
Recursive merge
- 이후 설명들은 main 브랜치에 commit이 생겼다면 처리 할 수 있는 방법
- 현재 브랜치와 main 브랜치의 공통 커밋을 하나 더 생성해서 합쳐버리는 방식
- 병합할_브랜치 커밋들 유지됨.
- git merge --no-ff 병합할_브랜치명
1. 새로운 브랜치 fix2 를 만들어 봐요.
git checkout -b fix2
2. no-ff.py 수정하기
print 함수에서 flush=True 넣어주기
3. 변경사항 commit
git commit -am "fix:no-ff.py in fix2"
4. main 브랜치로 이동
git checkout main
5. no-ff.py 또 수정해서 일부로 conflict 만들기
1. 36번째 줄에 print문에 인수 모두 없애기
2. git commit -am "fix:no-ff.py in main"
3. git merge fix2
4. conflict 구경하기 & 해결방법 생각하기
- Squash and merge
- main 브랜치에 commit이 생겼다면 처리 할 수 있는 방법
- 현재 브랜치와 main 브랜치의 공통 커밋을 하나 더 생성해서 합쳐버리는 방식
- 병합할_브랜치 커밋들은 삭제됨.
git checkout main git merge --squash 병합할_브랜치 git commit -m 'message'
1. 새로운 브랜치 fix3 를 만들어 봐요. - git checkout -b fix3 2. squash.py 수정하기 - print 함수에서 flush=True 넣어주기 3. 변경사항 commit - git commit -am "fix:squash.py in fix3" 4. main 브랜치로 이동 - git checkout main 5. squash.py 또 수정해서 일부로 conflict 만들기 36번째 줄에 print문에 인수 모두 없애기 2. git commit -am "fix:squash.py in main" git merge fix3 4. conflict 구경하기 & 해결방법 생각하기
Rebase and merge
main 브랜치에 commit이 생겼다면 처리 할 수 있는 방법 Base는 병합할_브랜치 가 분기된 브랜치 병합할_브랜치 의 Base를 최신 커밋으로 다시 설정. git checkout 병합할_브랜치 git rebase main git checkout main git merge 병합할_브랜치 10
새로운 브랜치 fix4 를 만들어 봐요.
git checkout -b fix4
2. rebase.py 수정하기
1. print 함수에서 flush=True 넣어주기
3. 변경사항 commit
1. git commit -am "fix:rebase.py in fix4"
4. main 브랜치로 이동
1. git checkout main
5. rebase.py 또 수정해서 일부로 conflict 만들기
1. 36번째 줄에 print문에 인수 모두 없애기
2. git commit -am "fix:rebase.py in main"
3. git merge fix4
4. conflict 구경하기 & 해결방법 생각하기
- 병합 후 브랜치 정리 병합이 완료된 후에는 더 이상 필요하지 않은 브랜치를 정리합니다. 예시 명령어: git branch -d 새브랜치명 git push origin --delete 새브랜치명 참고: Git의 다양한 브랜치 병합 방법 (Merge, Squash & Merge, Rebase & Merge) 12
클래스
클래스란 무엇인가?
- 클래스는 객체를 생성하기 위한 일종의 템플릿
- 객체의 속성(attributes)과 행동(methods)을 정의하며, 데이터와 함수를 하나의 캡슐화 된 단위로 묶는다.
- 예를 들어 '자동차' 클래스는 속성(색상, 브랜드)과 메소드(운전, 정지)를 가질 수 있다.
객체 지향 프로그래밍(OOP)과 클래스
- 객체 지향 프로그래밍은 프로그램을 객체들의 집합으로 파악하는 프로그래밍 패러다임.
- 절차 지향 프로그래밍의 대안으로 나왔다.
- 클래스는 이러한 OOP의 핵심 요소로, 실세계의 사물을 모델링하고 프로그램 내에서 그 행동을 정의한다.
- OOP의 주요 특징은 상속, 다형성, 캡슐화 같은 것들이 있는데, 핵심은 클래스와 객체이다.
예제 코드:
class Car:
def __init__(self, color, brand):
self.color = color
self.brand = brand
def drive(self):
return f"{self.brand} 붕붕"
def stop(self):
return f"{self.brand} 끼이익"
my_car = Car("회색", "모닝")
print(my_car.drive())
print(my_car.stop())
클래스 선언 및 기본 구조
- 클래스는 class 키워드로 만든다.
- 클래스의 이름은 일반적으로 파스칼 이스(PascalCase)를 사용한다.
- 클래스 내부에는 데이터를 나타내는 속성(attributes)과 기능을 나타내는 메소드 (methods)가 정의된다.
class Wizard:
def __init__(self, name, age, skill):
self.name = name
self.age = age
self.skill = skill
def greet(self): # 메소드
return f"안녕? 나는 {name}이야. 올해 {age}살 됐어. 내 {skill}맛 좀 볼래?"
# 객체 생성
dumbledore = Wizard("덤블도어", 60, '엑스펙토 파트로눔')
print(dumbledore.greet())
Wizard 클래스는 name 과 age , skill 3개의 속성을 가지며, greet 메소드를 통해 인 사를 한다. 우리가 게임에서 보는 NPC들은 모두 이렇게 만들어 졌을 것이다.
객체(Objects):
- 객체는 클래스에 의해 생성된 데이터 구조. 클래스에 정의된 속성과 행동을 가진다.
- 객체는 실세계의 사물이나 개념을 소프트웨어 내에서 표현한 것
- 파이썬에서 모든 것은 객체로, 숫자, 문자열, 리스트, 함수 등도 객체이다.
- 예를 들어, Car 클래스를 바탕으로 만들어진 각각의 차량은 Car 객체일 것이다.
인스턴스(Instances):
인스턴스는 클래스의 정의에 따라 메모리에 생성된 객체를 의미한다. 특정 클래스의 구조와 기능을 가진 객체를 그 클래스의 인스턴스라고 합니다. 사람의 설계도 같은 것이 있다고 할 때, 그 설계도가 클래스이며, 우리가 개와 사람을 구분할 수 있듯이 객체는 그 클래스가 세상에 드러난 것으로 볼 수 있다. 사람들 마다 나이도 다르고 생김새도 다르듯이 각 객체의 고유성이 강조되면 인스턴스라 볼 수 있다. 큰 차이 없이 써도 사실상 무방할 것 같다.
class Panda:
def __init__(self, name):
self.name = name
# Panda 클래스의 인스턴스 생성
pubao = Panda("푸바오")
print(isinstance(pubao, Panda)) # True
9
클래스와 인스턴스의 차이는?
A) 클래스는 메모리에 생성된 객체이며, 인스턴스는 클래스의 정의를 나타낸다.
**B) 클래스는 객체의 설계도와 같고, 인스턴스는 그 설계도에 따라 생성된 실제 객체이다.**
C) 클래스와 인스턴스는 같은 개념이며, 차이가 없다.
퀴즈 2
2. 객체 지향 프로그래밍의 핵심 특징?
A) 객체 지향 프로그래밍은 함수의 집합으로 프로그램을 구성한다.
B) 객체 지향 프로그래밍에서 클래스는 불필요하며, 모든 코드는 절차적으로 실행된다.
**C) 객체 지향 프로그래밍은 실세계의 사물을 모델링하여 프로그램 내에서 객체의 행동**
속성과 메소드
- 속성(Attribute): 클래스에 속한 데이터. 인스턴스의 상태를 저장한다.
- 메소드(Method): 클래스에 속한 함. 해당 클래스의 객체가 수행할 수 있는 행동을 정의.
- 속성은 init 메소드 내에서 정의되며, 'self' 키워드를 통해 클래스의 다른 메소드에서 접근할 수 있음.
- 메소드는 객체의 행동을 정의하며, 첫 번째 파라미터로 self 를 받아 인스턴스에 접근한다. 주의사항
- 이름이 self인 것은 문법이 아니라 관습(convention)!
- 클래스 생성 시 init 안해도 될까?
- 속성을 할당할 필요가 없으면 안해도 된다.
- 예제코드:
# Panda 클래스 정의
class Panda:
def __init__(self, name, breed):
self.name = name # 이름 속성
self.breed = breed # 품종 속성
def eat_bamboo(self): # 대나무 먹는 메소드
return f"{self.name}가 또 대나무를 먹습니다."
# 객체 생성
my_dog = Panda("푸바오", "자이언트 판다")
print(my_dog.eat_bamboo())
Panda 클래스는 판다의 이름과 품종을 속성으로 가지며, eat_bamboo 메소드로 대나무 먹 는 행동을 나타낸다.
이닛메소드:
init 메소드: 생성자
- init 메소드는 클래스를 생성하는, 즉 초기화하는 역할을 하는 메소드이다.
- 객체의 초기 상태를 정의해 줘야 객체로서 의미를 갖는다.
- 예: 게임에서 처음 생성된 캐릭터. 레벨 1의 경험치 0
- 예: 갓 태어난 아기 객체 외부와의 상호작용으로 객체의 상태가 변하면서 점차 객체들 간의 차이가 발생한다.
클래스 인스턴스 생성
- 클래스 인스턴스는 클래스명(인자...) 형태로 생성.
- 생성 시 init 메소드에 정의된 매개변수에 해당하는 인자를 전달해줘야 한다.
- 예제 코드:
- new_laptop = Laptop("Apple", "MacBook Pro") print(new_laptop.describe())
여기서 new_laptop 은 Laptop 클래스의 새 인스턴스이다.
메소드 호출과 속성 접근
- 메소드 호출은 인스턴스명.메소드명(인자1, 인자2, ...) 형태로 이루어집니다.
- 속성에 접근할 때는 인스턴스명.속성명을 사용합니다.
- 예제 코드를 통해 이를 설명합니다:
pythonCopy code
# 메소드 호출과 속성 접근 예제
print(my_laptop.brand) # 'Apple'
print(my_laptop.model) # 'Macbook Pro'
print(my_laptop.describe()) # '2020년형 인텔 어쩌구저쩌구'
위 코드에서 my_laptop 인스턴스를 통해 브랜드와 모델 속성에 접근하고, describe 메소드를 호출한 예제입니다.
- **my_laptop.brand**는 my_laptop 인스턴스의 브랜드 속성에 접근합니다.
- **my_laptop.model**은 my_laptop 인스턴스의 모델 속성에 접근합니다.
- **my_laptop.describe()**는 my_laptop 인스턴스의 describe 메소드를 호출합니다.
이처럼, 인스턴스를 통해 속성과 메소드에 접근하여 해당 속성의 값을 가져오거나 메소드를 실행할 수 있습니다.
퀴즈
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
def bark(self):
return "멍멍!"
my_dog = Dog("마루", "시바견")
- A) 클래스 이름 옆에 () 표시를 빠트렸다.
- B) __init__ 메소드의 매개변수가 잘못됐다.
- C) bark 메소드 정의가 잘못됐다.
- D) 인스턴스 생성이 잘못됐다.
- E) 이 코드는 잘못되지 않았다.
클래스변수란?
- 클래스 변수는 클래스 정의 내에서 선언되며, 모든 인스턴스가 공유하는 변수입니다.
- 이것은 생성자의 인스턴스 변수와는 구별되어야 합니다. 인스턴스 변수는 각 인스턴스가 고유한 값을 가지지만, 클래스 변수는 모든 인스턴스가 동일한 값을 공유합니다.
- 클래스 변수는 클래스 자체에 속하며, 클래스의 이름을 통해 접근할 수 있습니다. 클래스명.클래스변수 형식으로 접근하고, 클래스명.클래스변수 = 새로운값 형식으로 값을 할당할 수 있습니다.
- 한 인스턴스가 클래스 변수의 값을 변경하면 다른 인스턴스의 클래스 변수도 그 변경된 값으로 변경됩니다. 이는 모든 인스턴스가 클래스 변수를 공유하기 때문입니다.
- 클래스 변수는 전역 변수를 클래스 내에서 사용하는 것과 유사한 개념이며, 데이터를 클래스 수준에서 관리하고 공유할 때 유용합니다.
예시로 스타크래프트의 질럿에서 언급한 경우, "속도"라는 클래스 변수는 모든 질럿 인스턴스가 공유하며, 한 인스턴스에서 속도를 변경하면 모든 질럿의 속도가 변경될 것이고, "HP"는 각 질럿 인스턴스마다 고유한 값을 가지게 됩니다.
예제
# 클래스 정의
class Zealot:
velocity = 1.00 # 클래스 변수
# 생성자 메소드
def __init__(self, hp, shield, damage):
self.hp = hp # 인스턴스 변수
self.shield = shield # 인스턴스 변수
self.damage = damage # 인스턴스 변수
# 메소드
def roar(self):
print("My life for Aiur!")
# 인스턴스 생성
zealot_1 = Zealot(100, 60, 8)
zealot_2 = Zealot(100, 60, 8)
# 클래스 변수와 인스턴스 변수 사용
print(Zealot.velocity) # 클래스 변수 출력: 1.00
print(zealot_1.velocity) # 인스턴스에서 클래스 변수 출력: 1.00
print(zealot_2.velocity) # 인스턴스에서 클래스 변수 출력: 1.00
# 클래스 변수 값 업데이트
Zealot.velocity = 1.05
# 업데이트된 클래스 변수 값 출력
print(Zealot.velocity) # 클래스 변수 출력: 1.05
print(zealot_1.velocity) # 인스턴스에서 클래스 변수 출력: 1.05
print(zealot_2.velocity) # 인스턴스에서 클래스 변수 출력: 1.05
만일, zealot_1만 속도가 빨라지는 버프를 받았다. 그럼 모든 Zealot이 빨라질까? zealot_1.velocity = 1.1 print(Zealot.velocity) # 값은? 19
class Zealot:
velocity = 1.00 # 클래스 변수
def __init__(self, hp, shield, damage):
self.hp = hp # 인스턴스 변수
self.shield = shield # 인스턴스 변수
self.damage = damage # 인스턴스 변수
# 두 개의 Zealot 인스턴스 생성
zealot_1 = Zealot(100, 60, 8)
zealot_2 = Zealot(100, 60, 8)
# 클래스 변수 velocity 변경
Zealot.velocity = 1.10 # 올바른 방법
# 결과 확인
print(Zealot.velocity) # 1.10
print(zealot_1.velocity) # 1.10
print(zealot_2.velocity) # 1.10
ㅍ
상속의 개념과 장점
- 상속(Inheritance)은 한 클래스(자식 클래스)가 다른 클래스(부모 클래스)의 멤버(속성과 메소드)를 물려받는 것을 의미한다.
- 기존 클래스의 재사용을 목적으로 한다.
- 자식 클래스는 부모 클래스의 모든 기능을 사용할 수 있으며,
- 필요에 따라 새로운 기능을 추가하거나 기존 기능을 수정(오버라이딩)할 수 있다.
파이썬에서 상속 구현하기
파이썬에서 상속은 부모 클래스를 자식 클래스 정의에 괄호 안에 명시함으로써 구현된다. super() 함수를 사용하면, 부모 클래스의 메소드에 접근할 수도 있다. 예제 코드:
class Unit:
def __init__(self, name, health):
self.name = name
self.health = health
def move(self):
return f"{self.name} 이동 중"
class Marine(Unit):
def __init__(self, name, health, damage):
super().__init__(name, health)
class Unit:
def __init__(self, name, health):
self.name = name
self.health = health
def move(self):
return f"{self.name} 이동 중"
class Marine(Unit):
def __init__(self, name, health, damage):
super().__init__(name, health)
self.damage = damage
def attack(self):
return f"{self.name} 공격! 데미지: {self.damage}"
class Medic(Unit):
def heal(self, target):
return f"{self.name}이(가) {target.name} 치료 중"
class Firebat(Unit):
def __init__(self, name, health, damage):
super().__init__(name, health)
self.damage = damage
def attack(self):
return f"{self.name} 화염 방사! 데미지: {self.damage}"
# 인스턴스 생성
marine = Marine("마린", 100, 20)
medic = Medic("메딕", 60)
firebat = Firebat("파이어뱃", 120, 30)
# 메소드 호출
print(marine.move()) # '마린 이동 중'
print(marine.attack()) # '마린 공격! 데미지: 20'
print(medic.heal(marine)) # '메딕이(가) 마린 치료 중'
print(firebat.attack()) # '파이어뱃 화염 방사! 데미지: 30'
- Unit 클래스는 모든 유닛의 공통적인 기능(이동)과 속성(이름, 체력)을 정의합니다.
- Marine, Medic, Firebat 클래스는 Unit 클래스를 상속받아 각각 고유한 기능(공격, 치 료, 화염 방사)을 추가합니다.
- super().init(name, health)를 통해 부모 클래스인 Unit의 생성자를 호출하여 공통 속성 을 초기화합니다. 25
퀴즈
class Unit:
def __init__(self, name, health):
self.name = name
self.health = health
def move(self):
return f"{self.name} 이동 중"
class Medic(Unit):
def heal(self, target):
return f"{self.name}이(가) {target.name} 치료 중"
A) heal 메소드
B) move 메소드
C) attack 메소드
D) __init__ 메소드
다형성: 메소드 오버라이딩과 오버로딩
- 다형성은 같은 이름의 메소드가 다른 클래스 또는 같은 클래스 내에서 다른 행동을 할 수 있 게 하는 프로그래밍 개념이다.
메소드 오버라이딩(Method Overriding):
상속 관계에 있는 클래스에서 부모 클래스의 메소드를 자식 클래스에서 재정의하는 것이 다.
- 상속받는 클래스에 따라 다른 기능을 수행할 수 있다.
메소드 오버로딩(Method Overloading):
- 같은 이름의 메소드가 매개변수의 유형이나 개수에 따라 다른 행동을 하는 것입니다. 파이썬은 오버로딩을 직접적으로 지원하지 않지만, 비슷한 효과가 있는 방법이 있다고 알려져 있다. 이 수업에서는 다루지 않겠다.