* 정적 메소드와 클래스 메소드


인스턴스 메소드는 인스턴스(객체)에 속한 메소드를 말한다.

메소드는 클래스에 정의하는데 인스턴스에 속하다니 무슨말인가 ?

여기서 인스턴스에 속한다 라는 표현은 인스턴스를 통해 호출가능하다 라는 뜻이다. 그럼 클래스에 속한(클래스를 통해 호출 가능한) 메소드도 있을 것이다. 이 두개의 메소드가

정적 메소드와 클래스 메소드이다.


정적메소드는 @staticmethod 데코리에터로 수식하며, self매개변수 없이 정의한다. 


class 클래스이름 :

@staticmethod

def 메소드이름( 매개변수 ):

pass


self매개변수는 사용하지 않는다.


ex) 정적메소드

1
2
3
4
class Calculator:
    @staticmethod
    def plus(a,b):
        return a+b

cs

인스턴스를 통해서 접근이 가능하지만, 보통 클래스를 통해 호출한다.


obj = Calculator()

obj.plus(3,5)<-- 대게는 이렇게 인스턴스를 만들어 호출하지 않는다.

a = Calculator.plus(3,4) <-- 이렇게 호출하는 것이 보통이다.

ex) 사용 예

1
2
3
4
5
6
7
8
9
10
11
12
class Calculator:
    @staticmethod
    def plus(a,b):
        return a+b
 
    @staticmethod
    def minus(a,b):
        return a-b
 
print("{} + {} = {}".format(7,4,Calculator.plus(7,4)))
print("{} - {} = {}".format(7,4,Calculator.minus(7,4)))
 

cs

출력결과

7 + 4 = 11
7 - 4 = 3


정적 메소드는 self매개변수를 전달받을 방법이 없으므로 객체/인스턴스의 변수에 접근할 수 없다.



* 클래스 메소드

클래스를 통하여 호출한다.

인스턴스를 통해서도 호출이 가능하다.

첫 매개변수로 클래스 객체를 전달한다.

관용적으로 첫 매개변수를 cls로 사용한다.

클래스 메서드는 @classmethod장식자에 의해서 선언된다.


class 클래스이름 :

#...


@classmethod

def 메소드이름(cls):

pass


매개변수로 self가 인스턴스를 나타냈다면 cls는 클래스를 나타낸다.


ex) 클래스 메소드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Calc:
    var1 = 1
    var2 = 2
 
    def InstanceAdder(self):
        print("인스턴스 메소드:",self.var1 + self.var2)
 
    @classmethod
    def classMethod(cls):
        print("클래스메소드:",cls.var1 + cls.var2)
       #print("인스턴스변수사용:",self.var1 + self.var2)     에러
 
 
 
 
#Calc.InstanceAdder()   #인스턴스메소드이기 때문에 에러
Calc.classMethod()     #클래스.메소드 접근가능
mycal = Calc()
mycal.InstanceAdder()
mycal.classMethod()    # 인스턴스도 클래스메소드 사용가능
 

cs

출력결과

클래스메소드: 3

인스턴스 메소드: 3

클래스메소드: 3

11행 : 인스턴스변수 사용 self는 사용할 수 없다.

16행 : Calc클래스의 instanceAddr(self)메소드는 인스턴스메소드이기 때문에 사용할 수 없다.



* 공개, 비공개 속성(public & private)


클래스 안에서만 접근가능한 멤버를 private멤버라고 한다.

클래스 안과 밖에서 모두 접근 가능한 멤버를 public멤버라고 한다.

메서드에도 public, private 속성 적용이 가능하다.

프라이빗 속성은 멤버 혹은 메소드 앞에 __ 를 붙인다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class tes:
    def __init__(self):
        self.public="public"
        self.__private = "private"
 
    def internal(self):
        print(self.public)
        print(self.__private)
 
 
>>> a=tes()
 
>>> a.internal()
public
private
>>> print(a.public)
public
>>> print(a.__private)
Traceback (most recent call last):
  File "<pyshell#4>", line 1in <module>
    print(a.__private)
AttributeError: 'tes' object has no attribute '__private'

cs


11행 인스턴스를 만들어주고, 13행에서 실행을 하고 있다. 같은 클래스의 멤버끼리 자유롭게 접근이 된다.

하지만 18행은 __private 데이터 속성이 아예 존재하지 않는 것처럼 보이기 때문에 에러가 난다.


* 상속 *

클래스는 상속을 통해서 부모클래스의 속성 및 기능을 물려받는다.

상속에 관련된 클래스는 부모(기반,상위) 클래스와 자식(파생,하위)클래스로 구분된다.

자식클래스는 부모클래스의 변수, 메소드, 생성자등을 이용할 수 있다.

자식클래스는 상속받은 기능외에 자신만의 기능을 추가할 수 있다.

자식클래스는 상속받은 기능을 수정할 수 있다. (메소드 오버라이딩,재정의) => 다형성(그림판)


class 기반(부모)클래스:

#멤버 정의


class 파생(자식)클래스(기반(부모)클래스):

# 아무 멤버를 정의하지 않아도 기반 클래스의 모든 것을 물려받아 가지게 된다.

# 단 프라이빗 멤버는 제외다.(__로 시작하는 멤버)


ex) 상속

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Animal:
    def __init__(self,name,age):
        self.name = name
        self.age = age
 
    def printInfo(self):
        print("이름:",self.name)
        print("나이:", self.age)
 
    def play(self):
        print("놀기")
 
    def parentMethod(self):
        print("__prarentMethod__")
 
 
class Dog(Animal):
    pass
 
>>> mydog = Dog("해피",7)
>>> mydog.printInfo()
이름: 해피 나이: 7
>>> mydog.play()
놀기
 
 

cs

19행부터 출력결과이다.

Dog클래스가 스스로 구현한 메소드는 없지만, Animal로부터 상속받은 메소드는 가지고 있다.


super

부모클래스의 객체 역할을 하는 프록시(Proxy)를 반환하는 내장 함수이다. 

ex)

1
2
3
4
5
6
7
8
class A:
    def __init__(self):
        print("hh")
 
        
class B(A):
    def __init__(self):
        super().__init__()

cs

8행 : A.__init()과 같은 결과

즉, 자식클래스의 메소드 안에서 부모클래스의 메소드를 호출할 때 !

super를 쓰면 기반 클래스가 다른 클래스로 교체되거나 수정되어도 파생 클래스가 받는 영향을 최소화 할 수 있다.


오버라이딩

기반(부모) 클래스로부터 상속받은 메소드를 다시 정의한다.(재정의)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Animal:
    def __init__(self,name,age):
        self.name = name
        self.age = age
 
    def printInfo(self):
        print("이름:",self.name)
        print("나이:", self.age)
 
    def play(self):
        print("놀기")
 
    def parentMethod(self):
        print("__parentMethod__")
 
class Dog(Animal):
    def play(self): # 메소드 오버라이딩(재정의)
        super().play()  # 부모의 메소드 호출
        print("신나게 놀기") # 재정의
 
    def callerMethod(self):
        super().parentMethod()  #부모의 메소드 호출
 
 
>>> mydog = Dog("해피",7)
 
>>> mydog.printInfo()
이름: 해피
나이: 7
>>> mydog.play()
놀기 신나게 놀기

>>> mydog.callerMethod()
__parentMethod__

 
 
 
 

cs

12~14행 : 오버라이딩을 하면서, 부모의 메소드를 활용할 수 있는 방법이다.!


다중상속


자식 하나가 여러부모로부터 상속을 받는 것!


1
2
3
4
5
6
7
8
9
10
11
class A:
    pass
 
class B:
    pass
 
class C:
    pass
 
class D(A,B,C): #다중상속
    pass

cs


클래스 D가 A,B,C로부터 상속을 받고있다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A:
    def method(self):
        print("A")
 
class B(A):             # 부모가 A
    def method(self):
        print("B")
 
class C(A):             # 부모가 A
    def method(self):
        print("C")
 
class D(B,C):           # 부모가 B,C
    pass

cs


위의 예제는 일명 다이아몬드상속?이라고도 한다.

A        A 부모클래스

   B     C     B,C는 A가 부모클래스

D        D는 B,C가 부모클래스


A는 method()라는 메소드를 구현하고있고, B와 C는 A로부터 상속을 받았다. 하지만 B와 C는 method()메소드를 재정의 하고 있다.

이 때 D는 B와 C중 누구의 method()를 물려받을 것인가 ? 그 정답은 B이다.

부모클래스의 목록에서 가장 앞에 있는 클래스의 메소드를 물려주고 있기 때문이다.


* 추상클래스

클래스 내에 한개 이상의 추상메소드가 있어서 인스턴스 객체가 생성할 수 없는 클래스

하위클래스가 반드시 구현해야할 메소드를 가지고 있다.

abc(Abstract Base Classes)모듈을 import하고 AbC Meta클래스를 지정한 뒤, @abstractmethod 장식자를 이용하여서 추상메소드를 만든다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from abc import *
class StudentBase(metaclass=ABCMeta):
 
    @abstractclassmethod    #추상메소드
    def study(self):
        pass
    @abstractclassmethod
    def goToLibrary(self):
        pass
 
class Student1(StudentBase):
    def study(self):        # 추상메소드를 오버라이딩
        print("공부를한다.")
    def goToLibrary(self):  # 추상메소드를 오버라이딩
        print("도서관에 간다.")
 
class Student2(StudentBase):
    pass
 
 
std1=Student1()
std1.study()
std1.goToLibrary()
#std2=Student2()    # goToLibrary메소드를 재정의 하지 않아서 에러
 
#stB = StudentBase() 추상클래스는 인스턴스를 만들지 않는다.
 
 

cs

4행, 7행 : 추상메소드를 정의하고 있다.
12, 14행 : 자식클래스가 부모클래스를 재정의 하고 있다.
24행 : Student2가 부모클래스의 추상메소드를 재정의 하지 않아서 에러가 발생한다.!
26행 : 추상클래스는 인스턴스를 만들지 않는다.

'programming > Python' 카테고리의 다른 글

Python // 예외처리  (0) 2017.12.07
Python // 객체와 클래스  (0) 2017.12.01
Python // 모듈과 패키지  (0) 2017.11.30
Python // 함수  (0) 2017.11.27
Python // 반복문  (0) 2017.11.26

+ Recent posts