whatisthis?

Phython. 파이썬 코딩 기초편-08(上) 본문

WEB STUDY/PHYTHON | BACK-END

Phython. 파이썬 코딩 기초편-08(上)

thisisyjin 2021. 9. 18. 14:56

<Quiz>

 

당신의 회사에서는 매주 1회 보고서를 작성해야한다.

보고서는 항상 아래와 같은 형태로 출력되어야한다.

 

- X  주차 주간 보고 -

부서 :

이름 :

업무 요약 :

 

1주차부터 50주차까지의 보고서 파일을 만드는 프로그램을 작성하시오.

 

조건 : 파일명은 1주차.txt , 2주차.txt, ... 와 같이 만든다.

 

 

내가 작성한 코드 

for week in range(1,51):
with open("{0}주차.txt".format(week), "w", encoding="utf8") as report_file:
report_file.write("- {0} 주차 주간 보고 - \n부서 :\n이름 : \n업무요약 : \n".format(week))

나는 with문을 이용하였다.
이 대신

for week in range(1,51):
report_file = open("{0}주차.txt".format(week), "w", encoding="utf8")
report_file.write("- {0} 주차 주간 보고 - \n부서 :\n이름 : \n업무요약 : \n".format(week))
report_file.close()

와 같이 작성해도 된다.

 

 

 

<for문 vs while문>

for문은 정해져있는만큼 반복할떄,
(이 문제같은경우 1~50주차라고 정해져있었으므로 for)

while문은 얼마나 반복 수행해야 할 지 모를 때,
특정한 조건에 도달할때까지 계속해 이런 명령을 하고 싶을 때 사용

 

 

___

 

강의에서 언급된 모범 답안.

 

str(i) + "주차.txt"  # 강의 모범 답안

"{0}주차.txt".format(week)  # 내가 작성한 코드

다른 부분은 모두 내가 작성한것과 같으나, 

나같은 경우 파일명을 format을 이용해서 week변수를 for문을 반복시켰지만

강의 답안에서는 str(i) + "텍스트" 형식으로 나타냈다.

그러나, 결과는 같은 걸 보면 큰 차이는 없는 것 같다.

 


1. 클래스

 

스타크래프트 게임 예제.

 

# 마린 : 공격 유닛, 군인.

name = "마린"
hp = 40
damage = 5

print("{0} 유닛이 생성되었습니다.".format(name))
print("체력 {0}, 공격력 {1}\n".format(hp, damage))

# 탱크 : 공격 유닛, 탱크. 일반모드와 시즈모드.

tank_name = "탱크"
tank_hp = 150
tank_damage = 35

print("{0} 유닛이 생성되었습니다.".format(tank_name))
print("체력 {0}, 공격력 {1}\n".format(tank_hp, tank_damage))


def attack(name, location, damage):
    print("{0} : {1} 방향으로 적군을 공격합니다. [공격력 {2}]".format(name, location, damage))


attack(name, "1시", damage)
attack(tank_name, "1시", tank_damage)

위와 같이 각 유닛을 만들고 공격하는 attack 함수를 선언했다.

 

그러나, 실제 게임에서는 이러한 유닛들이 수십 수백개가 존재하는데, 유닛이 추가될때마다

tank2, tank3, tank4 ... 와 같이 하나하나 추가해줄수는 없다.

 

이때 필요한 것이 바로 클래스이다.

(= 연관성있는 함수와 변수의 집합)

 

이는 붕어빵을 제작하기 위한 붕어빵 틀과 비유되기 좋은데, 틀을 한번 만들어 놓으면

같은 모양의 붕어빵을 계속해서 만들 수 있기 떄문이다.

 

 

__

 

class Unit:
    def __init__(self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print("{0} 유닛이 생성되었습니다.".format(self.name))
        print("체력 {0}, 공격력 {1}".format(self.hp, self.damage))

 

다음과 같이 클래스를 선언할 수 있다.

 

Class (클래스명):

     def __init__(self)

는 기본값이므로 반드시 작성해야한다.

 

self라는 변수 뒤에 원래의 작성하려 하는 변수들을 차례로 입력하면 된다.

그리고, 본문 부분에서 사용되는 변수는 모두 self.name = name과 같이 사용해야한다.

 

 

marine1 = Unit("마린", 40, 5)
marine2 = Unit("마린", 40, 5)
tank = Unit("탱크", 150, 35)

다음과 같이 클래스를 사용해서 유닛을 생성할 수 있다.

(여기서 클래스명 뒤에 인자들은 self를 제외한 인자들이다.)

 

 

이때, 유닛에 해당하는 marine1, marine2와 같은 것을 객체(Object)라고 한다.

 

 

 


 

2. __init__ 

(언더바두개씩)

 

클래스를 사용할때에는 반드시 self를 제외한 나머지 인자들을 다 입력해야 객체를 만들 수 있다.

 

위 예제에서는

 

def __init__(self, name, hp, damage):

위와 같이 self를 제외하면 3개의 인자가 있으므로

 

marine1 = Unit("마린", 40, 5)

tank = Unit("탱크", 150, 35)

다음과 같이 세개의 값을 모두 입력해줘야한다.

(한개의 값만 입력하거나 하면 오류가 뜬다.)

 

 


3. 멤버 변수

# 레이스 : 공중 유닛. 비행기. 클로킹 기능(상대에게 보이지않게)
wraith1 = Unit("레이스", 80, 5)

print("유닛 이름 : {0}, 공격력 : {1}".format(wraith1.name, wraith1.damage))

다음과 같이 클래스를 사용한 경우에

wraith1이라는 이름의 객체를 만들었다면 

 

wraith1하고 .을 누르면 사용 가능한 인자들이 나온다. (name, hp, damage)

 

 

___

 

# 마인드 컨트롤 : 상대 유닛을 빼앗음

wraith2 = Unit("빼앗은 레이스", 80, 5)
wraith2.clocking = True #객체에 추가로 변수를 만들어서 쓸 수 있음.
if wraith2.clocking == True:
    print("{0} 는 현재 클로킹 상태입니다.".format(wraith2.name))

 

이와 같이 객체에는 class에 지정되어있는 변수가 아닌(name, hp, damage)

다른 추가적인 변수를 만들어서 쓸 수 있다.

 

위에 코드를 보면 clocking이라는 변수는 클래스 내에 존재하지 않지만,

wraith2라는 객체 한정으로 clocking이라는 변수를 선언했으므로 임의적으로 확장시킨 것과 같다.

 

 


4. 메소드(method)

 

예제.

class AttackUnit:
    def __init__(self, name, hp, damage):
        self.name = name #self.name은 자기 자신의 값이고, name은 전달받은 값이다.
        self.hp = hp 
        self.damage = damage
    def attack(self, location):
        print("{0} : {1}방향으로 적군을 공격합니다. [공격력 {2}]".format(self.name, location, self.damage))
        # name과 attack은 self값을 사용했으나, attack은 전달받은 값을 사용한다는 의미이다.

 

앞에 self.가 붙은 변수의 경우에는 자기 자신의 변수에 접근하기 위함.

클래스 내에서 매소드 앞에는 항상 self.를 붙여준다.

 

self가 붙지 않은 값은 전달받은 값을 사용한다는 뜻임.

 

def damaged(self, damage):
        print("{0} : {1} 데미지를 입었습니다.".format(self.name, damage))
        self.hp -= damage
        print("{0} : 현재 체력은 {1}입니다.".format(self.name, self.hp))
        if self.hp <= 0:
            print("{0} : 파괴되었습니다.".format(self.name))

공격을 받았을 경우의 함수를 정의한다.

이때 if문을 써서 self.hp (즉, 클래스 내에 있는 자기 자신의 변수인 hp값)이 0이되면 파괴되었다는 문구가 뜨게 한다.

 

 

 

** 지금까지의 클래스와 클래스에 속한 함수를 살펴보면 다음과 같다.

-각 클래스는 기본적으로 def __init__(self)를 포함한다는 것에 유의-

 

# 일반 유닛
class Unit:
    def __init__(self, name, hp):
        self.name = name
        self.hp = hp

# 공격 유닛
class AttackUnit:
    def __init__(self, name, hp, damage):
        self.name = name #self.name은 자기 자신의 값이고, name은 전달받은 값이다.
        self.hp = hp 
        self.damage = damage

    def attack(self, location):
        print("{0} : {1} 방향으로 적군을 공격합니다. [공격력 {2}]".format(self.name, location, self.damage))
        # name과 attack은 self값을 사용했으나, attack은 전달받은 값을 사용한다는 의미이다.
    
    def damaged(self, damage):
        print("{0} : {1} 데미지를 입었습니다.".format(self.name, damage))
        self.hp -= damage
        print("{0} : 현재 체력은 {1}입니다.".format(self.name, self.hp))
        if self.hp <= 0:
            print("{0} : 파괴되었습니다.".format(self.name))

한 클래스에 __init__함수를 제외한 다른 함수들을 선언할 때에도 반드시 self 변수는 포함되어야한다.

 

 

한번 위 클래스가 제대로 작동되는지 시험해보기위해

파이어뱃이라는 유닛을 만들어서 공격을 하고, 대미지를 받도록 해보았다.

firebat1 = AttackUnit("파이어뱃", 50, 16)
firebat1.attack("5시") # location값 보냄. self는 안보내도됨

# 공격을 받는다고 가정
firebat1.damaged(25)
firebat1.damaged(25)

 

실행 결과

유닛의 체력이 50이기 때문에 25의 공격을 두번 받는다 가정했을때

체력이 0이 되고, damaged 함수의 if문에 의해 파괴되었다는 문구가 뜨게 된다.

 

 

 


5. 상속

 

상위 클래스 - 하위 클래스로 구분하여 변수를 상속시킬 수 있음.

예를들면, 위의 예제에서

Unit이라는 클래스와  AttackUnit이라는 클래스를 살펴보자.

 

# 일반 유닛 
class Unit:
    def __init__(self, name, hp):
        self.name = name
        self.hp = hp
# 공격 유닛
class AttackUnit:
    def __init__(self, name, hp, damage):
        self.name = name 
        self.hp = hp 
        self.damage = damage

두 클래스에는 공통된 변수인 name과 hp가 존재한다.

이때, 우리는 상속을 통해 Unit 클래스의 변수를 AttackUnit클래스로 끌어와 사용할 수 있다.

 

 

 

예제>

class AttackUnit(Unit):
    def __init__(self, name, hp, damage):
        Unit.__init__(self, name, hp)
        self.damage = damage
변경 전 변경 후 (상속)
class AttackUnit : class AttackUnit(Unit) :
def __init(self, name, hp, damage):
   self.name = name
   self.hp = hp
def __init(self, name, hp, damage):
   Unit.___init___(selff, name, hp)

 

 


6. 다중 상속

 

부모 클래스를 두개 이상 상속받는 것.

부모 클래스 : 자식 클래스가 N : 1인 경우.

 

# 날 수 있는 클래스
class Flyable:
    def __init__(self, flying_speed):
        self.flying_speed = flying_speed

    def fly(self, name, location):
        print('{0} : {1} 방향으로 날아갑니다. [속도 {2}]'.format(name, location, self.flying_speed))

# 공중 공격 유닛 클래스
class FlyableAttackUnit(AttackUnit, Flyable):
    def __init__(self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self, name, hp, damage)
        Flyable.__init__(self, flying_speed)

 

다음과 같이 공중 공격 유닛 클래스인 FlyableAttackUnit 클래스의 경우,

AttackUnit이면서도 Flyable이므로 두 클래스가 모두 부모 클래스가 된다.

즉, AttackUnit과 Flyable 두 클래스로부터 변수들을 상속받는 것인데, 이를 다중 상속이라고 한다.

 

 

 

class 자식클래스명(부모클래스1, 부모클래스2):
def __init__(self, 자식클래스 변수들 다)
   부모클래스1.__init__(self, 부모클래스 변수 다)
   부모클래스2.__init__(self, 부모클래스 변수 다)