python class/self

kangjuju·2023년 4월 12일
0

python

목록 보기
2/4
  • 객체지향적 프로그래밍 가능
  • 클래스는 새로운 이름공간을 지원하는 단위
  • 접근지정자X ,메소드 오버로딩X

기본 원형을 확인해보자

class TestClass: #class header
    #이하는 class body
    aa = 1 #멤버 변수. 클래스 내에서 전역
    
    def __init__(self):
        print('생성자')
        
    def __del__(self):
        print('소멸자')
    
    def printMsg(self): #멤버메소드
        name='한국인'
        print(name)
        print(self.aa)

print(TestClass.aa) #원형 클래스의 멤버변수를 호출가능.

test = TestClass() #생성자 호출
print(test.aa) # 멤버변수 사용

test.printMsg() #멤버메소드 호출방법1 : Bound Method call
TestClass.printMsg(test)  #멤버메소드 호출방법2 : unBound Method call

print('클래스 타입 확인' ,isinstance(test, TestClass))

#또다른 출력법
TestClass.printMsg(TestClass)
TestClass.printMsg(test1)
TestClass.printMsg(test2) 등등	
  • 생성자 __init__ 와 소멸자 __del__ 가 존재하며 self가 있다면 멤버메소드, 없다면 함수로 구분한다.

  • 원형클래스의 멤버변수를 바로 호출할 수도 있다. 다만 메소드는 해당방법으로 불가능.
    TestClass.printMsg() <-- error. 인자에 test 객체 주소를 넣으면 가능한데, 이유는 아래 self절에서 확인하자

  • 객체를 test에 생성했고, 동시에 생성자가 호출된다.

  • 클래스에서의 생성자는 초기화를, 소멸자는 마무리를 담당한다.
    가비지 컬렉터때문에 소멸자는 필수가 아니다.

  • 클래스 원형 자체도 객체로써의 주소를 갖는다. 인스턴스를 생성할때 또한 같은 구조의 객체가 생성되고, 당연히 다른 주소로 생성되어 사용된다.

  • isinstance 로 해당 클래스의 객체인지를 확인가능.


생성자에 파라미터를 받는 클래스를 하나 더 확인해보자.

class Car:
    handle = 0 #멤버변수
    speed = 0
    def __init__(self,name,speed):
        self.name = name
        self.speed = speed
        
    def showData(self):
        km = '킬로미터' #지역변수
        msg = '속도' + str(self.speed)+km #<--!
        return msg
        
car1 = Car('tom','5')
car1.name
car1.__dict__ #dict타입으로 해당 인스턴스의 멤버들을 확인가능
  • ! : msg 구절을 보면, showData안에서가 아닌 멤버변수의 speed변수를 접근 하기 위해 self.speed를 사용했다.(this)

멤버변수를 즉시 추가 할수도있다. 추가된 멤버는 당연히 해당 인스턴스에서만 사용가능

car2 = Car('james',7)
car2.speed
car2.color = 2

원형클래스에게 직접 변수를 주고, 각 인스턴트 객체에서 aa라는 변수를 출력하려고 할때, 먼저 각각의 인스턴스 본인의 aa변수를 찾는다.
없다면 prototype 원형클래스의 aa변수에 접근하여 사용하고, 있다면 원형클래스까지 가지않고, 본인의 변수를 사용한다.

이러한 특성을 아래 코드에서 확인해보았다.

car1.speed = 19
car2.speed = 29

Car.speed = 300
#print
car1.speed #19
car2.speed #29
=========
Car.handle = 5
#print
car1.handle #5
car2.handle #5

먼저 각 car1,car2 speed변수에 임의의 값을 저장했다.
이 경우 원형클래스 Car.speed로 300이라는 값을 줘도, 각 인스턴스에게 먼저 주어진 값을 호출하게 된다.

만약 생성자에도 없는, 각각의 인스턴스에게 값이 할당되지 않은 상태인 handle과 같은 변수일때 원형클래스 Car.handle에 5라는 값을 주고 car1,car2 인스턴스의
handle을 출력해보자.

car1과 car2는 자신에게 할당된 handle이 없으므로 원형클래스에서 지정된 5라는 값을 가져온다.


self

self의 특성에 대해 잘 정리되어 있다. 클래스의 원리를 이해하려면 짚고 넘어가는 것이 좋다.


모듈, 클래스 멤버

모듈과 클래스의 차이, 전역/멤버/지역 변수의 범위를 확인해봤다.

kor = 100

def abc():
    print('함수')
#================
class MyClass:
    kor = 90
    
    def abc(self):
        print('abc메소드')
        
    def showData(self):
       # kor=80
        print(self.kor,' ',kor) # 멤버변수, 지역변수 출력. 
        self.abc() #클래스 멤버 호출 
        abc()  #클래스 밖 모듈 호출
        
my = MyClass()
my.showData() # 90  80

전역변수 kor 100 / 멤버변수 kor 90 / showData 지역변수 kor 80을
클래스 내 메소드에서 출력해보았다.

  • kor
    showData내 kor변수는 먼저 지역변수 kor을 찾아 출력한다. (80)
    만약 해당 지역변수가 없다면 전역변수를 찾아 출력한다. (100)

  • self.kor
    self.kor은 우선순위를 갖는다.
    my 해당 인스턴스의 kor > 원형클래스의 kor멤버

  • self.abc() : 클래스 멤버 호출

  • abc() : 클래스 밖 모듈 호출


다른 모듈의 멤버 참조(클래스)

모듈클래스

# 아래 클래스는 다른 모듈에서 재활용을 목적으로 작성

class Robot:
    name = '태권브이'
    energy = 100
    
    def attack(self):
        return '돌려차기'

메인클래스

# 다른 모듈의 멤버(클래스) 참조하기
from pack1basic.test25other import Robot

def main():
    print('뭔가를 하다가')
    robot = Robot()
    print('이름:' , robot.name)
    print('필살기:', robot.attack())
    robot2 = Robot #원형클래스의 주소만 받았으므로
    print('필살기2:',robot2.attack(robot2)) #메소드는 이렇게 사용
    robot2.name = '엔트맨' # 둘다 변경. robot2는 원형클래스이므로
    print(robot2.name,robot.name) 
    print(Robot.attack(Robot))
    
#보통 응용프로그램 작성시 메인함수에 아래 구문을 명시한다.
if __name__ == '__main__':
    main()

클래스 포함(상속)

  • 클래스 내에서 타 클래스의 인스턴스를 생성자에서 생성하면서,
    타 클래스를 클래스의 멤버로써 사용했다.

아래의 코드는 모듈로써 사용(포함)시킬 핸들클래스이다.

class PohamHandle:
    quantity = 0 #회전량
    
    def LeftTurn(self,quantity):
        self.quantity = quantity
        return '좌회전'
    
    def RightTurn(self,quantity):
        self.quantity = quantity
        return '우회전'

포함클래스를 이용하여 Car클래스를 작성했다.

생성자에서 PohamHandle()의 인스턴스를 생성하고, 아래 메소드들에서 사용했다.

class PohamCar:
    turnShowMessage = '정지'
    
    def __init__(self,ownerName):
        self.ownerName = ownerName
        self.handle = PohamHandle() #클래스의 포함관계!

    def Turnhandle(self,q):
        if q>0:
            self.turnShowMessage = self.handle.RightTurn(q)
        elif q<0:
            self.turnShowMessage = self.handle.LeftTurn(q)
        elif q == 0:
            self.turnShowMessage='직진'
            self.handle.quantity=0

이를 출력에 사용해보자.

if __name__ == '__main__':
    tom = PohamCar('tom')
    tom.Turnhandle(10)
    print(tom.ownerName + '의 회전량은 ' + tom.turnShowMessage + str(tom.handle.quantity))
    # tom의 회전량은 우회전10

tom이라는 인스턴스를 생성. 생성자에 이름을 주고, TurnHandle에 10을 줬다.
포함된 클래스(인스턴스)를 접근할땐 . 접근자를 2번 사용하여 사용한다.


이해를 위해 추가적인 냉장고 예제를 작성했다.

# 클래스의 포함 : 냉장고에 음식 넣기
class Frige:
    isOppened = False #냉장고 개폐여부
    foods = []
    
    def open(self):
        self.isOppened = True
        print('냉장고 문이 열림')
        #========포함사용========
    def put(self,thing):
        if self.isOppened:
            self.foods.append(thing) #클래스 포함(묶음형자료 사용)
            print('냉장고에 음식을 저장')
            self.list()
        else:
            print('냉장고 문이 닫혀있어 넣을 수 없음.')
    #=======================
    def close(self):
        self.isOppened=False
        print('냉장고 문 닫음')
    
    def list(self): #냉장고 내용물 확인 
        for food in self.foods:
            print('-',food.irum,food.expiry_date) #이름과 유통기한

포함관계에 사용될 FoodData 클래스도 만들었다.
생성자에서 이름과 유통기한을 입력받는다

class FoodData: #포함될 음식클래스
    def __init__(self,irum,expiry_date):
        self.irum = irum
        self.expiry_date = expiry_date

포함클래스의 사용:

f1.open()
f1.put(apple) #Frige형 객체에 FoodData형 객체를 인자로
f1.close()

f1 인스턴스 객체에 apple객체를 넣는다.
f1 put()메소드의 thing 파라미터로 받았다.(apple(foodData)의 주소값을 넘김)
넘어온 주소값을 리스트에 담았고,이를 list메소드에서 for문 속 . 접근자로 객체에 접근하게 된것.

냉장고가 열려있는지에 대한 여부를 확인.
self.foods.append로 클래스 멤버리스트인 foods[] 에 담고, 출력한다.

0개의 댓글