λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🐍 Algorithm/Python

[Python] class, instance 속성, class 상속과 μƒμ„±μž

by Danna 2020. 12. 7.
728x90
728x90

C++/Javaμ—μ„œμ˜ Class와 차이점

  • 클래슀 instance μƒμ„±μ‹œ new ν‚€μ›Œλ“œκ°€ μ—†λ‹€. ν•¨μˆ˜ν˜ΈμΆœκ³Ό 같은 방식을 μ‚¬μš©ν•œλ‹€.
  • λ©”μ†Œλ“œ μ˜€λ²„λ‘œλ”©μ΄ μ—†λ‹€.
    • λ©”μ†Œλ“œ μ˜€λ²„λ‘œλ”©: ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ—μ„œ λ©”μ†Œλ“œ 이름은 κ°™κ³ , 인자λ₯Ό λ‹€λ₯΄κ²Œ ν•˜λŠ” ν˜•νƒœ
    • κ°€λ³€μΈμžλ₯Ό ν™œμš©ν•΄ μ‚¬μš©ν•œλ‹€. κ°€λ³€μΈμžλŠ” 인자 μ•žμ— *λ₯Ό λΆ™μ—¬μ„œ μ‚¬μš© (ν•¨μˆ˜μ°Έκ³ )
    • def add(self, *num)
  • class 속성과 instance 속성을 κ΅¬λΆ„ν•΄μ„œ μ •μ˜ν•΄μ€˜μ•Όν•œλ‹€
  • C#, JavaλŠ” 닀쀑상속이 λΆˆκ°€λŠ₯ν•˜μ§€λ§Œ python, c++은 닀쀑상속이 κ°€λŠ₯ν•˜λ‹€.

class 속성과 instance 속성 κ΅¬λΆ„ν•˜κΈ°

class 속성은 classλ₯Ό importν•œ ν›„ μ‚¬μš©ν•  수 μžˆλ‹€.

  • class λ³€μˆ˜λŠ” class λ‚΄λΆ€μ—μ„œ μ •μ˜ν•΄μ€€λ‹€.
  • class method μ •μ˜μ‹œ @classmethod λ°μ½”λ ˆμ΄ν„°λ₯Ό ν‘œμ‹œν•΄μ€€λ‹€.
  • class methodλŠ” class μ†μ„±μž„μ„ μ˜λ―Έν•˜λŠ” clsλ₯Ό 첫번째 λ§€κ°œλ³€μˆ˜λ‘œ λ°›λŠ”λ‹€. (λ‹€λ₯Έ 이름도 κ°€λŠ₯ν•˜λ‹€.)

instance 속성은 class의 instanceλ₯Ό 생성할 λ•Œ μƒμ„±λ˜λ©°, 각 instanceμ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

  • instance λ³€μˆ˜λŠ” μƒμ„±μž 역할을 ν•˜λŠ” __init__ ν•¨μˆ˜μ—μ„œ μ •μ˜ν•΄μ€€λ‹€.
  • instance methodλŠ” instance μ†μ„±μž„μ„ μ˜λ―Έν•˜λŠ” selfλ₯Ό 첫번째 λ§€κ°œλ³€μˆ˜λ‘œ λ°›λŠ”λ‹€.

def __init__(self, argument) λŠ” C++μ—μ„œμ˜ μƒμ„±μžμ™€ κ°™λ‹€.

  • μΌλ°˜μ μœΌλ‘œλŠ” __init__ν•¨μˆ˜λ§Œ μ˜€λ²„λΌμ΄λ”©ν•΄μ„œ instance μ΄ˆκΈ°ν™”μ— μ΄μš©ν•œλ‹€.
  • μžμ„ΈνžˆλŠ” instance μƒμ„±μ‹œ __new__ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄ instance 생성할당을 ν•œλ‹€. __new__ ν•¨μˆ˜κ°€ __init__ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³ , instanceμ—μ„œ μ‚¬μš©ν•  μ΄ˆκΈ°κ°’λ“€μ„ μ΄ˆκΈ°ν™”ν•œλ‹€.

class, instance 속성을 κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ simpleClass.py 에 class Cλ₯Ό μ •μ˜ν•˜κ³ , μ»€λ§¨λ“œλΌμΈμ—μ„œ class C, instance f, g의 속성듀을 ν™•μΈν•œλ‹€.

# simpleClass.py
class C:
        class_attr = [] # class 속성

        def __init__(self):
                self.instance_attr = [] # instance 속성

        def add_instance_attr(self, number): # instance method
                self.instance_attr.append(number)

        @classmethod
        def add_class_attr(cls, number): # class method
                C.class_attr.append(number)

class 속성 ν™•μΈν•˜κΈ°

>>> from simpleClass import C
>>> C.class_attr # 클래슀 속성
[]
>>> C.add_class_attr(7) # 클래슀 λ©”μ†Œλ“œ
>>> C.class_attr
[7]
>>> C.add_instance_attr(5) # instance methodλ₯Ό 뢈러올 경우 TypeErrorκ°€ λ°œμƒν•œλ‹€.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method add_instance_attr() must be called with C instance as first argument (got int instance instead)

instance 속성 ν™•μΈν•˜κΈ°

>>> f = C()
>>> g = C()
>>> f.add_instance_attr(5)
>>> f.add_class_attr(5) # instanceλŠ” class ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
>>> print f.instance_attr, f.class_attr # class_attr은 κ³΅μœ λœλ‹€.
[5] [7, 5]
>>> g.add_instance_attr(3)
>>> g.add_class_attr(3)
>>> print g.instance_attr, g.class_attr
[3] [7, 5, 3]

 

Class 상속

상속은 Parent class의 λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ 좔가적인 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€. μžμ‹ 클래슀의 instance μƒμ„±μ‹œ 상속받은 λΆ€λͺ¨ν΄λž˜μŠ€μ˜ class λ³€μˆ˜, class methodλŠ” μžμ‹ 클래슀의 instanceμ—μ„œ λ°”λ‘œ μ ‘κ·Ό κ°€λŠ₯ν•˜λ‹€. μ΄λŠ” λΆ€λͺ¨ 클래슀의 class 속성과 같은 값이닀.

 

μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό λ§Œλ“€μ§€ μ•Šμ€ κ²½μš°μ™€ μƒˆλ‘œ λ§Œλ“€ κ²½μš°μ— 차이가 λ°œμƒν•œλ‹€. μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό λ§Œλ“€μ§€ μ•Šμ€ 경우, μžμ‹ 클래슀의 instance μƒμ„±μ‹œ λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ ν˜ΈμΆœν•œλ‹€.

 

μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό μƒˆλ‘œ λ§Œλ“  경우, λΆ€λͺ¨ 클래슀의 μƒμ„±μžλŠ” μžλ™μœΌλ‘œ ν˜ΈμΆœλ˜μ§€ μ•ŠλŠ”λ‹€. λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜κΈ° μœ„ν•΄μ„œλŠ” super() ν•¨μˆ˜λ₯Ό ν†΅ν•΄μ„œ ν˜ΈμΆœν•˜κ±°λ‚˜, λΆ€λͺ¨ 클래슀λͺ…을 μ΄μš©ν•΄ 직접 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€. 두 ν•¨μˆ˜μ˜ μ°¨μ΄λŠ” μ•„λž˜μ™€ κ°™λ‹€.

  • Parent.__init__(self)방식은 λΆ€λͺ¨ν΄λž˜μŠ€μ˜ μƒμ„±μž λ©”μ†Œλ“œλ₯Ό 직접 μ°Έκ³ ν•˜κΈ° λ•Œλ¬Έμ—, λΆ€λͺ¨ν΄λž˜μŠ€κ°€ 변경될 경우 Child(Parent), Parent.function() λ‘˜ λ‹€ λ³€κ²½ν•΄μ€˜μ•Όν•œλ‹€.
  • super(Child, self).__init__방식은 λΆ€λͺ¨ν΄λž˜μŠ€λ₯Ό μžλ™μœΌλ‘œ μΈμ‹ν•˜λ―€λ‘œ, λΆ€λͺ¨ 클래슀λ₯Ό λ³€κ²½ν•  경우, Child(Parent) λΆ€λΆ„λ§Œ λ³€κ²½ν•΄μ£Όλ©΄ λœλ‹€.
  • μƒμ„±μž μ΄ˆκΈ°ν™”μ‹œ super()ν•¨μˆ˜λŠ” μžλ™μœΌλ‘œ selfκ°€ μ „λ‹¬λ˜μ§€λ§Œ, 직접 ν˜ΈμΆœμ‹œμ—λŠ” self도 μ „λ‹¬ν•΄μ•Όν•œλ‹€.

μ•„λž˜ μ˜ˆμ‹œλŠ” μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό μƒˆλ‘œ λ§Œλ“€κ³ , λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λŠ” μ˜ˆμ œμ΄λ‹€.

κ³΅ν†΅μ μœΌλ‘œ 상속받은 class λ³€μˆ˜, class ν•¨μˆ˜, instance ν•¨μˆ˜λŠ” μ‚¬μš©κ°€λŠ₯ν•˜λ‹€.

  • μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό λ§Œλ“€μ§€ μ•Šμ„ 경우
    • μžμ‹ 클래슀 instance인 child의 instance μ†μ„±μœΌλ‘œ instance_attr이 μƒμ„±λ˜μ–΄ μ‚¬μš©κ°€λŠ₯ν•˜λ‹€.
  • μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό λ§Œλ“€κ³  λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šμ„ 경우
    • μžμ‹ 클래슀 instance인 child의 instance μ†μ„±μœΌλ‘œ child_instance_attr만 μƒμ„±λœλ‹€.
    • λΆ€λͺ¨ 클래슀 instance μƒμ„±μžκ°€ ν˜ΈμΆœλ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— instance_attr은 μƒμ„±λ˜μ§€ μ•ŠλŠ”λ‹€.
  • μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό λ§Œλ“€κ³  λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•œ 경우 (μ•„λž˜ μ˜ˆμ‹œμ™€ κ°™λ‹€)
    • μžμ‹ 클래슀 instance인 child의 instance μ†μ„±μœΌλ‘œ child_instance_attr, instance_attr이 μƒμ„±λœλ‹€.
class Parent(object):
    class_attr = []

    def __init__(self):
        self.instance_attr = []

    def add_instance_attr(self, number):
        print("parent instance function")
        self.instance_attr.append(number)

    @classmethod
    def add_class_attr(cls, number):
        Parent.class_attr.append(number)

class Child(Parent):
    child_attr = []

    def __init__(self):
    super(Child, self).__init__() # Parent.__init__(self) 와 κ°™λ‹€.
        self.child_instance_attr = []

    def add_child_instance_attr(self, number):
        self.child_instance_attr.append(number)

    @classmethod
    def add_child_class_attr(cls, number):
        Child.child_attr.append(number)
>>> child = Child()
>>> child.add_child_class_attr(1)
>>> child.add_child_instance_attr(2)
>>> child.add_class_attr(3) # parent class function

>>> print "child class attr:", child.child_attr
child class attr: [1] [1]

>>> print "child instance attr:", child.child_instance_attr
child instance attr: [2]

>>> print "parent class attr:", child.class_attr, Parent.class_attr # parent class var
parent class attr: [3] [3]

>>> child.add_instance_attr(4) # parent instance function

>>> print "parent instance attr:", child.instance_attr
parent instance function
parent instance attr: [4]

>>> print child.__dict__
{'instance_attr': [4], 'child_instance_attr': [2]}

닀쀑상속

Python μ—μ„œλŠ” 닀쀑 상속을 μ§€μ›ν•œλ‹€. λ‹€μŒκ³Ό 같은 ν˜•νƒœλ‘œ 닀쀑상속을 ν•  수 μžˆλ‹€.
class DerivedClassName(Base1, Base2, Base3)

λ‹€μ€‘μƒμ†μ˜ 경우 super()λ₯Ό μ΄μš©ν•˜λ©΄ 첫번째 λΆ€λͺ¨λ§Œμ„ μ˜λ―Έν•΄, 각각의 λΆ€λͺ¨λ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€. λΆ€λͺ¨μ˜ 클래슀λͺ…을 μ΄μš©ν•΄ 직접 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€.

닀쀑상속을 받은 Parent듀이 같은 μ΄λ¦„μ˜ ν•¨μˆ˜λ₯Ό κ°–κ³  μžˆμ„ 경우, 첫번째 λΆ€λͺ¨μ˜ λ©”μ†Œλ“œλ§Œ λΆˆλŸ¬μ™€μ§€κΈ° λ•Œλ¬Έμ— λ”°λ‘œ μ •μ˜ν•΄μ€˜μ•Όν•œλ‹€.

class ParentOne(object):
        def __init__(self):
                self._one = 1

        def func(self):
                print('ParentOne.func')

class ParentTwo(object):
        def __init__(self):
                self.two = 2

        def func(self):
                print('ParentTwo.func')

class Child(ParentOne, ParentTwo):
        def __init__(self):
                ParentOne.__init__(self)
                ParentTwo.__init__(self)
                self._three = 3

        def oneFunc(self):
                ParentOne.func(self)

        def twoFunc(self):
                ParentTwo.func(self)

if __name__ == "__main__":
        child = Child()
        print(child.__dict__)
        child.oneFunc()
        child.twoFunc()
μ‹€ν–‰ κ²°κ³Ό >
{'_one': 1, 'two': 2, '_three': 3}
ParentOne.func
ParentTwo.func

λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©κ³Ό λ„€μž„ 맹글링

λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©(method overriding)은 λΆ€λͺ¨ ν΄λž˜μŠ€μ— μžˆλŠ” method와 같은 μ΄λ¦„μ˜ methodλ₯Ό μžμ‹ ν΄λž˜μŠ€μ—μ„œ μƒˆλ‘­κ²Œ κ΅¬ν˜„ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 것이닀.

ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μ •μ˜λœ μ΄λ¦„λ“€κ³Όμ˜ μΆ©λŒμ„ ν”Όν•˜κΈ° μœ„ν•΄μ„œ name mangling을 μ‚¬μš©ν•œλ‹€. μ •μ˜ν•œ ν•¨μˆ˜κ°€ ν΄λž˜μŠ€λ§ˆλ‹€ 이름이 κ²ΉμΉ˜μ§€ μ•Šκ²Œ μžλ™μœΌλ‘œ λ°”κΎΈμ–΄μ€€λ‹€.

μ•„λž˜ μ½”λ“œμ—μ„œ class A, Bμ—μ„œ μ •μ˜ν•œ __double_methodλŠ” _A__double_method, _B__double_method둜 λ³€κ²½λœλ‹€.

  • 이런 κ²½μš°κ°€ λ°œμƒν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€,,
class A:
        def _single_method(self):
                pass
        def __double_method(self):
                print("A' double method")
class B(A):
        def __double_method(self):
                print("B' double method")

print(dir(A))
print(dir(B))

b = B()
b._A__double_method() # class A μ—μ„œ μ •μ˜ν•œ ν•¨μˆ˜κ°€ λΆˆλŸ¬μ™€μ§„λ‹€.
b._B__double_method() # class B μ—μ„œ μ •μ˜ν•œ ν•¨μˆ˜κ°€ λΆˆλŸ¬μ™€μ§„λ‹€.
μ‹€ν–‰ κ²°κ³Ό >
['_A__double_method', '__doc__', '__module__', '_single_method']
['_A__double_method', '_B__double_method', '__doc__', '__module__', '_single_method']
A' double method
B' double method
728x90
728x90