Class, Decorator

LeeKyoungChang·2021년 11월 18일
0
post-thumbnail

Class & Decorator

🕹1. 클래스

데이터를 표현하는 속성(attribute)와 행위를 표현하는 메서드(method)를 포함하는 논리적인 컨테이너

객체

컴퓨터 시스템에서 다양한 기능을 수행하도록 속성메소드를 가진 요소

type() : 객체의 자료형을 반환

id() : 객체의 id를 반환

 

n + 100 == n.__add__(100) : n 객체와 정수 100의 합을 연산한다.

 

클래스의 개념

  • 클래스의 모양과 생성
class 클래스명 
	# 이 부분에 관련 코드 구현

속성 (변수) : 클래스/인스턴스 변수 (attribute)

기능 (클래스 안에서 구현된 함수) : 메서드(method)

class Car:
    # 자동차의 필드
    색상 = ""
    현재_속도 = 0
    
    # 자동차의 메서드
    def upSpeed(증가할_속도량):
        # 현재 속도에서 증가할_속도량만큼 속도를 올리는 코드
        
    def downSpeed(감소할_속도량):
        # 현재 속도에서 감소할_속도량만큼 속도를 내리는 코드

클래스 변수 : 클래스 정의에서 메서드 밖에 존재하는 변수, 해당 클래스를 사용하는 모두에게 공용으로 사용되는 변수, 클래스명. 변수명

인스턴스 변수 : 각 객체 인스턴스마다 별도로 존재, 클래스 정의에서 메서드 안에서 사용되면서 self.변수명처럼 사용, 각 객체별로 서로 다른 값을 갖는 변수

  • 클래스 내부 : self.
  • 클래스 외부 : 객체변수.인스턴스변수

메서드

  • 함수의 인자중에 첫 번째는 반드시 self가 있어야 한다.
  • self : 클래스 자신을 가리키는 것, 메서드 호출시 파이썬이 내부적으로 클래스 자체의 참조를 넘기게 된다.

 

클래스 사용 순서

1단계

  • 클래스 선언
  • class 클래스명:

2 단계

  • 인스턴스 생성
  • 인스턴스 = 클래스명()

3단계

  • 필드나 메서드 사용
  • 인스턴스. 필드명 = 값
  • 인스턴스.메서드()
class Car: # 1단계
    color = ''
    def upSpeed(self.value):
        ....
        
myCar1 = Car() # 2단계
myCar1.color = '빨강' # 3단계
myCar1.upSpeed(30) 	 # 3단계

 

🔮2. 생성자

생성자의 개념 : 인스턴스를 생성하면서 필드값을 초기화시키는 함수

생성자의 기본

  • __init__()
class 클래스명:
    def __init__(self):
        # 이 부분에 초기화할 코드 입력

 

클래스 내부에 선언된 함수 : 메소드 or 멤버 함수

인스턴스들이 개별적으로 가지는 속성을 저장하는 변수 : 인스턴스 변수 or 멤버 변수 or 필드

  • __str__()
class Cat:
    def __init__(self, name, color):
        self.name = name
        self.color = color
        
    def __str__(self):		# Cat 객체의 문자열  표현 방식
        return 'Cat(name='+self.name+', color='+self.color+')'
    
nabi = Cat('나비', '검정색')

print(nabi)

# 결과
# Cat(name=나비, color=검정색)

 

클래스 변수 : 클래스 안에 공간이 할당된 변수, 여러 인스턴스가 클래스 변수 공간 함께 사용

class Car:
    color = "" #인스턴스 변수
    speed = 0 # 인스턴스 변수
    count = 0 # 클래스 변수
    
    def printMessage():
        print("시험 출력")
        
    def __init__(self):
        self.speed = 0
        Car.count += 1
        
# 변수 선언
myCar1, myCar2 = None, None

# 메인 코드 부분
myCar1 = Car()
myCar1.speed = 30
print("%dkm, %d"%(myCar1.speed, Car.count))


myCar2 = Car()
myCar2.speed = 60
print("%dkm, %d"%(myCar2.speed, myCar2.count))

# 결과
# 30km, 1
# 60km, 2

 

🛶3. 클래스의 상속

클래스의 상속(Inheritance)

: 기존 클래스에 있는 필드와 메서드를 그대로 물려받는 새로운 클래스를 만드는 것

public, protected, private등의 접근 제한자를 갖지 않는다.

Python 클래스는 기본적으로 모든 멤버가 public이라고 할 수 있다.

  • 내부적으로만 사용하는 변수 혹은 메서드는 그 이름 앞에 하나의 밑줄(_)을 붙인다.

  • 특정 변수명이나 메서드를 private으로 만들어야 한다면 두개의 밑줄(__)을 이름 앞에 붙이면 된다.

 

상속의 개념

  • 공통된 내용을 자동차 클래스로부터 상속을 받음으로써 일관되고 효율적인 프로그래밍 가능
  • 상위 클래스를 슈퍼 클래스 또는 부모 클래스, 하위 승용차는 서브 클래스 또는 자식 클래스
class 자식클래스 이름(부모클래스이름):
    def __init__(self, 속성값1, 속성값2):
        super(자식클래스이름,self).__init__()
        # 자식클래스의 초기화 코드

# ex)
class Person:
    def __init__(self):
        print('Person __init__')
        self.hello = 'Hello.'
        
class Student(Person)
	def __init__(self):
        print('Student __init__')
        super().__init__() # super으로 부모 클래스의 __init__메서드 호출
        self.school = 'Python Coding'

james = Student()
print(james.school)
print(james.hello)

# 결과
# Student __init__
# Person __init__
# Python Coding
# Hello.


# 파생 클래스에서 __init__ 메서드를 생략한다면 부모 클래스의 __init__이 자동으로 호출되므로 super()는 사용하지 않아도 된다.

class Person:
    def __init__(self):
        print('Person __init__')
        self.hello = 'Hello.'
        
class Student(Person)
	pass

james = Student()
print(james.hello)


# 결과
# Person __init__
# Hello.

 

메서드 오버라이딩

상위 클래스의 메서드를 서브 클래스에서 재정의

class Car:
    def upSeed(self, value):
        ~
        
class Sedan(Car):
    def upSeed(self, value):
        ~

 

트럭 --> 현재 속도(슈퍼 클래스) : 200
승용차 --> 현재 속도(서브 클래스) : 150
소나타 --> 현재 속도(서브 클래스) : 150
## 클래스 선언 부분
class Car :
    speed = 0
    def upSpeed(self, value):
        self.speed += value
        
        print("현재 속도(슈퍼 클래스) : %d"%self.speed)
        
class Sedan(Car):
    def upSpeed(self,value):
        self.speed += value
        
        if self.speed > 150:
            self.speed = 150
            
        print("현재 속도(서브 클래스) : %d"%self.speed)
        
class Sonata(Sedan):
    pass

class Truck(Car):
    pass


## 변수 선언 부분
sedan1, truck1 = None, None

## 메인 코드 부분
truck1 = Truck()
sedan1 = Sedan()
sonata1 = Sonata()

print("트럭 --> ", end = "")
truck1.upSpeed(200)

print("승용차 --> ",end = "")
sedan1.upSpeed(200)

print("소나타 --> ",end = "")
sonata1.upSpeed(300)

 

super() 함수 : 서브 클래스에서 메서드 오버라이딩을 할 때, 슈퍼 클래스의 메서드나 속성을 사용해야 하는 경우, super() 메서드를 사용하면 된다.

class Car:    value = '슈퍼 값'    def carMethod(self):        print('슈퍼 클래스 메서드 실행 ~ ')        class Sedan(Car):    def carMethod(self):        super().carMethod # Car 클래스의 carMethod()가 실행        print(super().value) # Car 클래스의 value가 출력된다.        sedan1 = Sedan()sedan1.carMethod()

 

🔒4. 캡슐화

캡슐화

  • 메소드와 변수를 외부에서 함부로 조작하는 것을 제한
  • 데이터를 보호
  • 우연히 값이 변경되는 것을 방지
  • 클래스의 속성을 외부에서 접근할 때 오류를 줄일 수 있다.

setXXX로 시작하는 메소드 : 세터(setter)

getXXX로 시작하는 메소드 : 게터(getter)

더블 스코어 변수명(__변수) : 선언된 클래스 안에서만 해당 이름으로 사용 가능하다.

 

🎩5. 심화 내용

객체의 identity operator

is 연산자 : 두 인스턴스가 같으면 True를 반환하며, 그렇지 않으면 False를 반환

is not : 반대 역할을 한다.

== : 두 인스턴스의 속성 값 즉 인스턴스 변수 값이 서로 일치하는지 확인하는데 사용

같은 문자를 할당한 경우, 같은 저장위치를 참조한다.

 

__del__()메서드 : 소멸자(Destructor), 생성자와 반대로 인스턴스 삭제할 때 자동 호출

__repr__()메서드 : 인스턴스를 print() 문으로 출력할 때 실행

__add__()메서드 : 인스턴스 사이에 덧셈 작업이 일어날 때 실행되는 메서드, 인스턴스 사이의 덧셈 작업 가능

비교 메서드

  • __it__() : <
  • __le__() : <=
  • __gt__() : >
  • __ge__() : >=
  • __eq__() : ==
  • __ne__() : !=

 

추상 메서드(abstract method)

서브 클래스에서 메서드를 오버라이딩 : 슈퍼 클래스에서는 빈 껍질의 메서드만 만들어 놓고 내용은 pass로 채운다.

class SuperClass:
    def method(self):
        pass
    
class SubClass1(SuperClass):
    def method(self):
        print('SubClass -> 오버라이딩')

 

멀티 스레드

프로그램 하나에서 여러 개를 동시에 처리할 수 있도록 제공하는 기능

스레드

import threading

class Calculator :
    number = 0
    def __init__(self, number) :
    	self.number = number
        
    def runCalc(self) :
        hap = 0
        for i in range(0, self.number+1) :
        	hap += i
        print("1+2+3+.....+", self.number, "=", hap)


calc1 = Calculator(1000)
calc2 = Calculator(100000)
calc3 = Calculator(10000000)

th1 = threading.Thread(target = calc1.runCalc)
th2 = threading.Thread(target = calc2.runCalc)
th3 = threading.Thread(target = calc3.runCalc)

th1.start()
th2.start()
th3.start()

 

🦺6. static method & class method

@staticmethod

  • 정적 메서드
  • self를 지정하지 않는다.
class 클래스이름:
    @staticmethod
    def 메서드(매개변수1, 매개변수2)
    	코드

@ : 데코레이터, 메서드(함수)에 추가 기능을 구현할 때 사용한다.

  • 정적 메서드를 호출할 때는 클래스에서 바로 메서드를 호출하면 된다.
클래스이름.메서드(변수1, 변수2)
  • 정적 메서드는 self를 받지 않으므로 인스턴스 속성에는 접근할 수 없다.
  • 정적 메서드는 인스턴스 속성, 인스턴스 메서드가 필요 없을 때 사용한다.
  • 정적 메서드는 인스턴스의 상태를 변화시키지 않는 메서드를 만들 때 사용한다.

자료

@classmethod

  • 클래스 메서드
  • 첫 번째 매개변수에 cls를 지정해야 한다. (cls : class)
class 클래스이름:
    @classmethod
    def 메서드(cls, 매개변수1, 매개변수2):
        코드
class Person:    count = 0 # 클래스 속성        def __init__(self):        Person.count += 1# 인스턴스가 만들어질 때마다 숫자를 세야 하므로 __init__ 메서드에서 클래스 속성 count에 1을 더해준다. 클래스 속성에 접근한다는 것을 명확하게 하기 위해 Person.count와 같이 만들어준다.    @classmethod    def print_count(cls):        print('{0}명 생성되었습니다.'.format(cls.count))# 이제 @classmethod를 붙여서 클래스 메서드를 만든다. 클래스 메서드는 첫 번째 매개변수가 cls인데 여기에는 현재 클래스가 들어온다. 따라서 cls.count처럼 cls로 클래스 속성 count에 접근할 수 있다.james = Person()maria = Person()# Person으로 인스턴스를 두 개 만들었으므로 print_count를 호출해보면 '2명 생성되었습니다.'가 출력된다. 물론 print_count는 클래스 메서드이므로 Person.print_count()처럼 클래스로 호출해준다.Person.print_count()   # 2명 생성되었습니다.

@classmethod(클래스 메서드)

  • 클래스 메서드는 정적메서드처럼 인스턴스 없이 호출할 수 있다.
  • 클래스 메서드는 메서드 안에서 클래스 속성, 클래스 메서드에 접근해야 할 때 사용한다.
  • cls를 사용하면 메서드 안에서 현재 클래스의 인스턴스를 만들 수도 있다.
  • cls는 클래스, cls() == Person()

 

👑7. abstract class

abstract class

  • 추상 클래스는 메서드의 목록만 가진 클래스

  • 상속받는 클래스에서 메서드 구현을 강제하기 위해 사용

  • 추상 클래스를 만들려면 import로 abc 모듈을 가져와야 한다.

  • 추상 클래스를 상속받았다면 @abstractmethod가 붙은 추상 메서드를 모두 구현해야 한다.

from abc import *class 추상클래스이름(metaclass=ABCMeta):    @abstractmethod    def 메서드이름(self):        코드
from abc import *

class StudentBase(metaclass=ABCMeta):
    @abstractmethod
    def study(self):
        pass
    
    @abstractmethod
    def go_to_school(self):
        pass
    
class Student(StudentBase):
    def study(self):
        print('공부하기')
        
james = Student()
james.study()

# 결과
# Traceback 오류 발생
# 추상 클래스 StudentBase에서는 추상 메서드로 study와 go_to_school을 정의했다.
# 하지만, StudentBase를 상속받은 Student에서는 study 메서드만 구현하고, go_to_school 메서드는 구현하지 않았으므로 에러가 발생한다.
# 추상 클래스를 상속받았다면 @abstractmethod가 붙은 추상 메서드를 모두 구현해야 한다.
  • 추상 클래스의 추상 메서드를 모두 구현했는지 확인하는 시점은 파생 클래스가 인스턴스를 만들 때이다. (생성자 호출하는 시점)

추상 메서드를 빈 메서드로 만드는 이유

  • 추상 클래스는 인스턴스로 만들 수가 없다는 점이다. (만들 시 에러 발생)

  • 추상 메서드를 만들 때 pass만 넣어서 빈 메서드로 만든다.

추상 클래스는 인스턴스로 만들 때는 사용하지 않으며 오로지 상속에만 사용한다.

파생 클래스에서 반드시 구현해야 할 메서드를 정해 줄 때 사용한다.

 

🎱8. Decorator

장식하는 도구이다.

@로 시작하는 것들이 데코레이터이다.

데코레이터 만들기

  • 데코레이터는 함수를 수정하지 않은 상태에서 추가 기능을 구현할 때 사용한다.
def trace(func):
    def wrapper():
        print(func.__name__, '함수 시작')
        func()
        print(func.name__name__, '함수 끝')
    return wrapper

# 호출할 함수를 매개변수로 받음
# 호출할 함수를 감싸는 함수
# __name__으로 함수 이름 출력
# 매개변수로 받은 함수를 호출
# wrapper 함수 반환

@trace
def hello():
    print('hello')

@trace
def world():
    print('world')
    
hello()
world()

# 결과
# hello 함수 시작
# hello
# hello 함수 끝
# world 함수 시작
# world
# world 함수 끝
@데코레이터
def 함수이름():
    코드

trace

@데코레이터(인수)
def 함수이름():
    코드

Decorator 추가 공부하기

 

 


참고 자료

  • python 수업 자료, Class Decorator
profile
"야, (오류 만났어?) 너두 (해결) 할 수 있어"

0개의 댓글

관련 채용 정보